Skip to content

性能基准

测试环境:Apple M5(10 核),本地回环,使用 redis-benchmark -n 100000 -c 50

场景SET QPSGET QPSp50 延迟
基线(不淘汰)62,18965,2310.42ms
流水线 -P 16350,877378,7871.06ms
LFU(16MB 上限)57,33961,6900.42ms
AHE(16MB 上限)59,55950,7870.42ms

如何解读

  • 流水线 是提升吞吐最显著的杠杆 —— 批量发送命令可降低单请求开销,成倍提升吞吐。
  • QPS 和延迟只说明引擎"跑得多快",却无法体现淘汰算法的真正目的:把工作集留住。下面的命中率表补上了这个缺口。

各淘汰策略的命中率

这才是评判一个缓存淘汰算法的核心指标,也是纯 QPS 数字无法体现的:在真实访问模式下,工作集能留住多少。测试以端到端方式跑在真实 server 上(与上面的 QPS 方法一致),工作集为 100,000 个不同键,缓存上限 5,000 个条目(约 590 KiB)——即缓存只装得下键空间的 1/20,淘汰始终处于高压状态。

策略zipf(稳定倾斜)shift(热点轮转)mixed(热集 + 扫描)scan(纯顺序)
allkeys-lru59.5%52.4%56.3%0.0%
allkeys-lfu59.4%51.1%58.0%0.0%
allkeys-ahe59.5%52.3%56.8%0.0%
allkeys-random57.1%52.4%54.5%0.0%

越高越好。每个格子用同一份固定种子的负载、对应当前策略的全新 server 回放;数值取自 server 自身的 keyspace_hits / (keyspace_hits + keyspace_misses)(含冷启动)。复现方式:scripts/bench-hit-ratio.sh;测试代码见 examples/hit_ratio_bench.rs

方法说明

  • 读穿透客户端GET 未命中则用 SET 回填,与实际缓存填充一致。只有缓存填满后淘汰才会触发——这才是关键区间。
  • 真实的请求间隔(约 1ms)。FerrumKV 的 LRU 与 AHE 都是时间相关的:recency 以 600 秒为尺度衡量,AHE 控制器也以观测到的命中率为输入。紧凑的进程内微基准会在毫秒内跑完,把 recency 信号压平、让自适应循环失效——那样 AHE 会静默退化为纯 LFU,对比也就失去意义。用真实 server 加真实间隔驱动,recency 与自适应循环才能表现得和生产环境一致。
  • 每个 (策略, 模式) 都用独立的新 server,计数不会跨负载泄漏。
  • 负载模式zipf(稳定 Zipf 倾斜,最简单的情况)、shift(热点区间每个 epoch 轮转,非平稳负载)、mixed(小热集 + 周期性全扫描,类 OLTP)、scan(纯顺序,用于诚实展示"所有策略都无能为力"的对照)。第五个模式 ttl 也可通过 --patterns ttl 选用,它把持久热集与短 TTL 的 ephemeral 集混合以检验 TTL 感知型淘汰;在我们的实测中,它在现实缓存容量下与 LRU/LFU 趋同、在极紧的缓存下也不稳定优于 LFU,因此作为 opt-in 模式,不列入上面的头条矩阵。
  • 单次代表性运行;数字在不同运行间约有 ±1 个百分点的波动,因为引擎内部的 LFU/LRU 采样 RNG 以系统时钟为种子。

数字说明了什么

  • 稳定倾斜(zipf:各策略都收敛到约 59%;AHE 与领先者持平。
  • 热点轮转(shift:LFU 粘性的频率计数器崩到 51.1%,而 LRU 与 AHE 维持在 约 52.3–52.4%——AHE 跟随 LRU,避开了 LFU 的最差情况。
  • 混合(mixed:LFU 领先(58.0%),LRU 跌到 56.3%;AHE 落在 56.8%——接近 LRU,明显优于 random 的 54.5% 下限。
  • 纯扫描(scan:所有策略都被钉在约 0%,证明 AHE 不会把无望的访问模式变魔术般救回来。

结论:AHE 是"无后悔"的选择。 在每种负载下它都跟住 LRU 与 LFU 中较优的一方,且从不陷入任一方的最差情形(LFU 在热点轮转时、LRU 在扫描密集的混合负载时)。这种自适应能力——而非对 recency 或 frequency 的固定偏向——才是该算法的意义所在。

完整的方法说明与原始输出见 benches/redis-benchmark.md