php并发处理关键在配置与资源管理:合理设置php-fpm的pm.max_children(依内存实测)、禁用ondemand模式、避免flock阻塞、慎用pdo持久连接、改用redis或数据库事务保障一致性,协程方案优先选swoole而非curl_multi。

PHP 本身不处理并发,它靠外部模型“扛住”并发——关键不是写多少 async,而是别让请求在 PHP 层变成串行或崩溃。
PHP-FPM 的 pm.max_children 设多少才不崩
线上最常见 502/504 就是它设错了:设太大,内存爆掉被 OOM killer 杀进程;设太小,请求排队超时。这不是理论值,得实测。
- 先用
ps aux --sort=-%mem | grep 'php-fpm' | head -5看几个活跃子进程实际占多少内存(通常 25–45MB,含扩展和业务代码) - 再算:可用内存 × 0.8 ÷ 单进程平均内存 ≈ 合理
pm.max_children - 禁用
pm = ondemand——冷启动 fork 延迟高,突发流量直接超时 - 静态模式(
pm = static)比动态更稳,pm.start_servers和pm.max_children设成一样,避免扩容抖动
别用 flock() 做计数器或日志锁
flock() 是阻塞式文件锁,没有超时、不可中断,1000 QPS 下可能只剩 30 QPS 真实写入速度——它把并发强行压成单线程。
- 高频写场景(如 PV 统计、订单号生成)一律换
Redis::incr()或Redis::lPush() - 必须落盘的日志,去掉
LOCK_EX,用file_put_contents($f, $d, FILE_APPEND)无锁追加,后续靠 Logrotate 或定时脚本归档 - 若真要强一致性(如库存扣减),改用数据库
SELECT ... FOR UPDATE+ 事务,别碰文件
PDO 持久连接(PDO::ATTR_PERSISTENT)为什么反而拖垮 MySQL
持久连接不是“共享连接”,而是每个 PHP-FPM 子进程独占一条长连接。100 个子进程 = 100 条空闲连接,很快打满 MySQL 的 max_connections,还容易积压 stale connection。
- 查 MySQL 当前连接:
SHOW STATUS LIKE 'Threads_connected';,如果长期接近max_connections,大概率是 PDO 持久连滥用 - 要么关掉
PDO::ATTR_PERSISTENT,改用短连 + 连接池(如 ProxySQL) - 要么保留持久连接,但同步调低 MySQL 的
wait_timeout(建议 60s)和 PHP-FPM 的pm.max_requests(建议 300–500),强制回收 - 协程方案(如 Swoole)下用
Swoole\Coroutine\MySQL才真正复用连接,不是 PDO 那套
用 curl_multi_init() 发并发 HTTP 请求的坑
它只是把多个 cURL 句柄塞进一个批处理上下文,底层仍是阻塞 socket,没解决 I/O 等待问题——只是“看起来并发”,不是真正的异步。
- 超时控制得手动设:
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 3000),否则一个慢接口拖垮整批 - 别在 Web 请求里直接跑
curl_multi_exec(),CPU 密集且易超时;适合 CLI 守护进程或队列消费者 - 真正要高吞吐调第三方 API,优先选 Swoole 的
Swoole\Coroutine\Http\Client,协程非阻塞,1 个进程轻松撑 5000+ 并发连接 - 如果必须用 cURL 多路,记得循环调
curl_multi_select()等待就绪,而不是忙等
真正卡脖子的地方往往不在代码逻辑,而在配置误配、锁滥用、连接泄漏这些“看不见”的地方。上线前盯死 php-fpm.log 里的 slow log、MySQL 的 processlist 和 Redis 的 INFO clients,比反复改业务代码管用得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











