Ubuntu 20.04 + PHP 7.4 的站点,接口 p99 每三十秒左右出现一次两秒的尖峰,监控上看不出 CPU 和 IO 异常,session 目录里已经堆了两百多万个 sess_ 文件。

一开始怀疑是「请求分散在多个子进程,多个进程同时触发回收,磁盘压力叠加」,查了一圈,方向不对。

把日志和配置对完,能解释这个现象的基本就这几处。session 的垃圾回收按概率触发,一次要把整个目录扫一遍才能删掉过期文件。还有一种是目录里文件太多,单次遍历的 stat 开销被放大到秒级。

还有一种情况,session 存的是文件而不是集中存储,多台机器还各存各的。

第一件事是看 session 目录到底有多少文件

ls /var/lib/php/sessions | wc -l

然后把概率回收关掉,改由定时任务清理

sed -i 's/^session.gc_probability.*/session.gc_probability = 0/' /etc/php/7.4/fpm/php.ini && systemctl reload php7.4-fpm

再往下按修改时间清掉两周前的 session 文件

find /var/lib/php/sessions -type f -name 'sess_*' -mtime +14 -delete

剩下的就是配上定时任务每天凌晨跑一次

printf '15 3 * * * root find /var/lib/php/sessions -type f -name "sess_*" -mtime +14 -delete\n' > /etc/cron.d/php-session-clean

别只看报错消失,验证要多做一步。监控上 p99 的周期尖峰消失,session 目录文件数稳定在十万以内,接口耗时曲线不再每三十秒抖一次。

关掉概率回收后如果定时任务没配上,session 会无上限增长,先把清理任务落实再关。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189