一万并发下PHP-FPM进程溢出本质是配置超限与单进程内存失控,需从FPM静态模式、单请求内存≤80MB、I/O异步化、多级缓存四层收敛,并建议迁移到think-swoole。

一万并发下 PHP-FPM 进程溢出,本质是 进程数配置超限 + 单进程内存失控,不是 ThinkPHP 本身写错了,而是默认模型根本没设计承载这种量级。直接调高 pm.max_children 到 1000+ 只会触发 OOM Killer 杀进程,必须从模型、内存、IO、缓存四层同步收敛。
一、FPM 进程模型必须切 static 模式
Dynamic 模式在万级并发下会因频繁 fork/spawn 导致 CPU 抖动、进程数误判、空闲回收混乱;ondemand 更不可用(启动慢、易超时)。static 模式才能让进程数完全可控:
- 设
pm = static,只保留pm.max_children一个关键参数 - 按实测单进程内存占用倒推上限:例如压测发现 TP6 + Redis + OPcache 下单 worker 占 65MB,则 16GB 可用内存服务器最多配
pm.max_children = 180(16×1024÷65 ≈ 253,留 30% 余量) - 禁用
pm.process_idle_timeout(dynamic 模式才生效,static 下无需设置)
二、单请求内存必须压到 80MB 以内
TP6 在万并发下最常崩在单请求内存超标,不是配置低,而是框架行为没收敛:
- 强制关闭调试:
APP_DEBUG = false,同时删掉所有Log::debug()、dump()、未清理的 trace 输出 - 路由和配置必须预编译:
php think optimize:route+php think optimize:config,避免每次请求重复解析 - 大查询不用
select()全加载,改用chunk(200, function($items){ ... })或原生 SQL +Db::query()配合unset($result) - 模板中禁止
{:dump($data)}、{:print_r($data)}类调试输出,它们会把整个数据结构留在内存直到请求结束
三、阻塞型 I/O 必须剥离或异步化
TP6 是同步阻塞框架,file_get_contents、curl_exec、session_start()(文件驱动)在万并发下会排队锁死:
立即学习“PHP免费学习笔记(深入)”;
- 移除所有同步 HTTP 调用,改用 Swoole Coroutine Client(需配合
think-swoole)或投递到消息队列 - 禁用 Session 文件驱动:
session.type = redis或直接关掉(如接口无状态) - 日志写入改异步:用
monolog配合RedisHandler或SocketHandler,别写本地文件 - 数据库连接必须启用连接池(仅限 Swoole 环境),FPM 下只能靠
pool_size+ 持久连接 + 查询复用
四、缓存策略必须分层且避坑
FPM 下缓存若全走 file 或全压 Redis,都会成为瓶颈:
- 禁用
cache.type = file:高并发下千万级小文件 flock 争用直接拖垮磁盘 IO - 配置多级缓存:
Cache::store('redis')存热点,Cache::store('apcu')存短时配置(需启用 APCu 扩展) - 路由/语言包/模板编译结果全部进 OPcache:确认
opcache.validate_timestamps = 0、opcache.revalidate_freq = 0、opcache.max_accelerated_files = 65536 - 避免缓存大对象:如把整个用户模型实例塞进 Redis,应只存 ID,查时再组装
真要稳扛一万并发,FPM 只是过渡方案。建议尽快迁移到 think-swoole 或 think-worker,用协程替代进程,单机 QPS 可从几百跃升至上万,且内存占用下降 60% 以上。



















