💠

💠 2024-09-06 11:36:43


缓存

用时效和空间换时间

从Web应用系统的流程上可分为 客户端 服务端 数据库

缓存淘汰算法

  • FIFO First In First Out 先进先出

    • 优点:实现简单
    • 缺点:未考虑数据访问频率和时间,和实际场景不贴和。
  • LRU Least Recently Used 最近最久未使用

    • 实现方式:维护一个所有数据的链表,新数据插入到链表的头部,如果缓存满了,就会从链表尾部开始移除数据。
    • 优点:LRU考虑了最近的数据访问模式,对于局部性原理的表现优秀,简单实用
    • 缺点:不能体现数据的访问频率,如果数据最近被访问过,即使访问频度低也不会被淘汰。
      • 如果一个数据在一分钟的前59秒被频繁访问,而在最后一秒无任何访问,但是有一批冷门数据在最后一秒进入缓存,那么热点数据可能会被淘汰掉。
  • SLRU Segmented LRU 分段LRU

    • 实现方式:类似于内存分代,将缓存分为淘汰段,保护段,两个段都是LRU实现。
      • 数据访问第一次被放入淘汰段,访问第二次才会升级到保护段
      • 保护段的数据要淘汰时,数据复制到淘汰段。淘汰段的数据要淘汰时就会被直接删除。
    • 优点:抵御冷门数据引起热门数据被淘汰
    • 缺点:两段的容量设计需要更参考业务场景做调优
  • LFU Least Frequently Used 最近最少频率使用

    • 实现方式:对每个在缓存中的数据进行计数,记录其被访问的次数
    • 优点:LFU能够较好地处理长期访问稳定、频率较高的情况,因为这样可以确保频繁访问的数据不容易被淘汰。
    • 缺点:对于一些暂时高频访问但之后不再访问的数据,LFU无法有效处理。因为这些数据的访问次数已经非常高,不容易被淘汰,可能造成缓存空间的浪费。
      • 并且LFU需要维护所有对象的访问计数,这可能会消耗比较多的存储空间和计算资源。
  • W-TinyLFU Window Tiny Least Frequently Used 论文 TinyLFU: A Highly Efficient Cache Admission Policy

    • 实现方式: W-TinyLFU缓存淘汰策略
    • 优点:
      • 平衡了最近性和频率:与 LRU 相比,不仅考虑了使用频率,还计算了缓存的热门程度。与 LFU 相比,不会让以前非常热门但现在很少使用的数据长时间占用缓存。
      • 额外内存占用小: TinyLFU 使用一个固定大小的计数滤波器来跟踪访问频率,这使得其内存占用远低于传统的 LFU 策略。
      • 适应性强:可以更好地适应工作负载的变化,因为它对频率的计数有一个时间窗口
      • 避免缓存污染:由于它维护了一个 admission window,它可以避免一次性的、大规模的请求可能带来的缓存污染。
    • 缺点:
      • 需要维护额外的频率信息,SLRU等,增加了一些开销。
      • 不如 LRU 算法实现简单。对于不同的使用场景,需要调整参数以获得最佳性能。

应用场景

客户端

浏览器

  • 静态资源缓存,Cookie,各种 *Storage, IndexDB

PC端原生

  • 配置文件,SQLite,LevelDB

服务端


数据库

会话缓存

MySQL Buffer Pool


分布式缓存

使用分布式共识算法构建出一个集群,将读写压力摊分到集群内节点上。

  • tinykv 构建分布式 Key-Value 数据库的教程

Ehcache

Redis cluster

一致性Hash实现数据在分区上的均匀分布


场景

Hot Key

海量用户请求同一个key,引发整个链路的 网卡 带宽 CPU 出现瓶颈

  • 统计出hot key 将这批key分散在集群内多个节点上
  • 多级缓存,将流量的请求链路缩短

BigKey

Value的内存占用很大,读写,加载容易超时的key

  • 拆分Key

缓存雪崩 Cache Avalanche

缓存层大量缓存过期,或者整个缓存层崩溃, 导致大量流量直接访问上游资源层

缓存穿透 Cache Penetration

缓存层和上游资源层都没有当前查询的数据

缓存击穿/崩溃 Cache Breakdown

缓存层部分数据过期了,并且突增大量流量直接访问上游资源层,去查询这部分过期的数据

缓存一致性

缓存和数据库一致性问题,看这篇就够了

参考: 关于缓存可靠性、关乎数据一致性

  • 数据库更新 缓存更新
  • 数据库更新 缓存删除