Press "Enter" to skip to content

用Yac给WordPress做缓存:比Memcached快19%

这个博客用了很多年 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,激活后自动部署,同时带了一个后台面板,用来查看缓存命中率、内存占用和淘汰情况。

WP Yac 后台面板:命中率与健康状态

图1:后台面板会直接显示命中率、健康状态和相关指标

实际能快多少?

测试直接使用这个博客的首页,没有另外准备空白站点或测试页面。服务器是 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 与 Memcached 吞吐对比

图2:三档并发下,Yac 的吞吐提升都稳定在 19% 左右

三档并发下,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,安装并激活。

在 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 持续增加时,通常应该扩大值内存。

Yac 共享内存内容统计

图3:共享内存中的键分布、占用统计和最大条目

内容统计可以进一步回答“内存到底被谁占了”。饼图按 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)

11 Comments

  1. Jack
    Jack August 23, 2026

    最近看到鸟哥连着更新博客,还在编码折腾,有受到鼓舞,哈哈。也谢谢鸟哥一直在更新维护 Ya 系列的扩展 🙂

  2. jiangjun
    jiangjun August 22, 2026

    我是使用hostinger共享主机,Yac这个不能在cli安装,是否您的插件在wordpress的插件市场通过后,就可以直接安装插件??不需要再增加系统底层的功能??

    • jiangjun
      jiangjun August 22, 2026

      或者有什么办法,在共享主机环境直接安装插件使用?

    • laruence
      laruence August 22, 2026

      那不太行,你需要能修改php增加这个扩展,或者你也可以问问你的提供商,yac是标准pecl扩展,应该也要支持的

      • jiangjun
        jiangjun August 23, 2026

        我在一个独立主机安装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.

        • laruence
          laruence August 23, 2026

          感觉内存分配的有点多了,一般不大的站点8M/64就够了,内容多的,爬虫机器人多的,可以考虑只加大keys比如16M/64M,不过就算keys满了也没关系,主要看hits rate,这个提示如果你是刚刚装完,冷启动的时候立即看,确实可能误报,我回头修一下,你忽略就好了,等缓存热起来就应该没了

  3. 石樱灯笼
    石樱灯笼 August 22, 2026

    搜了一下,Memcached竟然没有可靠支持 unix socket。

  4. dust
    dust August 21, 2026

    yac 很有用啊,解决了单机高并发请求缓存问题,例如本地配置文件。场景,单服务器多容器部署,无配置中心时,yaf 大型项目多目录结构多配置文件频繁切换,频繁读取本地配置文件导致文件最大句柄超出服务器最大数而瘫痪,使用redis 增加网络请求。

    • laruence
      laruence August 21, 2026

      如果是静态不变的配置文件话,建议使用yaconf, 会更合适一些, 新版本的yaconf也支持子目录了,你可以一个项目一个子目录,方便管理,当然性能也更好

  5. bolo
    bolo August 20, 2026

    这是每个金丹期phper曾经绞尽脑汁的事(曾经觉得eAccelerator、opcache、memcached、Zend optimizer很神奇,然后是mod_php、php-fpm、varnish。。。),直到php不再是自己的主力语言😂

Comments are closed.