- 本文地址: https://www.laruence.com/2026/08/20/6420.html
- 转载请注明出处
这个博客用了很多年 Memcached。它一直很稳定,也没出过什么问题,但有件事始终绕不开:PHP 每读一次缓存,都要经过 localhost TCP。连接管理、协议编解码、数据往返,单次开销不算大,可 WordPress 渲染一个页面往往要读几十甚至上百次对象缓存,累积起来就很可观了。
更重要的是,这部分开销和缓存命中率无关。即使命中了,也得完整走一遍。
Yac(Yet Another Cache)走的是另一条路。它把缓存放在 PHP-FPM master 创建的共享内存里,worker 进程 fork 之后可以直接访问,不需要独立的缓存服务,也不需要经过 socket。
既然 WordPress 有标准的 Object Cache 接口,我就想试试看:把 Memcached 换成 Yac,实际能省下多少?
于是有了 WP Yac Object Cache。它提供标准的 object-cache.php drop-in,激活后自动部署,同时带了一个后台面板,用来查看缓存命中率、内存占用和淘汰情况。

实际能快多少?
测试直接使用这个博客的首页,没有另外准备空白站点或测试页面。服务器是 8 核 CPU、31GB 内存,运行 PHP 8.1 FPM 和 Nginx。Memcached 通过 localhost:11211 访问,Yac 使用 WP Yac v1.0.0。
为了让两组测试尽量对称,每轮都只替换 Object Cache drop-in,其他配置不动。测试前先执行 wp cache flush,重启 PHP-FPM,再用 500 个请求预热,最后分别以 20、50、100 并发持续压测 30 秒。
| 并发 | Yac RPS | Memcached RPS | 提升 | Yac p50 | Mem p50 | Yac p95 | Mem p95 |
|---|---|---|---|---|---|---|---|
| 20 | 141.6 | 118.7 | +19.3% | 139ms | 167ms | 192ms | 216ms |
| 50 | 140.6 | 118.5 | +18.6% | 353ms | 420ms | 407ms | 465ms |
| 100 | 142.1 | 118.4 | +20.1% | 699ms | 840ms | 754ms | 886ms |
每档测试都完成了 3500 到 4200 次完整页面渲染,返回码全部为 200,没有失败请求。

三档并发下,Yac 的吞吐量都在 140 RPS 左右,Memcached 则在 118 RPS 左右,差距很稳定。换成 ab -n 10000 -c 100 的固定请求数再测一轮,结果也差不多:Yac 为 141.8 RPS,Memcached 为 120.6 RPS,提升 17.6%。
这个结果当然不意味着所有 WordPress 站点换成 Yac 都会快 19%。主题、插件、数据库负载和每个请求访问缓存的次数不同,收益也会不同。但至少在这个博客上,差异可以稳定复现。
这 19% 是从哪里省出来的?
Yac 的优势不是命中率更高,而是命中以后,取回数据的路径更短。
Memcached 的调用路径大致是:
PHP → Socket → Memcached → Socket → PHP
Yac 则是:
PHP → Shared Memory
一次访问只省下一点时间,未必容易观察。但 WordPress 生成一个页面时,会反复读取 options、terms、post meta、comments 等对象。几十上百次访问累积起来,省掉的 socket 通信和协议处理成本就变成了一个可以测出的差距。
测试还说明了另一件事:Yac 到了大约 140 RPS 后,继续增加并发,吞吐量也没有再提高。此时的瓶颈已经转移到了 PHP 页面渲染和 MySQL。并发从 20 增加到 100,p50 延迟也从 139ms 增加到 699ms,基本就是吞吐饱和后的排队结果。
所以,这次优化解决的是每个请求里反复访问对象缓存的固定成本,而不是把站点的所有瓶颈都解决了。真要继续提高上限,下一步应该看 OPcache、页面缓存或多机部署,而不是继续调对象缓存。
安装
先安装 PHP 的 Yac 扩展,下面三种方式任选一种。
# PECL pecl install yac # PIE(PHP Foundation 的 PECL 继任者,Yac 已在 Packagist) pie install laruence/yac # 源码编译 git clone https://github.com/laruence/yac.git && cd yac phpize && ./configure && make && sudo make install
安装完成后,在 php.ini 中启用扩展:
extension=yac.so
然后重启 PHP-FPM。
安装 WordPress 插件
最简单的方式是在 WordPress 插件市场搜索 yac-object-cache,安装并激活。

