ThinkPHP6 万级并发卡顿主因是同步阻塞模型与默认配置叠加导致资源争抢,需从PHP-FPM调优、接口逻辑剥离阻塞、数据库连接优化、缓存驱动升级四方面系统治理。

ThinkPHP6 在面对一万并发 POST 请求时出现卡顿,核心问题不在框架本身,而在于同步阻塞模型与默认配置叠加后的资源争抢。它不是“扛不住”,而是没按高并发场景去配置和设计。关键要拆解瓶颈点:PHP-FPM 进程耗尽、数据库连接打满、文件/Session 锁死、缓存驱动误用、日志和调试拖累。下面分四块说清楚怎么做。
PHP-FPM 和运行环境必须调优
默认的 FPM 配置(如 pm.max_children=5)在万级并发下连排队都排不上,直接 503。这不是 ThinkPHP 的锅,但它是第一道闸门。
- 把 pm = dynamic,设 pm.max_children ≥ 128(根据内存算:单进程约 20–40MB,16GB 内存建议 128–256)
- pm.start_servers 和 pm.min_spare_servers 设为 32–64,避免突发流量冷启动延迟
- 启用 pm.max_requests = 300–500,防止长期运行导致内存缓慢泄漏
- Nginx 端配 worker_connections 20480,并开启 keepalive_timeout 15,减少 TCP 握手开销
- PHP 层强制启用 OPcache,且必须做字节码预热:在
public/index.php开头加opcache_compile_file(BASE_PATH . '/vendor/topthink/framework/src/think/App.php');等核心文件,否则 OPcache 命中率极低
POST 接口逻辑必须剥离阻塞操作
万级 POST 请求进来,如果每个都同步写日志、发邮件、查三次库、再写文件缓存,系统立刻雪崩。ThinkPHP6 不支持原生协程,所以“异步”只能靠剥离。
- 关闭所有调试开关:.env 中 APP_DEBUG=false,同时禁用 trace、关闭 SQL 日志(
'log_sql' => false) - 禁止在控制器里用
file_get_contents()、sleep()、curl_exec()等同步 I/O;外部 HTTP 调用改用队列 + Guzzle 异步客户端或 Swoole HTTP Client - Session 文件驱动在高并发下会锁文件,要么禁用 session(无状态接口),要么切到 Redis 驱动:
'type' => 'redis'并确保session_start()不被中间件或模板意外触发 - 所有非实时必需操作(如通知、统计、生成缩略图)全部推入 Redis 队列:
Queue::push('App\Job\SendNotify', ['order_id' => $id])
数据库连接和查询不能“随用随连”
TP6 没有连接池,但可以极大降低连接争抢。10000 并发若每请求建一个 PDO 连接,MySQL 的 max_connections 很快爆掉(默认通常 151),报错 SQLSTATE[HY000] [1040]。
立即学习“PHP免费学习笔记(深入)”;
- 数据库配置中启用持久连接:
'params' => [\PDO::ATTR_PERSISTENT => true],并同步调大 MySQL 的wait_timeout(建议 300 秒) - 禁用 TP6 默认读写分离(
'deploy' => 0),除非你真有稳定主从架构;否则额外路由判断反而增加延迟 - 高频小查询(如获取配置、状态码)改用 APCu 缓存:
apcu_fetch('sys_config'),完全绕过 DB - 事务务必短平快:
Db::transaction()内只做必要写操作,别包查询或 sleep;异常时确保 rollback,否则连接一直被占 - 检查是否有 N+1 查询,用
withJoin()或手动join()合并,避免循环查库
缓存策略必须换掉默认文件驱动
TP6 默认 Cache::get() 走的是文件缓存,万并发下所有请求抢同一个 cache 文件锁,结果变成串行处理——比不缓存还慢。
- 立即切换缓存驱动为 Redis:
'default' => 'redis',并确认 Redis 实例内存充足、网络低延迟 - 所有缓存 key 必须带业务前缀和版本号,比如
user:profile:v2:123,避免误删或冲突 - 设置合理过期时间,防雪崩:热点数据用随机偏移(
3600 + rand(0,300)),冷数据可设永不过期但配合主动更新 - 对超高频只读数据(如首页 Banner),考虑加一层本地缓存(APCu)做二级缓存,减少 Redis 网络往返
- 禁止缓存大对象(如整张用户表结果),只缓存 ID 列表或聚合值;大内容改用 Redis Hash 或单独 key 存储



















