You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境php-fpm通过CurlMultiHandler拉取S3对象卡住如何排查解决

根因

该问题是Guzzle 6.x与libcurl 7.58.0组合的已知死循环bug,触发逻辑如下:

  • libcurl 7.58.0存在curl_multi_select函数错误:当连接被对端(此处为AWS S3服务)主动关闭、本地处于CLOSE_WAIT状态时,curl_multi_select会错误返回0(超时状态),哪怕实际上已有就绪的请求事件需要处理。
  • Guzzle 6.x的CurlMultiHandler::tick逻辑未覆盖该边界场景:代码判断curl_multi_select返回0时会直接跳过后续的curl_multi_exec调用,导致已完成的请求永远不会被标记为结束,待处理请求队列长期非空,tick函数被无限循环调用,进程完全卡住。
  • 周日批量处理报表时,短时间内并发拉取大量S3对象,容易触发S3侧的连接主动断开(限流、连接空闲超时等原因),产生大量CLOSE_WAIT连接,刚好触发该bug。
可行解决方案

永久修复方案

  • 优先升级Guzzle版本到7.3.0及以上:该版本官方已修复CurlMultiHandler的边界逻辑,无论curl_multi_select返回值是什么,都会执行一次curl_multi_exec处理已就绪的请求事件,从逻辑层避免死循环。
  • 若无法升级Guzzle大版本,可手动给Guzzle 6.x的CurlMultiHandler::tick函数打补丁,移除“curl_multi_select返回0则跳过执行curl_multi_exec”的判断逻辑,每次调用tick都执行一次curl_multi_exec处理积压事件。
  • 可选底层修复:将libcurl升级到7.68.0及以上版本,该版本修复了curl_multi_select的返回值错误问题,从底层消除触发条件。

临时缓解方案

  • 调整php-fpm配置:设置pm.max_requests = 200(可根据实际情况调整为100~500),让php-fpm子进程处理完指定数量请求后自动重启,避免卡住的进程长期占用资源。
  • 给S3请求添加显式超时配置,初始化Guzzle客户端或S3Client时添加以下参数:
$client = new GuzzleHttp\Client([
    'connect_timeout' => 10,
    'timeout' => 30,
]);
  • 降低批量拉取S3对象的并发数,减少短时间内大量连接断开产生CLOSE_WAIT的概率。

内容的提问来源于stack exchange,提问作者kaktusas2598

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 20:57:00