硬盘灯狂闪主因是PHP触发的高频磁盘IO,如session文件写入、日志刷盘、临时文件操作;典型表现为%wa高、iotop显示php-fpm大量WRITE;优先用iotop和pidstat定位具体进程与IO量,再优化session.save_path至tmpfs或改用redis、调整日志和临时目录路径。

PHP脚本运行时硬盘灯狂闪,大概率是IO卡住了
不是PHP本身在“拼命干活”,而是它触发了大量磁盘读写——比如日志刷盘、session写文件、临时文件生成、或数据库查询结果缓存到磁盘。灯狂闪只是表象,背后通常是fwrite、file_put_contents、session_start这类操作在反复刷磁盘,尤其当磁盘慢(如机械盘、高负载云盘)或文件系统有瓶颈时更明显。
- 常见错误现象:
top里%wa(iowait)持续高于20%,iotop -o能看到php-fpm进程在高频WRITE - 典型使用场景:批量导出Excel(用
PhpSpreadsheet)、上传大文件后做move_uploaded_file、开启session.save_handler = files且并发高 - 别急着怀疑代码逻辑错误——先确认是不是
/tmp分区满了,或session.save_path指向了IO性能差的挂载点
用iotop和pidstat定位具体PHP进程和IO行为
光看灯没用,得抓到哪个PHP请求在刷盘。优先用实时工具,避免事后分析失真:
- 运行
sudo iotop -o -p $(pgrep php-fpm),观察IO>列,找出WRITE量大的php-fpmworker PID - 再用
sudo pidstat -d -p <pid> 1</pid>看该进程每秒读写字节数,确认是否稳定在几MB以上 - 如果
iotop看不到PHP进程,检查是否用了opcache.enable_cli=1跑脚本——CLI模式下php进程不会被php-fpm管理,需改用pgrep php - 注意
iotop默认只显示“有IO活动”的进程,静默期长的请求可能漏掉,建议搭配strace -p <pid> -e trace=write,open,fsync</pid>抓系统调用
session.save_handler = files是高频IO元凶之一
PHP默认把session存在文件里,每次session_start()都会flock+fopen+fwrite,高并发下变成串行磁盘争抢。这不是bug,是设计使然。
- 验证方法:临时改
session.save_handler = redis(配合redis.so),观察硬盘灯是否缓解;若明显改善,基本锁定问题 - 不换方案的话,至少把
session.save_path挪到tmpfs(内存文件系统):比如mount -t tmpfs -o size=64M tmpfs /var/lib/php/sessions - 注意权限:
php-fpm用户(如www-data)必须对save_path有读写权,否则会静默降级到/tmp,反而更慢 - 别忽略
session.gc_maxlifetime设得过大——过期session文件堆积,gc扫描时一次扫几千个文件,IO毛刺直接拉满
临时文件和日志配置不当也会拖垮IO
PHP自身不直接写盘,但依赖的扩展和运行时环境会。关键不是“有没有写”,而是“写得有多碎、多频繁、写到哪”。
立即学习“PHP免费学习笔记(深入)”;
-
upload_tmp_dir如果指向机械盘,且上传100个1MB文件,就会触发100次copy到临时目录——换成tmpfs路径可立竿见影 -
error_log = /var/log/php/error.log如果开了log_errors = On又没配error_log为syslog,每个警告都同步刷盘;建议改用error_log = syslog或加error_log = /dev/null(开发环境慎用) - 第三方库如
monolog默认StreamHandler是同步写,RotatingFileHandler切日志时还会rename和touch一堆文件——检查是否启用了BufferHandler包装 -
opcache.file_cache如果开启,会把编译后的opcode写到磁盘,适合容器重启频繁场景,但会增加启动期IO;若磁盘弱,宁可关掉,靠内存缓存扛住
硬盘灯狂闪本身不危险,但背后暴露的是IO路径上某个环节没做缓冲、没选对介质、或没避开串行锁。最常被忽略的,是把所有“临时”都当成真临时——/tmp、session.save_path、upload_tmp_dir全挤在同一个慢盘上,还开着sync日志。拆开看,每个点都好调,合起来就成风暴眼。



















