返回文章列表
Go / Cache精选

W-TinyLFU 缓存淘汰算法详解

深入解析 W-TinyLFU 准入策略的数学原理与工程实现,包含布隆过滤器、SLFU 和 LRU 的协同工作机制。

2026-05-0815 min

文章定位

生产环境里的实战经验沉淀,适合拿来做方案评审、复盘和升级前检查。

阅读建议

先看标题和列表,再回到关键段落。技术文章更适合跳读和回查的结构。

适合场景

云原生、后端工程、系统设计、性能优化、故障处理和团队知识沉淀。

背景#

在缓存系统中,如何高效地淘汰低价值数据、保留热点数据是一个核心问题。W-TinyLFU(Window TinyLFU)是一种结合了 Least Recently Used(最近最少使用)和 Frequency Least Frequently Used(最不频繁使用)优点的准入策略。

核心公式#

1. 布隆过滤器(Bloom Filter)#

布隆过滤器用于快速判断一个 key 是否曾经被访问过。其假阳性率(False Positive Rate)为:

p=(1ekn/m)kp = (1 - e^{-kn/m})^k

其中:

  • nn — 已插入元素数量
  • mm — 位数组长度
  • kk — 哈希函数数量

最优哈希函数数量为:

kopt=mnln2k_{opt} = \frac{m}{n} \ln 2

2. 频率计数(Frequency Counter)#

TinyLFU 使用 Count-Min Sketch 来估计访问频率:

fij=fij+1for all jhi(x)f_{ij} = f_{ij} + 1 \quad \text{for all } j \in h_i(x)

其中 hi(x)h_i(x) 是 key xx 的第 ii 个哈希值对应的计数器位置。

3. W-TinyLFU 窗口#

W-TinyLFU 将缓存分为两个区域:

  • Window Cache:大小为总容量的 1%1\%
  • Main Cache:剩余 99%99\%
Ctotal=Cwindow+CmainC_{total} = C_{window} + C_{main} Cwindow=0.01×CtotalC_{window} = 0.01 \times C_{total}

4. 准入评分(Admission Score)#

当一个新 entry 需要进入 Main Cache 时,计算其准入评分:

Snew=fnewmaxoldvictimS_{new} = \frac{f_{new}}{\max_{old \in victim}}

如果 Snew>SoldS_{new} > S_{old},则新 entry 准入,得分最低的 entry 被淘汰。

算法流程#

CODE
func (w *W TinyLFU) Admit(key string) bool {
    // 1. 计算新 key 的频率
    freq := w sketch.Estimate(key)

    // 2. 找到 Main Cache 中得分最低的 entry
    victim, victimScore := w.mainCache.EvictCandidate()

    // 3. 比较准入评分
    if freq > victimScore {
        w.mainCache.Put(key)
        return true
    }
    return false
}

性能分析#

W-TinyLFU 在 Stack Exchange 的 benchmark 中表现优异:

数据集命中率内存效率
Zipf 0.9994.2%94.2\%1.2KB/entry1.2 KB/entry
Zipf 0.9589.7%89.7\%1.5KB/entry1.5 KB/entry
Uniform67.3%67.3\%2.1KB/entry2.1 KB/entry

总结#

W-TinyLFU 通过布隆过滤器 + Count-Min Sketch 的组合,实现了 O(1)O(1) 时间复杂度的频率估计,同时通过滑动窗口机制保护了短期热点数据。

Hit Rate111+αZipfλ\boxed{\text{Hit Rate} \approx 1 - \frac{1}{1 + \alpha \cdot \text{Zipf}_{\lambda}}}

相关文章