(转)面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题

背景:redis问题在面试过程当中常常被问到,对于常见问题必定不能放过。面试

面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题redis

1、缓存雪崩

1.1什么是缓存雪崩?

若是缓存数据设置的过时时间是相同的,而且Redis刚好将这部分数据所有删光了。这就会致使在这段时间内,这些缓存同时失效,所有请求到数据库中数据库

这就是缓存雪崩设计模式

  • Redis挂掉了,请求所有走数据库。缓存

  • 对缓存数据设置相同的过时时间,致使某段时间内缓存失效,请求所有走数据库。架构

缓存雪崩若是发生了,极可能就把咱们的数据库搞垮,致使整个服务瘫痪!并发

1.2如何解决缓存雪崩?

对于“对缓存数据设置相同的过时时间,致使某段时间内缓存失效,请求所有走数据库。”这种状况,很是好解决:ide

  • 解决方法:在缓存的时候给过时时间加上一个随机值,这样就会大幅度的减小缓存在同一时间过时高并发

对于“Redis挂掉了,请求所有走数据库”这种状况,咱们能够有如下的思路:spa

  • 事发前:实现Redis的高可用(主从架构+Sentinel 或者Redis Cluster),尽可能避免Redis挂掉这种状况发生。

  • 事发中:万一Redis真的挂了,咱们能够设置本地缓存(ehcache)+限流(hystrix),尽可能避免咱们的数据库被干掉(起码能保证咱们的服务仍是能正常工做的)

  • 事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据

2、缓存穿透

2.1什么是缓存穿透

缓存穿透是指查询一个必定不存在的数据。因为缓存不命中,而且出于容错考虑,若是从数据库查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到数据库去查询,失去了缓存的意义。

这就是缓存穿透

  • 请求的数据在缓存大量不命中,致使请求走数据库。

缓存穿透若是发生了,也可能把咱们的数据库搞垮,致使整个服务瘫痪!

2.1如何解决缓存穿透?

解决缓存穿透也有两种方案:

  • 因为请求的参数是不合法的(每次都请求不存在的参数),因而咱们可使用布隆过滤器(BloomFilter)或者压缩filter提早拦截,不合法就不让这个请求到数据库层!

  • 当咱们从数据库找不到的时候,咱们也将这个空对象设置到缓存里边去。下次再请求的时候,就能够从缓存里边获取了。

  • 这种状况咱们通常会将空对象设置一个较短的过时时间

3、缓存与数据库双写一致

3.1对于读操做,流程是这样的

上面讲缓存穿透的时候也提到了:若是从数据库查不到数据则不写入缓存。

通常咱们对读操做的时候有这么一个固定的套路

  • 若是咱们的数据在缓存里边有,那么就直接取缓存的。

  • 若是缓存里没有咱们想要的数据,咱们会先去查询数据库,而后将数据库查出来的数据写到缓存中

  • 最后将数据返回给请求

3.2什么是缓存与数据库双写一致问题?

若是仅仅查询的话,缓存的数据和数据库的数据是没问题的。可是,当咱们要更新时候呢?各类状况极可能就形成数据库和缓存的数据不一致了。

  • 这里不一致指的是:数据库的数据跟缓存的数据不一致

删除缓存失败的解决思路

  • 将须要删除的key发送到消息队列中

  • 本身消费消息,得到须要删除的key

  • 不断重试删除操做,直到成功

3.3.3先删除缓存,再更新数据库

正常状况是这样的:

  • 先删除缓存,成功;

  • 再更新数据库,也成功;

若是原子性被破坏了:

  • 第一步成功(删除缓存),第二步失败(更新数据库),数据库和缓存的数据仍是一致的。

  • 若是第一步(删除缓存)就失败了,咱们能够直接返回错误(Exception),数据库和缓存的数据仍是一致的。

看起来是很美好,可是咱们在并发场景下分析一下,就知道仍是有问题的了:

  • 线程A删除了缓存

  • 线程B查询,发现缓存已不存在

  • 线程B去数据库查询获得旧值

  • 线程B将旧值写入缓存

  • 线程A将新值写入数据库

因此也会致使数据库和缓存不一致的问题。

并发下解决数据库与缓存不一致的思路

  • 将删除缓存、修改数据库、读取缓存等的操做积压到队列里边,实现串行化

3.4对比两种策略

咱们能够发现,两种策略各自有优缺点:

  • 先删除缓存,再更新数据库

  • 在高并发下表现不如意,在原子性被破坏时表现优异

  • 先更新数据库,再删除缓存(Cache Aside Pattern设计模式)

  • 在高并发下表现优异,在原子性被破坏时表现不如意#总结

相关文章
相关标签/搜索