关于java:面试官缓存一致性问题怎么解决

2次阅读

共计 1670 个字符,预计需要花费 5 分钟才能阅读完成。

对于 Redis 的其余的一些面试问题曾经写过了,比方常见的缓存穿透、雪崩、击穿、热点的问题,然而还有一个比拟麻烦的问题就是如何保障缓存一致性。

对于缓存和数据库的操作,次要有以下两种形式。

先删缓存,再更新数据库

先删除缓存,数据库还没有更新胜利,此时如果读取缓存,缓存不存在,去数据库中读取到的是旧值,缓存不统一产生。

解决方案

延时双删

延时双删的计划的思路是,为了防止更新数据库的时候,其余线程从缓存中读取不到数据,就在更新完数据库之后,再 sleep 一段时间,而后再次删除缓存。

sleep 的工夫要对业务读写缓存的工夫做出评估,sleep 工夫大于读写缓存的工夫即可。

流程如下:

  1. 线程 1 删除缓存,而后去更新数据库
  2. 线程 2 来读缓存,发现缓存曾经被删除,所以间接从数据库中读取,这时候因为线程 1 还没有更新实现,所以读到的是旧值,而后把旧值写入缓存
  3. 线程 1,依据估算的工夫,sleep,因为 sleep 的工夫大于线程 2 读数据 + 写缓存的工夫,所以缓存被再次删除
  4. 如果还有其余线程来读取缓存的话,就会再次从数据库中读取到最新值

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

如果反过来操作,先更新数据库,再删除缓存呢?

这个就更显著的问题了,更新数据库胜利,如果删除缓存失败或者还没有来得及删除,那么,其余线程从缓存中读取到的就是旧值,还是会产生不统一。

解决方案

音讯队列

这是网上很多文章里都有写过的计划。然而这个计划的缺点会更显著一点。

先更新数据库,胜利后往音讯队列发消息,生产到音讯后再删除缓存,借助音讯队列的重试机制来实现,达到最终一致性的成果。

这个解决方案其实问题更多。

  1. 引入消息中间件之后,问题更简单了,怎么保障音讯不失落更麻烦
  2. 就算更新数据库和删除缓存都没有产生问题,音讯的提早也会带来短暂的不一致性,不过这个提早相对来说还是能够承受的

进阶版音讯队列

为了解决缓存一致性的问题独自引入一个音讯队列,太简单了。

其实,个别大公司自身都会有监听 binlog 音讯的音讯队列存在,次要是为了做一些核查的工作。

这样,咱们能够借助监听 binlog 的音讯队列来做删除缓存的操作。这样做的益处是,不必你本人引入,侵入到你的业务代码中,中间件帮你做理解耦,同时,中间件的这个货色自身就保障了高可用。

当然,这样音讯提早的问题仍然存在,然而相比单纯引入音讯队列的做法更好一点。

而且,如果并发不是特地高的话,这种做法的实时性和一致性都还算能够承受的。

其余解决方案

设置缓存过期工夫

每次放入缓存的时候,设置一个过期工夫,比方 5 分钟,当前的操作只批改数据库,不操作缓存,期待缓存超时后从数据库从新读取。

如果对于一致性要求不是很高的状况,能够采纳这种计划。

这个计划还会有另外一个问题,就是如果数据更新的特地频繁,不一致性的问题就很大了。

在理论生产中,咱们有一些流动的缓存数据是应用这种形式解决的。

因为流动并不频繁产生扭转,而且对于流动来说,短暂的不一致性并不会有什么大的问题。

为什么是删除,而不是更新缓存?

咱们以 先更新数据库,再删除缓存 来举例。

如果是更新的话,那就是 先更新数据库,再更新缓存

举个例子:如果数据库 1 小时内更新了 1000 次,那么缓存也要更新 1000 次,然而这个缓存可能在 1 小时内只被读取了 1 次,那么这 1000 次的更新有必要吗?

反过来,如果是删除的话,就算数据库更新了 1000 次,那么也只是做了 1 次缓存删除,只有当缓存真正被读取的时候才去数据库加载。

总结

首先,咱们要明确一点,缓存不是更新,而应该是删除。

删除缓存有两种形式:

  1. 先删除缓存,再更新数据库。解决方案是应用提早双删。
  2. 先更新数据库,再删除缓存。解决方案是音讯队列或者其余 binlog 同步,引入音讯队列会带来更多的问题,并不举荐间接应用。

针对缓存一致性要求不是很高的场景,那么只通过设置超时工夫就能够了。

其实,如果不是很高的并发,无论你抉择先删缓存还是后删缓存的形式,都简直很少能产生这种问题,然而在高并发下,你应该晓得怎么解决问题。

微信搜寻公众号【艾小仙】回复【PDF】获取百本计算机电子书,文章每周继续更新。我是艾小仙,阿里巴巴技术专家,咱们下期见!

  • END –
正文完
 0