← 返回首页

把 OPCache Preloading 用对:不是提速神话,而是启动路径治理

2025-09-14 · PHP 性能 / 部署

很多团队一提到 preloading,就会把它理解成“再榨一点性能”。这当然没错,但太浅了。对于中大型 PHP 服务,preloading 的真正价值不只是快,而是把启动阶段真正稳定下来的那批类、接口和函数显式声明出来,让运行时对“哪些东西应该永远可用”有一个清晰边界。

不要 preload 变化频繁的领域层代码

如果你的 preloading 列表里混入了会经常调整的业务实现,部署时最容易遇到的问题不是性能,而是 worker 生命周期和代码版本切换不一致。尤其在 FPM 模式下,master 进程 preload 后 fork worker,这意味着你 preload 的更适合是:框架核心、容器基础设施、稳定的协议对象、异常体系、公共工具,而不是经常变更的业务策略。

把 preload 清单视作“可信启动面”

我更建议把 preload 文件当成“可信启动面”的定义:哪些类值得在 master 启动时就确定下来,哪些类应继续留给请求期惰性加载。这个判断会反过来逼你梳理依赖层次。如果一个看似基础的类总要连带一串数据库、环境变量、动态配置,那它就不配出现在 preload 列表里。

真正值得关注的是发布一致性

启用 preloading 后,要把 reload、graceful restart、容器滚动更新时间差这些部署细节一起考虑进去。很多线上“偶发 class not found / 签名不一致”问题,本质上不是 PHP 引擎的问题,而是某一批 worker 还活在旧世界里,另一批已经切到新版本。

// preload.php
$classes = [
    App\\Foundation\\Kernel::class,
    App\\Foundation\\Container::class,
    App\\Contracts\\DomainEvent::class,
    App\\Support\\Str::class,
];

foreach ($classes as $class) {
    class_exists($class);
}

配合 Composer classmap 才更稳

如果生产环境依然大量依赖 PSR-4 的运行时目录扫描,preloading 的收益会被打折。更稳的做法是配合优化 autoload、明确 classmap,并在构建阶段校验 preload 文件引用的类是否都能解析。这样你得到的不是一个“也许会快一点”的配置,而是一条从构建到运行都可验证的路径。

结论

preloading 不是玄学调优。它更像一次工程化表态:系统最核心、最稳定的那一层,我愿意在服务启动时就把它钉死。真正理解到这里,才知道该 preload 什么,以及坚决不该 preload 什么。