Yac 3.0 发布:常见缓存负载吞吐提升 42%

Yac 3.0 发布:常见缓存负载吞吐提升 42%

💡 原文中文,约5500字,阅读约需14分钟。
📝

内容提要

Yac 3.0 发布,重点优化缓存读写性能:新增 inline 机制,短 key 的 value 直接存入 slot,省去分配和拷贝,double 也可内联;读路径改用 versioned snapshot,降低读多写少场景的协调开销;引入基于 epoch 的 CRC,仅在无法确认数据稳定时校验;自研序列化器支持 array 和 stdClass,其余回退 PHP 原生;新增 Yac::has(),不更新 atime 和 hits。测试显示常见负载吞吐较 2.4.2 提升 42.3%,最高 95.4%。

🔎

延伸解读

42% 是缓存吞吐,不是页面速度

文中明确说明,42.3% 的几何平均提升指的是直接压缓存的 aggregate ops/s,测试条件为 16 个 worker、100:1 读写比、160MB 共享内存且关闭压缩。作者特意提醒,一个页面还包含 PHP、数据库、模板、网络和插件等环节,缓存只占其中一部分,因此不能把该数字理解为页面速度提升 42%。读者评估收益时,应区分缓存层指标与端到端响应时间。

inline 机制有明确的空间边界

inline 把 value 紧跟在 key 后放入同一个 slot,条件是 strlen($key) + strlen($value) <= 48。这意味着 key 越短,留给 value 的空间越大;key 恰好 48 字节时 inline 没有空间,仍会分配 values block。该机制让 double 也能内联,而 2.4 的 embedded 因只剩 61 bit payload 无法容纳完整 IEEE 754 双精度。短 option、短状态等负载更容易受益,长 key 或长 value 则不受影响

升级前需清理旧序列化配置

3.0 移除了 yac.serializer、JSON、MsgPack、igbinary 三套可选 serializer 及相应编译选项,改为内部 serializer 处理 array 和 stdClass,不支持的对象和值回退到 PHP 原生序列化。升级前应搜索并删除旧配置项,否则残留配置可能无效或引发困惑。此外,依赖 dump() 做分析的脚本需把 embedded 字段换成 loc,并注意带 prefix 的实例 dump() 返回的 key 不再包含内部 prefix。

has() 与属性判断不扰动 LRU

新增的 Yac::has() 用于判断键是否存在,且不更新 atime 和 hits;属性形式的 isset、empty、property_exists 检查从 3.0 起也不影响 LRU 信息。这对存在性探测很实用:false、null 都可以是正常缓存值,用 get() 判断“到底有没有”并不顺手,而 has() 能避免把仅做存在性检查的条目误标为刚被访问,从而减少对淘汰顺序的干扰。

❓

Q&A

Yac 3.0 的 inline 机制是什么?它解决了什么问题?

inline 机制是将短 key 的 value 直接存放在 slot 中 key 后面的剩余空间里,只要 strlen($key) + strlen($value) <= 48 就不进入 values 区。它解决了 2.4 版本 embedded 方案无法内联 double 的问题(因为 val 只剩 61 bit payload),现在 double 和短字符串都能内联,减少了内存分配和拷贝。

Yac 3.0 的读路径优化具体是怎么做的?

读路径改用 versioned snapshot,借鉴 Linux 内核的 seqcount/seqlock 思路:writer 更新前将 sequence 改为奇数,完成后改回偶数;reader 前后各读一次 sequence,若两次相同且为偶数则快照有效,否则重试。这样在读多写少场景下减少了协调开销,是性能提升的主要来源之一。

Yac 3.0 相比 2.4.2 吞吐量提升了多少?测试条件是什么?

在 16 个 worker、100:1 读写比、160MB 共享内存、关闭压缩的测试中,6B 到 8KB 常见值范围的几何平均吞吐提升 42.3%;布尔值、整数、开关和短值等负载最高提升 95.4%。测试环境为 MacBook Pro M5 Pro、PHP 8.5。

Yac 3.0 新增的 Yac::has() 方法有什么特点?

Yac::has() 用于判断缓存键是否存在,支持 false、null 等正常缓存值。它的特点是不会更新 atime 和 hits,也不会影响 LRU 信息,适合纯粹的存在性检查。

Yac 3.0 的序列化器有什么变化?

Yac 3.0 自研了内部序列化器,针对 array 和 stdClass(包括可支持的引用值)使用 Yac 内部序列化,不支持的对象和值回退到 PHP 原生序列化。同时删除了旧的 yac.serializer、JSON、MsgPack、igbinary 等可选序列化器及相关编译选项。

升级到 Yac 3.0 需要注意哪些兼容性变化?

升级前需删除配置中的 yac.serializer、enable-json、enable-msgpack、enable-igbinary 等选项;依赖 dump() 的脚本需将 embedded 字段改为 loc,并注意 dump() 返回的 key 不再带 prefix。当前正式版为 3.0.1,可通过 pecl upgrade yac 或源码安装升级。

🏷️

标签

➡️

继续阅读