【Cache System】缓存更新策略 - Cache Invalidation vs Cache Update

Posted by 西维蜀黍 on 2021-08-14, Last Modified on 2023-02-10

Invalidate Cache(淘汰缓存)VS Update Cache(更新缓存)

缓存更新时,Invalidate Cache VS Update Cache

Invalidate Cache

  • Pros

    • 简单
  • Cons

    • 更差的 performance,比如有super hot key时,这个缺点会更加突出

    • 可能会导致 cache avalenche,从而导致 DB 或者对应的data source挂掉。

    • 仍然可能出现读到stale data,比如

      • Case 1 - Due to the nature of async, small period of time where data is stale.

        ​ DB: (x=1) => (x=2)

        1. App writes to database (x=2)
        2. App reads old data from cache (x=1)
        3. Cache gets invalidated (x=nil)
      • Case 2 - Update db and invalidate cache are not atomic

        DB: (x=1) => (x=2)
        
        1. App2 reads from database (x=1)

        2. App1 writes database (x=2)

        3. Cache gets invalidated (x=nil)

        4. App2 writes old data to cache (x=1)

Update Cache

  • Pros
    • 更好的 performance,比如有super hot key
  • Cons
    • 并发写时, Update Cache 更可能出现数据不一致
      • 通过分区,保证在Update Cache时对于同一个key的 cache update的serializability,e.g.,
        • Distributed Lock rescues, but sacrifices performance/avalability
        • 将update cache的操作produce一个消息到MQ,并单独运行一个app用于处理cache update(同时保证同一个key的 cache update的serializability)
          • i.e., trade-off between system complexity and the tolerance of inconsistency

Summary

那到底是选择更新缓存还是淘汰缓存呢,主要取决于“更新缓存的复杂度”。

例如,上述场景,只是简单的把余额money设置成一个值,那么:

  1. 淘汰缓存的操作为deleteCache(uid)
  2. 更新缓存的操作为setCache(uid, money)

具体来说

  1. 如果更新缓存的代价很小,此时我们应该更倾向于更新缓存,以保证更高的缓存命中率。
  2. 如果更新缓存的代价很高(比如余额是通过很复杂的数据计算得出来的,例如业务上除了账户表account,还有商品表product,折扣表discount),则更倾向于删除缓存。

比如:

account(uid, money)
product(pid, type, price, pinfo)
discount(type, zhekou)

业务场景是用户买了一个商品product,这个商品的价格是price,这个商品从属于type类商品,type类商品在做促销活动要打折扣,购买了商品过后,这个余额的计算就复杂了,需要:

  1. 先把商品的品类,价格取出来:SELECT type, price FROM product WHERE pid=XXX
  2. 再把这个品类的折扣取出来:SELECT zhekou FROM discount WHERE type=XXX
  3. 再把原有余额从缓存中查询出来money = getCache(uid)
  4. 再把新的余额写入到缓存中去setCache(uid, money-price*zhekou)

更新缓存的代价很大,此时我们应该更倾向于淘汰缓存。

Reference