内存泄漏、数据库死锁、慢请求是高并发php故障三大主因:内存泄漏需监控vmrss和对象分布,重点排查静态缓存、闭包持有、循环引用;死锁须统一多表更新顺序并捕获重试;慢请求多源于i/o阻塞,应设超时、用连接池、转异步日志。

线上 PHP 服务突发内存暴涨、数据库报死锁、接口响应飙升到数秒——这类故障往往不是单点问题,而是多个隐患在高并发下集中暴露。复盘关键不在归责,而在建立可落地的识别路径和防御动作。
内存泄漏:常驻进程里最隐蔽的“慢性失血”
PHP-FPM 场景下泄漏不明显,但 Swoole、RoadRunner 或 CLI 守护进程中,内存会随请求次数线性增长,几天后 OOM 崩溃。
- 重点盯三类代码:静态数组无清理(如 static $cache = []; 不设上限也不淘汰)、闭包 use ($bigObject) 持有大对象、对象间双向引用未断开(如 A→B 和 B→A)
- 上线前必做两件事:用 memory_get_usage() 在循环体前后打点;对长生命周期脚本,每处理 N 条数据后调用 gc_collect_cycles()
- 生产环境快速验证:查 /proc/{pid}/status 中的 VmRSS,比 PHP 内部统计更真实;配合 php-meminfo --pid={pid} 看对象分布,若 stdClass 或 Closure 实例数持续上涨,基本锁定泄漏源
数据库死锁:并发写入时的“资源抢夺战”
死锁本身不可怕,可怕的是业务没重试逻辑,导致用户看到 500 或数据不一致。InnoDB 日志里那句 “Deadlock found…” 就是明确信号。
- 高频诱因就两个:事务内更新多张表时顺序不统一(A→B vs B→A),或 WHERE 条件没走索引触发间隙锁冲突(如 WHERE status = 'pending' 无索引,锁住整段间隙)
- 修复不靠猜:开启 MySQL innodb_print_all_deadlocks = ON,日志里会完整记录两个事务的 SQL、锁类型、等待链;对照业务代码,强制所有涉及多表更新的事务按固定顺序操作(如始终先扣库存再写订单)
- 应用层兜底:捕获 PDOException 中含 “Deadlock” 字样的异常,自动重试 1–2 次(带随机退避),避免前端直接失败
慢请求:表面是卡顿,根子常在 I/O 或锁竞争
响应时间 >2s 的请求,80% 以上不是 CPU 瓶颈,而是被阻塞住——等数据库锁、等远程 API、等文件读写、等 Redis 连接池耗尽。
- 先分层排查:用 Blackfire 或 Xdebug trace 看火焰图,确认耗时集中在哪一层;若大量时间在 curl_exec、PDOStatement::execute 或 file_get_contents,说明是外部依赖拖慢
- 常见硬伤:同步调用第三方 HTTP 接口没设超时;Redis 使用 get 却没配连接池,高峰时排队;日志写本地磁盘用 error_log() 频繁刷盘
- 立即见效动作:所有 curl 加 CURLOPT_TIMEOUT_MS(建议 ≤800ms);Redis 改用连接池(Predis 或 phpredis 的 persistent connection);日志转异步(如通过 syslog 或 Kafka)
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











