本文约 4,198 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:免费的 30% 性能,你只拿到了 5%
从 PHP 5.5 开始,OPcache 已经内置。它的作用是把 PHP 脚本编译后的字节码(opcode)缓存到共享内存,下次请求不用重新解析编译。这是零成本、零风险的性能提升,通常能给 WordPress 带来 20%–40% 的提速。
但默认配置是这样的:
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
128MB 内存、10000 个文件上限——一个装了 30 个插件的 WordPress,wp-includes + wp-admin + 插件 + 主题的文件总数轻松超过 15000。超过上限的文件根本不会被缓存,你的 OPcache 实际只缓存了一部分。
原理分析:OPcache 缓存了什么,不缓存什么
执行一个 PHP 文件时,Zend 引擎的流程是:
读取源码 → 词法分析 → 语法分析 → 编译成 opcode → 执行
前四步每次请求都重复,而源码没变。OPcache 把「编译结果」存进共享内存,之后直接跳到执行。
几个必须理解的参数:
opcache.memory_consumption:共享内存大小(MB)。满了之后新文件不再被缓存(不会淘汰旧的!这点很多人不知道)。opcache.interned_strings_buffer:字符串驻留内存。WordPress 大量重复字符串(如'post'、'options')靠这个省内存。默认只有 8MB,偏小。opcache.max_accelerated_files:哈希表的槽位数。不是文件数上限,但槽位越接近实际文件数,冲突越多,效率越低。可选值必须是质数集合里的:223、463、983、1979、3907、7963、16229、32531、65407、130987。opcache.revalidate_freq:多久检查一次文件是否被修改(秒)。设 0 表示每次请求都检查(开发环境用),生产环境设 60–300 更合适。opcache.validate_timestamps:是否检查文件时间戳。生产环境如果配合部署脚本主动清缓存,可以设为 0(不检查),性能最好,但改代码后必须手动重置 OPcache。
关键误区:OPcache 只缓存 PHP 的编译结果,不缓存数据库查询、不缓存 HTML。它和 Redis 对象缓存、页面缓存是三个不同层次。
保姆级实操
第一步:找到配置文件位置
php --ini | grep -i opcache
# 或
php -i | grep -i "opcache.*ini"
常见位置:
- Ubuntu/Debian:
/etc/php/8.2/fpm/conf.d/10-opcache.ini - CentOS:
/etc/php.d/10-opcache.ini - 宝塔:
/www/server/php/82/etc/php.ini
第二步:WordPress 推荐配置
[opcache]
; 启用(CLI 建议关闭,避免 WP-CLI 出现缓存困扰)
opcache.enable=1
opcache.enable_cli=0
; 共享内存:小站 128MB,中型站 256MB,插件多的站 384MB
opcache.memory_consumption=256
; 字符串驻留:16–32MB
opcache.interned_strings_buffer=32
; 文件槽位:必须是质数集合里的值,建议 32531 或 65407
opcache.max_accelerated_files=32531
; 文件修改检查间隔:生产 60 秒
opcache.validate_timestamps=1
opcache.revalidate_freq=60
; 快速关闭(加快 shutdown,但可能有边缘问题,可选)
opcache.fast_shutdown=1
; 注释不加载到内存,省一点
opcache.save_comments=1
; 大站可调高,小站默认即可
opcache.max_wasted_percentage=10
; 生产环境关掉错误信息输出
opcache.error_log=/var/log/php-opcache.log
第三步:重启生效
sudo php -i | grep "Loaded Configuration" # 确认改的是正确的 ini
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx
宝塔:软件商店 → PHP 8.2 → 服务 → 重启;或在 PHP 配置文件里改。
第四步:验证配置是否生效
php -r 'print_r(opcache_get_status()["memory_usage"]);'
php -r 'print_r(opcache_get_status()["opcache_statistics"]);'
重点看这几个值:
Array(
[used_memory] => 89432168
[free_memory] => 178543280
[wasted_memory] => 0
[current_wasted_percentage] => 0
)
Array(
[hits] => 982341
[misses] => 15234
[opcache_hit_rate] => 98.47
[num_cached_scripts] => 12480
[max_cached_keys] => 32531
)
健康指标:
- 命中率(opcache_hit_rate)> 99%;
num_cached_scripts明显小于max_cached_keys(说明槽位够);free_memory占总量 30% 以上(说明内存够);wasted_memory高说明文件频繁改动产生碎片,需要重启 FPM。
第五步:加一个可视化面板(可选)
装 OPcache Manager、OPcache Dashboard 之类的单文件脚本(如 opcache-gui),放到 Web 目录,能看到缓存了哪些文件、内存分布。注意:用完就删,别暴露在公网。
第六步:部署时主动清缓存
改了 PHP 文件后,如果 revalidate_freq=60,可能要等一分钟才生效。部署脚本里加:
# 通过 php-fpm 的 status 触发(需开启 pm.status_path)
# 或者最简单:重启 FPM
sudo systemctl reload php8.2-fpm
用代码清(适合自动化部署):
<?php
// opcache-reset.php —— 用完务必删除
if ( $_GET['token'] !== '你的随机token' ) { http_response_code(403); exit; }
opcache_reset();
echo 'ok';
常见踩坑
- 改了配置但没生效:改错了文件。用
php --ini找到实际加载的 ini,宝塔环境下经常有多个 php 版本,改到没用的那个去了。 max_accelerated_files填了非质数:虽然不会报错,但内部会向上取到最近的质数,观察值和设置值不一致会让人困惑。- 内存满了之后新文件不缓存:
wasted_memory涨、misses上升。判断方法:num_cached_scripts卡在某个值不再增长。解决:加大memory_consumption,或重启 FPM。 - 案例:某站
opcache.validate_timestamps=0追求极致性能,结果改了主题文件后前台一直不变,站长以为缓存插件坏了,折腾两天。最后发现是 OPcache 没清。生产环境建议保留validate_timestamps=1,那点性能收益不值得这个排查成本。 opcache.enable_cli=1导致 WP-CLI 结果异常:CLI 每次执行是新进程,缓存意义不大,反而可能让wp cache flush之类的命令行为诡异。保持 0。- 多个 PHP 池(pool)共用一份 OPcache:这是正常的,OPcache 是进程间共享内存,不需要每个 pool 都配。但是不同 PHP 版本的 OPcache 是独立的。
- Docker 环境:容器内改了 ini 要重建镜像或挂载配置。
docker-compose.yml里加:
yaml
volumes:
- ./opcache.ini:/usr/local/etc/php/conf.d/opcache.ini:ro
总结
OPcache 是性价比最高的 WordPress 优化项:改几个参数、重启服务,零风险换来 20%–40% 提速。核心配置项就四个:内存(memory_consumption)、字符串缓冲(interned_strings_buffer)、文件槽位(max_accelerated_files,取质数)、检查频率(revalidate_freq)。上线后用 opcache_get_status() 看命中率和内存余量,这两项达标就说明配好了。它和 WordPress Redis 对象缓存、Nginx FastCGI 缓存 是叠加关系,三层都配好,PHP 才算真的优化到位。
