Redis和数据库数据不一致该怎么做?
答:
情景:redis作为缓存,当我们修改数据库的数据的时候,会出现Mysql和redis的数据不一致的问题
如图,当修改更新MYSQL数据为9后,还没来得及取更新redis,这时候取查询redis为10,出现数据不一致的问题。
- 解决方案
- 先更新数据库,再更新缓存。。。(这种方式是不行的,还是会出现上述的问题)
- 先删除缓存,再更新数据库。
还是会出现数据不一致的情况,当删除了redis,还没来得及写入mysql时,这时候查询redis没有从数据库获取并写入redis为10,之后才更新的数据库9,还是出现不一致的情况。 - (缓存延时双删):先删除缓存,再更新数据库,再延迟删除缓存
为什么要延时?第一次删除缓存之后,更新数据库之前,他查询了数据库,如果他查询返回的时间比较久,导致回写redis时候是在第二次删除缓存之后,那么第二次删除缓存就没有意义,删除了空。最后回写的是更新前的数据,导致删不掉。所以我们延时的目的是要保证在构建缓存操作完毕后再去删除。
缺点:因为有延时操作,会造成服务器阻塞,不适合高并发,不能达到最大的吞吐性能。 - 最终一致性(redis和mysql现在不一致,但是要求过一会和最终要一致)
先更新mysql,然后删除redis里面的缓存,要注意的是确保redis一定要删除成功,利用消息队列的重试+手动确认的机制来删除redis的数据,如果删除redis缓存失败的情况下,再发送一个消息到mq,然后再写个程序去消费mq里面的消息,只要我删除成功就确认,没有删除成功就利用消息队列的重试机制,不断的删除,直到删除成功为止。。问题:对程序的耦合性比较高,修改和新增接口,每一个方法里面都要加发消息的操作,很麻烦。
有一种低耦合的解决方案,就是canal,原理是把自己伪装成mysql的从机,然后不断的去监听mysql的二进制日志文件,当我们数据发生变化的时候,他会主动的给我们的mq发送一个消息,所以就不用在每个修改新增方法的代码里面将发消息的代码写出来了,这个操作就交给canal去实现了