composer默认串行建连导致高频tls握手开销,根本解决需绕过其网络层:通过预下载+共享缓存或私有镜像服务实现连接复用,而非依赖参数调优。

Composer默认是串行建立HTTP连接,没法复用
Composer 2.x 的 CurlDownloader 每次下载一个 dist 包都会新建一个 cURL handle,不复用 TCP 连接。这意味着每个包都要走完整的三次握手 + TLS 协商,尤其在高频构建(如 CI/CD 每分钟触发)时,这部分开销会线性增长。
这不是 bug,是设计使然:Composer 优先保证单次请求的隔离性与可中断性,没做连接池或 HTTP/1.1 keep-alive 复用逻辑。
- 即使你配置了
http.proxy或用了镜像源,只要不是同一 session 内连续请求,cURL 就不会复用连接 -
--prefer-dist能减少 git clone 带来的额外握手,但 zip 下载本身仍各自独立建连 - 启用
hirak/prestissimo插件曾支持并行 + 连接复用,但它已停止维护,且 Composer 2.2+ 内置并发能力后官方明确不兼容
真正能压降握手次数的只有两招
想绕过串行建连瓶颈,得从网络层和包分发策略入手,不是调参数能解决的:
- 用
COMPOSER_CACHE_DIR指向共享缓存目录(如 CI 中挂载的 volume),让不同构建 job 复用已下载的.zip文件,彻底跳过 HTTP 请求 - 在构建节点前置部署私有镜像服务(如 Nexus、Satis),把所有依赖预同步到本地;然后通过
composer config -g repo.packagist composer https://your-mirror.example.com切换源——此时域名固定、IP 稳定、TLS 会话可复用,三次握手实际只发生在首次请求 - 禁用 HTTPS 强制(仅限内网可信环境):
composer config -g secure-http false,省去 TLS 握手;配合 HTTP 反向代理(如 Nginx)做 SSL 终结,也能摊薄握手成本
别信“HTTP/2 自动优化”这种说法
Composer 底层用的是 PHP cURL 扩展,默认不启用 HTTP/2,除非你手动编译 cURL 时开启 nghttp2 支持,并确认 PHP 的 curl_version() 返回包含 "http2" => 1。即便满足条件,Composer 也没做 HTTP/2 多路复用适配——它仍按包粒度发起独立 curl_exec() 调用,无法利用 stream 复用。
实测中,哪怕后端支持 HTTP/2,Composer 下载 50 个包依然产生 50 次独立 connect,只是每次的首字节延迟略低而已。
CI 场景下最有效的握手抑制方案
在 GitHub Actions / GitLab CI 这类短生命周期环境中,靠调整 Composer 配置收效甚微。真正管用的是构建流程改造:
- 第一阶段:用
composer install --dry-run --no-dev提前解析依赖树,输出所有 dist URL 到文件 - 第二阶段:用
wget -i urls.txt --restrict-file-names=windows并行下载(支持 connection reuse 和 HTTP/2),存入统一缓存目录 - 第三阶段:设置
COMPOSER_CACHE_DIR指向该目录,再跑composer install --no-interaction --prefer-dist——此时 90% 以上包直接从缓存提取,零网络握手
这个链路把 Composer 从“网络客户端”降级为“本地解压器”,才是高吞吐场景下减少三次握手最硬核的做法。其他任何“调 timeout”“改 retries”的尝试,都只是在默认串行模型里修修补补。











