opcache 调优:384M / 80000 文件 / revalidate_freq=3,每个值是怎么定的-第三维度MokIII

opcache 是"性价比最高"的一档优化

WordPress 每次请求都要把几十上百个 PHP 文件编译一遍。opcache 把编译结果缓存到共享内存里,后续请求直接复用——不改变任何代码行为,纯白赚。

代价是要给它分内存,而分多少、怎么分,有几个参数容易给错。

下面是我这台机器上实际的值和理由(PHP 8.2,多个 WordPress 站点共用一个 PHP-FPM 池)。

一、参数逐项说明

zend_extension=.../opcache.so
opcache.enable = 1
opcache.memory_consumption = 384
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 80000
opcache.revalidate_freq = 3
opcache.fast_shutdown = 1
opcache.enable_cli = 1
opcache.jit_buffer_size = 0
opcache.jit = disable

memory_consumption = 384(单位 MB)

这是编译产物(opcode)能占的共享内存上限。默认 128 MB 对单个小站够用,但一旦站点多、插件多,满了会触发全量清空并重新编译——表现就是"隔一阵子突然变慢",而且完全静默。

给 384 是留足余量:这个是共享内存,5 个站的 worker 共用同一份,不是每进程一份,所以给大了并不等于每个进程多占内存。

interned_strings_buffer = 16(单位 MB)

字符串驻留区。PHP 会把重复出现的字符串(变量名、函数名、类名)去重后放这里。默认 8 MB。

中文站点 + 多插件的情况下,驻留区也容易被塞满;它满了之后不会报错,只是去重效果变差、内存占用上升。给到 16 是很便宜的提升。

max_accelerated_files = 80000

这一项最容易给错,而且它的名字有历史误导性:

  • 它的上限不是"最多缓存 80000 个文件"这么简单——PHP 内部会把它映射到一个质数,用来决定哈希表的大小;
  • 默认值是 10000,而一个插件稍多的 WordPress 轻松超过这个数;
  • 超出的文件不会被缓存,但你也看不到任何报错,只能从命中率上察觉。

给 80000 是为了让哈希表足够大、覆盖全站文件。

revalidate_freq = 3(单位秒)

多久检查一次源文件的修改时间。

  • 给 0:每次请求都去 stat 文件,等于把 opcache 的收益吃掉一大半;
  • 给太大:改了代码要等很久才生效,排障时容易怀疑人生。

3 秒是个平衡点:改完代码最多等 3 秒。

fast_shutdown = 1

请求结束时的快速清理模式,减少每个请求的收尾开销。开了没坏处。

enable_cli = 1

让命令行运行的 PHP 也启用 opcache。

但要诚实说一句:对"跑完就退出"的一次性脚本(比如一次 wp-cron),共享缓存不会在进程之间保留,开不开几乎没区别。它真正有用的是常驻的命令行进程(队列 worker 之类)。如果你没有这类进程,这一项不用纠结。

jit_buffer_size = 0 + jit = disable

JIT 是关掉的,这是个需要解释的选择。

PHP 8 的 JIT 对计算密集型代码提升明显;但 WordPress 的请求时间主要花在数据库查询、文件 IO、网络等待上——JIT 能优化的那部分占比很小。

而 JIT 开着会:占一块独立内存、增加编译开销、并引入与部分扩展的兼容风险。

所以对 WordPress 这类应用,我选择把它关掉,把内存留给 opcache 本体。如果你跑的是计算密集的 PHP 服务,结论会反过来。

二、怎么确认它真的在生效

# 看配置是否被加载(注意看 ini 路径,别改错文件)
php -i | grep -iE 'opcache|Loaded Configuration'

# 站内查运行状态(把这段临时放到一个只有你能访问的 php 里,用完删掉)
# opcache_get_status() 会给出 :used_memory / free_memory / 命中率 / 缓存脚本数

重点看三个数:

指标说明
opcache_statistics.opcache_hit_rate命中率,稳定在 99% 以上算正常
used_memory / free_memoryfree_memory 接近 0 就说明给少了
opcache_statistics.num_cached_scripts缓存的文件数,若卡在某个值不动,可能是 max_accelerated_files 到顶

CLI 的 opcache_get_status() 和 FPM 的是两套共享内存,别拿 CLI 的结果判断 FPM。

三、改完要重启,不是 reload

opcache 的值在进程启动时读取:

systemctl restart php-fpm-82

光 reload 是没用的。

四、回滚

把值改回原样并 restart。这个优化不涉及数据、不改变行为,回滚成本极低——这也是它值得先做的原因。


一句话总结:opcache 里最值得动手的是三个数——memory_consumption(给足,这是共享内存不是每进程一份)、max_accelerated_files(默认 10000 对 WordPress 太小,且超限时静默不缓存)、revalidate_freq(别填 0)。JIT 对 WordPress 收益有限,我关了。