关于java:如何保证-Redis-缓存与数据库双写一致性

37次阅读

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

作者:不学有数的程序员 \
链接:https://www.jianshu.com/p/a8e…

在做系统优化时,想到了将数据进行分级存储的思路。因为在零碎中会存在一些数据,有些数据的实时性要求不高,比方一些配置信息。

基本上配置了很久才会变一次。而有一些数据实时性要求十分高,比方订单和流水的数据。所以这里依据数据要求实时性不同将数据分为三级。

  • 第 1 级:订单数据和领取流水数据;这两块数据对实时性和精确性要求很高,所以不增加任何缓存,读写操作将间接操作数据库。
  • 第 2 级:用户相干数据;这些数据和用户相干,具备读多写少的特色,所以咱们应用 redis 进行缓存。
  • 第 3 级:领取配置信息;这些数据和用户无关,具备数据量小,频繁读,简直不批改的特色,所以咱们应用本地内存进行缓存。

然而只有应用到缓存,无论是本地内存做缓存还是应用 redis 做缓存,那么就会存在数据同步的问题,因为配置信息缓存在内存中,而内存时无奈感知到数据在数据库的批改。这样就会造成数据库中的数据与缓存中数据不统一的问题。

接下来就讨论一下对于保障缓存和数据库双写时的数据一致性。

解决方案

那么咱们这里列出来所有策略,并且探讨他们优劣性。

  1. 先更新数据库,后更新缓存
  2. 先更新数据库,后删除缓存
  3. 先更新缓存,后更新数据库
  4. 先删除缓存,后更新数据库

先更新数据库,后更新缓存

这种场景个别是没有人应用的,次要起因是在更新缓存那一步,为什么呢?因为有的业务需要缓存中存在的值并不是间接从数据库中查出来的,有的是须要通过一系列计算来的缓存值,那么这时候后你要更新缓存的话其实代价是很高的。如果此时有大量的对数据库进行写数据的申请,然而读申请并不多,那么此时如果每次写申请都更新一下缓存,那么性能损耗是十分大的。

举个例子比方在数据库中有一个值为 1 的值,此时咱们有 10 个申请对其每次加一的操作,然而这期间并没有读操作进来,如果用了先更新数据库的方法,那么此时就会有十个申请对缓存进行更新,会有大量的冷数据产生,如果咱们不更新缓存而是删除缓存,那么在有读申请来的时候那么就会只更新缓存一次。

先更新缓存,后更新数据库

这一种状况应该不须要咱们思考了吧,和第一种状况是一样的。

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

该计划也会出问题,具体呈现的起因如下。

此时来了两个申请,申请 A(更新操作)和申请 B(查问操作)

  1. 申请 A 会先删除 Redis 中的数据,而后去数据库进行更新操作
  2. 此时申请 B 看到 Redis 中的数据时空的,会去数据库中查问该值,补录到 Redis 中
  3. 然而此时申请 A 并没有更新胜利,或者事务还未提交

那么这时候就会产生数据库和 Redis 数据不统一的问题。如何解决呢?其实最简略的解决办法就是延时双删的策略。

然而上述的保障事务提交完当前再进行删除缓存还有一个问题,就是如果你应用的是 Mysql 的读写拆散的架构的话,那么其实主从同步之间也会有时间差。

此时来了两个申请,申请 A(更新操作)和申请 B(查问操作)

  1. 申请 A 更新操作,删除了 Redis
  2. 申请主库进行更新操作,主库与从库进行同步数据的操作
  3. 请 B 查问操作,发现 Redis 中没有数据
  4. 去从库中拿去数据
  5. 此时同步数据还未实现,拿到的数据是旧数据

此时的解决办法就是如果是对 Redis 进行填充数据的查询数据库操作,那么就强制将其指向主库进行查问。

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

问题:这一种状况也会呈现问题,比方更新数据库胜利了,然而在删除缓存的阶段出错了没有删除胜利,那么此时再读取缓存的时候每次都是谬误的数据了。

此时解决方案就是利用音讯队列进行删除的弥补。具体的业务逻辑用语言形容如下:

  1. 申请 A 先对数据库进行更新操作
  2. 在对 Redis 进行删除操作的时候发现报错,删除失败
  3. 此时将 Redis 的 key 作为音讯体发送到音讯队列中
  4. 零碎接管到音讯队列发送的音讯后再次对 Redis 进行删除操作

然而这个计划会有一个毛病就是会对业务代码造成大量的侵入,深深的耦合在一起,所以这时会有一个优化的计划,咱们晓得对 Mysql 数据库更新操作后再 binlog 日志中咱们都可能找到相应的操作,那么咱们能够订阅 Mysql 数据库的 binlog 日志对缓存进行操作。

总结

每种计划各有利弊,比方在第二种先删除缓存,后更新数据库这个计划咱们最初探讨了要更新 Redis 的时候强制走主库查问就能解决问题,那么这样的操作会对业务代码进行大量的侵入,然而不须要减少的零碎,不须要减少整体的服务的复杂度。

最初一种计划咱们最初探讨了利用订阅 binlog 日志进行搭建独立零碎操作 Redis,这样的毛病其实就是减少了零碎复杂度。其实每一次的抉择都须要咱们对于咱们的业务进行评估来抉择,没有一种技术是对于所有业务都通用的。没有最好的,只有最适宜咱们的。

近期热文举荐:

1.Java 15 正式公布,14 个新个性,刷新你的认知!!

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 我用 Java 8 写了一段逻辑,共事直呼看不懂,你试试看。。

4. 吊打 Tomcat,Undertow 性能很炸!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0