论缓存一致性如何保证

220 阅读4分钟

开篇:哪类数据适合缓存

        缓存量大读取比较频繁但又不常变化的数据,比如详情,评论等。对于那些进场变化的数据,其实并不适合缓存,一方面会增加系统的复杂性(缓存的更新,缓存的脏数据),另一方面也给系统带来一定的不稳性(缓存系统的维护)。

但一些极端情况下,你需要将一些会变动的数据进行缓存,比如想要页面显示准实时的库存数据,或者其他一些特殊业务场景。这时候你需要保证缓存不能(一直)有脏数据。

缓存的优缺点

缓存优点:

  • 能够缩短服务的响应时间,给用户带来更好的体验。
  • 能够增大系统的吞吐量,依然能够提升用户体验。
  • 减轻数据库的压力,防止高峰期数据库被压垮,导致整个线上服务雪崩。

缓存不足:

  • 缓存有多种选型,是内存缓存,memcache还是redis,你是否都熟悉,如果不熟悉,无疑增加了维护的难度。
  • 缓存系统也要充分考虑分布式,比如redis的分布式缓存还会有很多坑,无疑增加了系统的复杂性
  • 在特殊场景下,如果对缓存的准确性有非常高的要求,就必须考虑缓存和数据库的一致性 。

如何保证缓存的一致性

不更新缓存而是删除缓存

  • 原因一:线程安全角度 同时有请求A和请求B进行更新操作,那么会出现
    a. 请求A更新了数据库
    b. 请求B更新了缓存 c. 请求B更新了缓存 d. 请求A更新了数据库 这样会导致脏数据的产生

  • 原因二:业务场景角度 a. 如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
    b. 如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

       所以得出的结果是采用更新数据的时候删除缓存的做法虽然会导致一次缓存未命中,但是可以避免缓存到脏数据。

删除缓存在更新之前还是之后

第一种情况,在更新之前 a. A请求删除缓存 b. B请求查询数据 c. B请求插入缓存 d. A请求更新数据 这种情况下会导致A更新的结果没有被刷入到缓存中去,那么缓存的结果就是脏数据 第二种情况,在更新之后
a. 缓存刚好失效
b. 请求A查询数据库
c. 请求B将新值写入数据库
d. 请求B删除缓存
e. 请求A将查到的旧值写入缓存
这种情况下当A执行过慢的且缓存刚好失效的时候就会发生 所以先更新数据库再删除缓存依然会出现问题,只不过出现问题的可能性降低

既然放前放后都会出现问题那么应该使用什么样的方法进行处理

  1. 延迟双删 针对先删除后更新的做法,可以是使用延迟双删的策略,即更新数据是先删除缓存,再更新数据库,然后停顿N秒后在删除缓存这样就可以保证删除在另一个请求的查询之后处理。
  2. 延迟删除 针对先更新后删除的做法,可以使用延迟删除的策略,即在更新数据库后延迟N秒删除缓存
    *N > 事务处理的最大时间
    *如果担心吞吐量问题,删除缓存的处理可以放在异步线程内完成。