php请求合并无需强制使用协程或进程池,fpm下硬做反而更慢;真正可行的合并发生在客户端聚合、nginx subrequest或swoole协程环境,且仅适用于高频低差异的简单查询。

PHP 请求合并必须用协程或进程池吗?
不用。PHP 本身不支持原生协程(async/await),FPM 模式下每个请求独占一个 PHP 进程,天然无法在请求间共享内存做实时合并。强行用 apcu 或 redis 做“合并等待”会引入竞态、超时、死锁风险,实际项目中极少这么做。
真正可行的合并发生在「客户端发起前」或「服务端入口层」,不是在 PHP 脚本里写个循环就能搞定的。
- 前端可聚合多个资源请求为单个接口调用(比如把
get_user、get_profile、get_settings合成/batch) - Nginx 可用
subrequest+proxy_pass合并后端多个 PHP 接口(但注意:这是串行合并,非并发合并) - PHP-FPM 上跑 Swoole/Workerman 时,才能在 Worker 进程内用
Channel或Coroutine\WaitGroup实现真正的并发请求合并
用 Swoole 实现请求合并的关键点
只有在 Swoole 的协程环境下,才具备“多个请求进来,暂存参数,等凑够一批再统一查库”的条件。核心是控制合并窗口和避免阻塞其他协程。
- 合并必须设超时(如
10ms),否则小流量下永远等不满,大流量下又拖慢首屏 - 不能直接用全局数组存待合并请求——协程间变量不隔离,要用
Channel或Co\WaitGroup协作 -
mysql_query等同步 IO 会退出协程调度,必须换Swoole\Coroutine\MySQL或pdo_mysql配合co::sleep - 示例逻辑:
go(function() { $ch = new Channel(100); defer(fn() => $ch->close()); // 合并逻辑 });
为什么 FPM 下硬做合并反而更慢?
FPM 是阻塞模型,每个请求卡在 sleep 或 while 等待合并时,不仅浪费 worker,还可能触发 max_children 限流,导致新请求排队。数据库连接数、Redis 连接池也会被无效占用。
立即学习“PHP免费学习笔记(深入)”;
- 常见错误现象:
502 Bad Gateway频发、php-fpm.log中大量WARNING: [pool www] child 12345 exited on signal 15 (SIGTERM) - 即使加了
apcu_fetch+apcu_store做“合并标记”,也无法解决请求间时间差带来的漏合并或重复合并 - 真实压测中,FPM 合并方案 QPS 通常比直连低
15%~30%,延迟 P99 升高 2~5 倍
哪些场景其实不需要合并?
不是所有“多请求”都该合并。先确认瓶颈在哪:
- 如果数据库是瓶颈,优先优化索引、加缓存(
redis)、读写分离,而不是合并查询 - 如果网络 RTT 高(比如跨机房调用),合并有意义;但同机房 PHP 到 MySQL 通常
,合并收益几乎为零 - GraphQL 或 BFF 层已做了字段级聚合,PHP 后端再合并属于重复劳动
- 真正适合合并的是:高频、低差异、可批处理的简单查询,比如
SELECT * FROM user WHERE id IN (?,?,?)
合并逻辑越复杂,越容易掩盖真实问题。上线前务必对比合并前后 slowlog、mysql general_log 和 APM 的 span 分布。











