max_request不是内存泄漏的解药,而是兜底止损机制;它通过定期重启worker进程缓解内存上涨,但无法修复泄漏根源,设错反而掩盖问题、增加开销、降低qps。

max_request 不是内存泄漏的解药,而是兜底止损机制——设错反而掩盖问题、拖慢服务。
为什么 max_request 会被误当成“防泄漏开关”
很多人看到 worker 进程内存持续上涨,第一反应就是加 max_request。但它本质不是修复泄漏,而是定期“杀进程重来”。PHP-FPM 每次请求后自动销毁上下文,而 Swoole 的 worker 是常驻的,只要代码里有 static $cache = []、未 unset 的 Redis 客户端、或闭包持有了大对象,内存就会一帧一帧涨上去。
设 max_request=0(默认)等于放任累积;设 max_request=100 则每处理 100 个请求就重建一次进程——上下文重建开销明显,QPS 下降,还让你误以为“重启够勤就没问题”,结果真实泄漏点一直埋着。
- 常见错误现象:
Fatal error: Allowed memory size of ... exhausted频繁出现,ps aux观察到 worker 进程 RSS 持续攀升 - 典型场景:Laravel-Swoole 或 think-swoole 中未清理 Eloquent 查询缓存、静态配置类、全局日志实例
- 关键事实:
max_request对 Base 模式无效,纯异步 Server(如 UDP)也不该设它
Laravel-Swoole 和 Think-Swoole 中 max_request 被写死为 0 的原因
你改了 config/swoole.php 里的 max_request 却没生效?因为 Laravel-Swoole 和 think-swoole 在底层 InteractsWithServer.php 中直接硬编码了 'max_request' => 0。这不是疏忽,是权衡:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- RPC 文件分片上传时,worker 若在第 3 次请求后退出,会导致文件传一半就断
- 框架希望开发者先解决根本泄漏,而非依赖进程重启“擦屁股”
- think-swoole 明确建议用事件钩子覆盖:在
swoole.init事件里调用$manager->getServer()->set(['max_request' => 1000])
注意:这个值不能拍脑袋定。上线前得用 memory_get_peak_usage() 打点采样,看单请求平均内存增长量。比如涨 20KB/请求,1000 次就是 +20MB,若机器内存紧张,就得调低到 500 甚至 300。
设多少才合理:别抄数字,要看压测和监控
网上说“设 5000 最佳”“1000 就够”,全是误导。真实值取决于你的代码质量、依赖库行为、并发模型:
- API 服务(轻逻辑、无长连接):1000~3000 较稳妥,兼顾重启开销与内存安全
- WebSocket 或长轮询服务:慎用
max_request,优先检查Swoole\Table容量限制和连接生命周期管理 - 含大量同步阻塞调用(如 file_get_contents、curl_exec)的服务:值要更小(500 左右),因为阻塞期间资源更易堆积
- 必须配合
server->stats()定期查worker_request_count和memory_usage,发现某 worker 提前崩了,说明泄漏严重,该修代码而不是调参数
另外,max_request_gently(平滑重启)在生产环境值得开启,避免瞬间所有 worker 同时退出导致请求抖动。
最常被忽略的一点:哪怕设置了 max_request,如果每次重启后内存基线比上一次还高,说明泄漏源在 manager 进程或全局初始化阶段——这时候再调 worker 参数已经没用了。










