先查dmesg确认oom killer是否杀进程:sudo dmesg -t | grep -i "killed process",若命中则坐实内存耗尽;再结合systemctl status和journalctl查服务退出状态(如status=137)、定时任务/节点维护干扰,并监控worker内存、连接数及宿主机可用内存三指标。

查 dmesg 日志看是否发生 OOM Killer 杀进程
Hyperf 服务在凌晨自动宕机,第一怀疑对象就是 Linux 内核触发了 OOM Killer —— 它会在内存严重不足时,主动 kill 掉占用内存最多的进程(比如 Worker0)。这类退出不会留下 PHP 或 Hyperf 日志,但 dmesg 里一定有痕迹。
执行以下命令快速筛查:
sudo dmesg -T | grep -i "killed process" | tail -20
如果看到类似这样的输出:
[Sun May 17 02:14:32 2026] Out of memory: Kill process 12345 (php) score 892 or sacrifice child [Sun May 17 02:14:32 2026] Killed process 12345 (php) total-vm:2845672kB, anon-rss:1987652kB, file-rss:0kB, shmem-rss:0kB
那就基本坐实是内存爆了。注意看时间是否集中在凌晨、被杀进程名是否为 php、RSS 内存是否超限(比如 >1.5GB)。
- 别只查最近几条,用
-T带时间戳 +grep -A2 -B2查上下文,确认是否伴随大量page allocation failure或swap告警 - 如果没匹配到,再跑一次
sudo dmesg -T | grep -i "oom\|kill\|out of memory",避免关键词大小写或拼写变体漏掉 -
dmesg缓冲区可能被刷掉,若无记录,需提前配置kernel.dmesg_restrict=0并启用日志持久化(如rsyslog转存到文件)
结合 systemctl status 和 journalctl 看服务退出状态
Hyperf 通常以 systemd 服务方式部署,凌晨宕机大概率表现为 service exited with code=exited, status=0/KILL 或 status=137(即被信号 9 强制终止,常为 OOM 后果)。
运行:
sudo systemctl status hyperf.service -n 50
重点看最后一行的 Process: XXXX ExecStart=... (code=exited, status=137),再补查完整日志:
sudo journalctl -u hyperf.service --since "2026-05-17 01:00:00" --until "2026-05-17 03:00:00" -n 100
- 若日志末尾只有
Stopping Hyperf server.没有报错,基本可排除框架自身异常,转向系统层 - 留意是否有
timeout start或start-limit-hit,说明 systemd 因频繁崩溃启停而自我限制 - 检查
journalctl中是否夹杂PHP Fatal error或Swoole Error: Too many open files,这两者也可能导致凌晨批量崩溃
验证是否为定时任务或节点维护触发的被动驱逐
很多团队把备份、日志清理、数据库归档等任务设在凌晨 2–4 点,一旦资源争抢激烈,可能直接拖垮 Hyperf Worker;Kubernetes 或云平台的节点自动维护也爱挑这个时段。
排查动作:
- 查本机 cron:
sudo crontab -l和ls /etc/cron.*/* | xargs -I{} sudo grep -l "php\|hyperf\|bin/hyperf" {} 2>/dev/null - 查 systemd timer:
systemctl list-timers --all | grep -E "(daily|hourly|backup)" - 如果是容器环境,确认是否设置了
Pod Disruption Budget (PDB),并检查kubectl get events --sort-by=.lastTimestamp是否有Evicted记录 - 用
ps aux --sort=-%mem | head -5在凌晨前 10 分钟手动抓一次快照,对比宕机前后内存占用突变进程
监控报警必须覆盖的三个硬指标
光靠事后查日志太被动。真正能防住凌晨宕机的,是提前在监控系统(如 Prometheus + Grafana)里盯死这三项:
-
process_resident_memory_bytes{job="hyperf"} / 1024 / 1024:单个 Worker 内存 ≥1.2GB 就该告警(视你机器总内存按比例调整) -
swoole_get_local_socket_count()对应的指标(如hyperf_sockets_established):持续 >500 且不回落,说明连接泄漏已成型 -
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100:宿主机可用内存
这些指标不能只看平均值——要配 rate() 或 deriv() 看变化斜率,凌晨内存线性上涨比瞬时峰值更危险。另外,dmesg 和 journalctl 的原始日志本身也该接入 ELK 或 Loki,否则下次还得手动登机器翻。











