这大概率是内存泄漏引发OOM Killer强制杀进程,需通过dmesg确认Killed process php记录、systemctl检查code=killed状态,再结合定时任务、Task Worker积压、协程sleep滥用、连接池未释放及全局变量累积等五方面定位泄漏源。

线上Hyperf3.1服务凌晨频繁重启Worker进程,日志无明显PHP错误,但dmesg显示“Killed process php”,内存监控曲线持续爬升——这大概率是内存泄漏引发OOM Killer强制杀进程,必须快速定位泄漏源并阻止服务反复崩溃。
确认是否为OOM Killer触发的Worker退出
执行sudo dmesg -T | grep -i "killed process",重点看时间是否集中在凌晨、被杀进程名是否含php、RSS内存是否超1.5GB。若匹配到类似Killed process 12345 (php) total-vm:2845672kB, anon-rss:1987652kB的输出,就坐实了内存耗尽。
注意:【dmesg缓冲区可能已被刷掉,若无记录,需立即配置kernel.dmesg_restrict=0并启用rsyslog持久化】,否则下次再出问题将失去关键证据。
补查systemd状态:sudo systemctl status hyperf.service -n 50,若看到status=137或code=killed,就是信号9终止,与OOM完全吻合。
定位泄漏发生在哪个环节
第一步:检查定时任务是否为元凶。Hyperf的crontab-dispatcher进程若配置不当(如秒级高频执行+未释放资源),会导致Worker内存缓慢但持续增长。把本地定时任务临时改为秒级,worker_num设为1,观察ps aux --sort=-%mem | head -5中PID对应进程的RSS变化——15分钟内上涨超200MB,基本锁定定时任务。
第二步:验证Task Worker是否积压。执行php bin/hyperf.php server:monitor,紧盯task_wait_queue_len和tasking_num。若tasking_num长期高于task_worker_num,说明任务投递快于处理速度,参数task_worker_num过小或任务内存在阻塞调用(如sleep()、未设超时的curl_exec())。
第三步:抓取可疑Worker的内存快照。当某个Worker RSS飙升时,立刻执行:sudo gcore -o /tmp/core-worker-$(pgrep -f "worker.*[0-9]" | head -1) $(pgrep -f "worker.*[0-9]" | head -1),生成core dump供后续gdb分析。
排查代码层常见泄漏点
方法一:检查协程内是否滥用sleep()。Swoole\Coroutine\System::sleep()在调度器离线时会触发死锁,表现为CPU归零、strace -p [pid]卡在futex调用。正确做法是改用Co::sleep(0.01)插入可调度点。
方法二:审查DB/Redis连接池使用。未关闭的PDOStatement、未释放的redis pipeline、循环中new PDO但未unset,都会累积内存。特别注意定时任务里是否在每次执行时都新建连接池实例而非复用。
方法三:扫描全局变量和静态属性。在App\Kernel\Process\WorkerStartProcess中注册register_shutdown_function,打印memory_get_usage(true)与gc_collect_cycles()结果——若每次Worker启动后内存基线持续抬高,说明有静态变量在不断追加数据。
验证Task协程开关是否真正生效
在Task类的handle()方法开头加入Co::sleep(0.01),然后运行strace -p $(pgrep -f 'task_worker') -e trace=epoll_wait。如果看到epoll_wait被频繁调用且返回0(表示协程挂起等待),说明task_enable_coroutine => true已生效;若一直忙等或报错coroutine is not available,说明Swoole扩展版本不兼容或配置未加载。
注意:【传递不可序列化的对象(如Closure、mysqli实例)会导致任务静默丢弃,日志里只有serialize(): __sleep should return an array】,务必检查handle()方法入参类型。
紧急止血与长期监控
立即生效的配置调整:在config/autoload/server.php中设置max_request => 100000防止单Worker内存无限累积,同时开启reload_async => true确保热更新不中断服务。
部署级监控加码:在Prometheus中新增指标hyperf_worker_rss_bytes(通过/proc/[pid]/statm提取),设置告警阈值为800MB;对task_wait_queue_len设置>50持续5分钟即触发人工介入。
执行php bin/hyperf.php server:restart应用新配置,观察接下来3个凌晨周期内Worker是否仍被OOM Killer终结。


















