“Extracting archive”卡住是磁盘I/O瓶颈而非网络慢,因解压时密集调用mkdir、file_put_contents、stat导致宿主机块设备队列(avgqu-sz)压爆,尤其在macOS APFS、WSL2或CI挂载/vendor场景下,毫秒级延迟被放大为秒级阻塞;需禁用vendor挂载、将cache-dir移至tmpfs、禁用ZIP缓存,并用--no-autoloader--no-scripts规避串行autoload生成。

为什么“Extracting archive”卡住不是网络慢,而是磁盘队列压爆了
根本原因不是带宽不够,是宿主机块设备队列(avgqu-sz)被 Composer 解压时密集的 mkdir、file_put_contents、stat 调用撑满。尤其在 macOS APFS、Windows WSL2 挂载卷、或 CI 中挂载 /vendor 的场景下,毫秒级系统调用延迟会被放大成秒级阻塞——iostat -x 1 里能看到 avgqu-sz > 10 且 await > 20ms,CPU 却很低。
禁用 vendor 挂载 + 切换 cache-dir 到 tmpfs 是最有效止损动作
CI/CD 中把 vendor/ 直接挂载进容器(如 -v $(pwd)/vendor:/app/vendor)是最大陷阱,宿主与容器间文件桥接开销会拖垮整个解压流水线。必须改用纯容器内生成 + 后置同步:
- 删掉所有
docker run -v .../vendor或compose volumes对vendor的映射 - 查当前缓存路径:
composer config -g cache-dir - 迁移到内存盘(Linux CI):
sudo mount -t tmpfs -o size=2G tmpfs /mnt/ramdisk,再执行composer config -g cache-dir /mnt/ramdisk/composer-cache - 禁用 ZIP 缓存减小写压力:
composer config --global cache-files-maxsize 0
并发下载快了,但 autoload 生成仍是单点瓶颈
composer install 的 Generating autoload files 和 post-install-cmd 完全串行,不受益于任何并发参数。一个 200+ 包的项目,这部分可能占总耗时 35% 以上:
- CI 构建时必须加:
--no-autoloader --no-scripts --no-plugins - 后续单独执行:
composer dump-autoload --optimize --classmap-authoritative - 别误以为
--no-dev能加速 autoload——它只删 dev 依赖,不影响 autoload 生成逻辑
Docker 多阶段构建中让 Composer 缓存真正生效的关键细节
很多人以为 COPY composer.lock 就能复用缓存,实际常因顺序错乱或隐式污染失效:
-
COPY composer.json composer.lock .必须是构建阶段第一条相关指令,前面不能有RUN chmod或COPY .env等干扰 - 启用 BuildKit 后,用
RUN --mount=type=cache,id=composer-cache,dest=/root/.composer/cache composer install --no-dev --optimize-autoloader - final 阶段绝对不要
RUN composer install——哪怕只装一个包,也会把/tmp/composer*、未清理的.git、bin/全打进镜像 - 检查最终镜像是否含
/root/.composer或/tmp/*:用docker history your-image看层体积,或docker run --rm -it your-image sh -c "ls -la /root/.composer"


















