composer 本身不支持零停机更新依赖,因其直接修改 vendor 目录,导致运行中进程加载冲突;零停机需靠部署层隔离,如构建阶段生成带版本的不可变 artifact,再原子切换软链,并同步重载 fpm 与清理 opcache。

Composer 本身不支持零停机更新依赖,它只是 PHP 的包管理工具,所有 composer install 或 composer update 操作都直接修改本地 vendor 目录——这意味着任何正在运行的 PHP 进程(如 FPM worker)若已加载旧版本类,就无法“热切换”到新版本。真要实现零停机,得靠部署层隔离,不是靠 Composer 本身。
为什么 composer install 不能直接用于生产环境热更新
它会原地覆盖 vendor/,导致以下问题:
- 正在执行的请求可能因类文件被删/重写而触发
Class not found或require(): failed to open stream - FPM worker 缓存了 opcache 中的旧字节码,即使文件更新,也不会自动 reload(除非配置了
opcache.validate_timestamps=1且间隔足够短,但仍有窗口期) - 没有原子性:
vendor/是目录树,不可能像单个文件那样用mv原子替换
蓝绿部署中 Composer 应该在哪儿跑
必须在构建阶段完成,而非线上服务器运行时。正确路径是:
- CI 流水线拉取代码后,执行
composer install --no-dev --optimize-autoloader,生成完整vendor/ - 将代码 +
vendor/打包为不可变 artifact(如 tar.gz 或 Docker 镜像),带上明确版本标签(如v20240520-123abc) - 部署系统解压 artifact 到新路径(如
/var/www/myapp/releases/v20240520-123abc),再原子切换软链:ln -sf v20240520-123abc current -
current被切换瞬间,FPM worker 下次请求才会加载新路径下的代码和vendor/
注意:不要在部署脚本里调用 composer install —— 网络波动、源站不可用或锁文件不一致都会导致线上失败。
如何避免 autoload_classmap.php 和 opcache 冲突
Composer 生成的优化类映射(vendor/composer/autoload_classmap.php)是静态文件,但 opcache 默认缓存它。如果部署时只替换了代码却没清 opcache,PHP 可能仍按旧映射去加载已被删除的类文件。
- 上线后必须执行
opcache_reset()(通过 CLI 或 HTTP 触发),或使用sudo systemctl reload php*-fpm强制 worker 重启 - 更稳妥的做法:在构建时禁用 classmap(去掉
--optimize-autoloader),改用 PSR-4 自动加载,虽然性能略低,但对文件变更更宽容 - 检查
opcache.revalidate_freq,设为0可让每次请求都校验文件时间戳(仅限开发/预发,生产慎用)
真正难的不是怎么跑 composer install,而是确保所有运行时依赖(包括 autoloader、opcache、FPM worker 生命周期)在同一时刻看到同一份代码快照。漏掉任意一环,比如忘记 reload FPM 或没清 opcache,就会出现“一半请求成功、一半报错”的现象。










