根本原因是多机房各自执行composer update且未统一提交composer.lock;只要所有机房仅运行composer install并确保lock文件已提交,vendor必然一致。

composer install 为什么在不同机房装出不一致的 vendor?
根本不是网络或镜像源问题,而是多机房各自执行了 composer update,又没统一提交新的 composer.lock。只要所有机房都只跑 composer install(且 composer.lock 已提交到 Git),结果就必然一致——Composer 不做决策,它只还原快照。
常见错误现象:
-
composer install --dry-run输出含Resolving dependencies:说明composer.json和composer.lock已脱钩,必须人工干预 - 同一 commit 在 A 机房装出
monolog/monolog v3.5.2,B 机房是v3.6.0:大概率某台机器偷偷跑了update或lock文件未提交
私有 Packagist 平台元数据同步,为什么不能靠“自动轮询”?
私有平台若模仿公共镜像做“按需拉取 + 缓存”,会因各机房首次请求时间差、包版本发布节奏不一,导致元数据“漂移”。比如 A 机房先查 laravel/framework v10.42.0,触发拉取并缓存;B 机房稍后查同版本,但此时上游已删该 tag 或重推,结果拿到的是旧快照或 404。
真正可控的做法是主动同步:
- 用
packagist/packagist官方同步工具(如bin/console packagist:sync:all)定时全量拉取,而非依赖 HTTP 请求触发 - 同步脚本必须带校验:比对
packages.json的lastModified时间戳,差值超 5 分钟即告警 - 禁止任何机房直接写入私有平台;所有包发布走统一 CI 流水线,打标
synced_at字段并写入审计日志
如何让多机房 Composer 客户端强制走指定私有源?
关键不是改 repositories 数组,而是覆盖 Composer 3.x+ 硬编码的元数据路由。必须用 composer config --global repo.packagist composer https://pkg.example.com/,且 URL 末尾的 / 缺一不可。
容易踩的坑:
- 写成
repos.packagist(多一个s)或漏掉composer这个 type 值,配置完全无效 - 项目级
composer.json里一旦定义了repositories,全局配置立即失效——这不是 bug,是设计逻辑 - 配完不执行
composer clear-cache,旧缓存里的repo.packagist.org元数据仍主导后续请求
验证是否生效:运行 composer config --list | grep repositories.packagist.url,输出必须是你配的私有域名;再跑 composer install -vvv,日志里不能出现 packagist.org 或 repo.packagist.org。
双机房元数据不一致时,怎么快速定位是平台问题还是客户端配置?
别信 -vvv 日志里那行 Resolving dependencies,真正卡点在后续几百次 provider 请求。直接测底层连通性:
- 在 A 机房执行:
curl -I https://pkg-a.example.com/p2/laravel/framework/10.42.0.json - 在 B 机房执行:
curl -I https://pkg-b.example.com/p2/laravel/framework/10.42.0.json - 对比响应码和
Last-Modified头;若一个 200 一个 404,说明 B 机房平台未同步完成
更隐蔽的问题是时间戳一致但内容不同:用 curl -s https://pkg-a.example.com/packages.json | jq '.providers' | wc -l 和同命令比对 B 机房,数量差 > 1 就说明索引文件未完整同步。
复杂点在于:私有平台的同步延迟不是线性的,它取决于包名哈希分片策略、数据库主从复制 lag、以及 CDN 缓存刷新周期。一次 curl 成功,不代表所有 p2/xxx/yyy.json 都就绪——必须按实际业务用到的包列表逐个验证。











