面试官问我缓存一致性

面试官问我缓存一致性

当面试官问到缓存一致性的时候,第一想到的总是强一致性,经过不断的查阅资料发现,有两种一致性方案,一种是最终一致性,一种是强一致性,重要是在一致性和性能之前做平衡,中间是一个模糊的灰色地带。

所谓最终一致性即最后落到数据库上面的时候是正确的即可,可以牺牲一定的用户体验来提高用户的性能,比如用户看到的库存可能是几秒前的库存;所谓强一致性,即能查到的数据一定是最新的,保证这样的强一致性,也要承担更多的性能损失。

查询操作

如果仅对数据库有读操作的话,那么势必不用考虑缓存一致性,引入缓存加可以大大加快查询速率。

面试官问我缓存一致性_第1张图片

更新时的缓存一致性

那如果加入更新操作了,就要思考是先更新或删除缓存,还是先更新数据库,以及如何保证两者的一致性了。

先验条件:读数据库要比写数据库快的多

  1. 首先先看更新缓存的操作,因为如果两个线程同时进行操作,那么两个线程更新数据库或者更新缓存的操作的先后顺序无法确定,大概率导致缓存不一致。当然可以采用加锁的方式,对更新缓存的过程加锁,保证同时只有一个线程更新缓存。

  2. 采用先删除缓存策略。会有较大概率发生数据不一致问题,并且影响较大。此时线程A更新数据,先删掉缓存,去更新数据库,还没更新结束呢,线程B来读,发现缓存不存在,就会读出数据库的旧值,并且更新缓存成旧值,如果很多后面都是读请求, 那么读的都是旧值,影响较大。有一种解决方案是,更新完数据库之后,等待一会再删一次,叫延迟双删。

  3. 采用后删除缓存策略。旁路缓存策略是说先更新数据库,在删除缓存。这样会在更新数据库的时候,如果有请求读缓存,也可能会有不一致性。不过当更新数据库操作完成时,会设置缓存失效,后续的请求读的都是新值。不过采用旁路缓存策略会发生:

    1. 某个时刻缓存没有数据,来了个更新请求A,更新数据库,此时有个读请求B读到了旧值,但是他等到更新请求 A 执行完了,删除完缓存了,读请求B才更新缓存,导致缓存里面是旧值,后续读请求都会读到旧值。不过这种情况发生概率极低,因为数据库读操作快于写操作。
    2. 删除缓存可能会失败。可以加上一定的重试机制,如果重试几次都不成功,那可能是缓存服务挂了。那么后续读请求也都会到数据库上面,数据还是一致的。

所以在不同的业务场景下,需要的一致性要求也是不一样的,要根据具体场景进行设计。另外一些常见的招式有:

  1. 给缓存设置过期时间
  2. Write Behind 思想
  3. 引入消息队列

参考文章:

缓存更新的套路 | 酷 壳 - CoolShell

更新数据时,是先删除缓存再更新DB,还是先更新DB再删除缓存?

你可能感兴趣的:(缓存,java,redis)