也可以使用 WP-CLI:
wp plugin install https://github.com/laruence/wp-yac-cache/releases/latest/download/yac-obj-cache.zip --activate
或者从 GitHub Releases 下载 yac-obj-cache.zip,再到 WordPress 后台上传安装。
插件激活后,会自动把 drop-in 部署到 wp-content/object-cache.php。然后在 wp-config.php 的 “That's all, stop editing!” 之前加入:
define( 'WP_CACHE', true ); define( 'WP_YAC_KEY_PREFIX', 'wp' );
如果同一个 PHP-FPM 池里运行了多个 WordPress 站点,每个站点都要使用不同的 WP_YAC_KEY_PREFIX,避免缓存键互相冲突。
插件还提供一个紧急开关:
define( 'WP_YAC_DISABLE', true );
启用后,插件会绕过 Yac,退回到单次请求内的缓存。如果上线后发现异常,可以先用它恢复站点,再排查问题。服务器没有安装 Yac 扩展时,drop-in 也会自动采用请求内缓存,站点仍然可以运行,只是得不到共享内存缓存的效果。
Yac 配置
这是这个博客运行一段时间后采用的配置:
yac.enable=1 yac.keys_memory_size=16M yac.values_memory_size=64M yac.compress_threshold=4096
Yac 的键空间和值空间是分开配置的。yac.keys_memory_size 决定可以容纳多少键,yac.values_memory_size 决定可以保存多少实际数据。发现淘汰时,要先判断是哪一块空间不足,而不是不加区分地一起扩大。
上面的 16M/64M 是这个大约 300 篇文章的博客实际运行后的配置。普通小站通常从 8M/64M 开始就够了,没有必要一上来分配很大的共享内存。
怎么看缓存是否正常?
插件激活后,可以从 WordPress 后台的 Tools → Yac Object Cache 打开状态面板。
刚安装时缓存还在预热,命中率低是正常的。只要键槽占用不到 90%,状态会保持为绿色。键槽接近满载后,面板才会结合命中率判断:
- 命中率高于 90%:绿色;
- 命中率在 70% 到 90%:黄色;
- 命中率低于 70%:红色。
如果键槽还没满,但值内存已经用完,状态也会显示为黄色。这时应该增加 yac.values_memory_size,或者启用 yac.compress_threshold,而不是扩大键空间。
面板里的 Hits 和 Misses 与其他缓存含义相同。另有两个 Yac 特有的指标:
- Kicks:键槽淘汰次数。Yac 使用定长哈希表,插入时连续探测 4 次仍然找不到空槽,就会淘汰旧条目。少量 Kicks 属于正常现象,持续快速增长才说明键空间可能不足。
- Recycles:值空间循环覆盖次数。值空间写满后会回到开头覆盖旧数据。Yac 没有 LRU,因此 Recycles 持续增加时,通常应该扩大值内存。

内容统计可以进一步回答“内存到底被谁占了”。饼图按 group 展示键的分布,Largest entries 则列出占用最大的条目。我的站点里,评论相关缓存约占键数量的 83%;较大的对象包括约 54.97KB 的 wp:options:alloptions,以及约 227KB 的 wp:post_meta:23。
这些数据能帮助判断问题究竟是键太多,还是某些值太大。面板中的键也尽量保持可读,格式是 <前缀>:<group>:<key>。超过 48 字节预算时会保留 group,只对 key 部分做哈希,这样仍然可以按 group 归因。
使用前需要注意
首先,Yac 是本机共享内存缓存。单机部署,或者节点之间不要求共享缓存时,Yac 很合适。但如果是多机集群,并且所有节点必须使用同一份缓存,那么 Memcached 或 Redis 的网络共享能力反而是必要特性。
其次,wp_cache_flush() 的影响范围比较大。它会清空这台机器上的整块 Yac 共享内存,其中可能包括同一个 PHP-FPM 池里其他 Yac 使用者的数据。多个站点共用 PHP-FPM 池时要特别注意。更稳妥的方式,是让不同站点使用独立的 PHP-FPM 池。
最后
对象缓存其实不是这个博客最大的瓶颈。压测结果已经很清楚:到了 140 RPS 左右以后,限制吞吐的是 PHP 页面渲染和 MySQL。
即便如此,把 Memcached 换成 Yac 后,仍然获得了接近 19% 的吞吐提升,延迟也有所降低。原因并不复杂:WordPress 每次生成页面都会大量访问对象缓存,Yac 把这些访问从 socket 通信变成了共享内存读写。每次只快一点,累积起来就是一个可以稳定测出的差距。
对单机 WordPress 来说,除了性能提升,还可以少运行和维护一个 Memcached 服务。如果服务器允许安装 PHP 扩展,值得试试看。
项目地址:github.com/laruence/wp-yac-cache(GPLv2)
WordPress插件审核通过了:https://wordpress.org/plugins/yac-object-cache/
最近看到鸟哥连着更新博客,还在编码折腾,有受到鼓舞,哈哈。也谢谢鸟哥一直在更新维护 Ya 系列的扩展 🙂
我是使用hostinger共享主机,Yac这个不能在cli安装,是否您的插件在wordpress的插件市场通过后,就可以直接安装插件??不需要再增加系统底层的功能??
或者有什么办法,在共享主机环境直接安装插件使用?
那不太行,你需要能修改php增加这个扩展,或者你也可以问问你的提供商,yac是标准pecl扩展,应该也要支持的
我在一个独立主机安装yac了,是在宝塔-php插件中安装。然后设置了参数:
yac.enable = 1;
yac.keys_memory_size = 512M ;
yac.values_memory_size = 1024M ;
请问这样设置是否可以?4核16G的主机,提示如下,大概什么意思?
Only 0% of the slotted entries belong to this install — the slot pressure is shared-pool occupancy from other Yac users on this machine. Raise yac.keys_memory_size or run a separate pool.
感觉内存分配的有点多了,一般不大的站点8M/64就够了,内容多的,爬虫机器人多的,可以考虑只加大keys比如16M/64M,不过就算keys满了也没关系,主要看hits rate,这个提示如果你是刚刚装完,冷启动的时候立即看,确实可能误报,我回头修一下,你忽略就好了,等缓存热起来就应该没了
搜了一下,Memcached竟然没有可靠支持 unix socket。
yac 很有用啊,解决了单机高并发请求缓存问题,例如本地配置文件。场景,单服务器多容器部署,无配置中心时,yaf 大型项目多目录结构多配置文件频繁切换,频繁读取本地配置文件导致文件最大句柄超出服务器最大数而瘫痪,使用redis 增加网络请求。
如果是静态不变的配置文件话,建议使用yaconf, 会更合适一些, 新版本的yaconf也支持子目录了,你可以一个项目一个子目录,方便管理,当然性能也更好
这是每个金丹期phper曾经绞尽脑汁的事(曾经觉得eAccelerator、opcache、memcached、Zend optimizer很神奇,然后是mod_php、php-fpm、varnish。。。),直到php不再是自己的主力语言😂