问题分析:
当MySQL中的数据发生更新时,就面临一个问题,如何确保MySQL与Redis数据的一致性,我们有两个选择:
- 先更新MySQL,后删除(或更新)Redis
- 先删除(或更新)Redis,后更新MySQL
但是不管使用其中哪种方式,都存在两个可能的问题:
- 由于第一步与第二步并不是原子的,中间会存在较短的时间间隔,如果间隔时间内有请求到达,就可能会访问到不一致的数据。
- 可能存在做完第一步,第二步还没来得及做,系统就发生异常的情况;这就会导致MySQL与Redis的数据不一致。
解决方案:
1、最终一致性:容忍数据短时不一致,最终达到一致即可
可以采用先删除Redis,后更新MySQL的方式来保证最终一致性。
- 删除Redis
- 在这时有请求到达,读取MySQL内容并写入Redis(此时写入的数据是旧的)
- 更新MySQL
- 删除Redis(再执行一次删除Redis,就可以确保Redis中的内容为最新数据)
但是上述的保证事务提交完以后再进行删除缓存还有一个问题,就是如果你使用的是 Mysql 的读写分离的架构的话,那么其实主从同步之间也会有时间差。
此时来了两个请求,请求 A(更新操作) 和请求 B(查询操作)
- 请求 A 更新操作,删除了 Redis
- 请求主库进行更新操作,主库与从库进行同步数据的操作
- 请 B 查询操作,发现 Redis 中没有数据
- 去从库中拿去数据
- 此时同步数据还未完成,拿到的数据是旧数据
此时的解决办法就是如果是对 Redis 进行填充数据的查询数据库操作,那么就强制将其指向主库进行查询。
2、强一致性:数据实时保持一致
先更新数据库,后删除缓存
问题:更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了。
此时解决方案就是利用消息队列进行删除的补偿。
具体的业务逻辑用语言描述如下:
- 请求 A 先对数据库进行更新操作
- 在对 Redis 进行删除操作的时候发现报错,删除失败
- 此时将Redis 的 key 作为消息体发送到消息队列中
- 系统接收到消息队列发送的消息后再次对 Redis 进行删除操作
但是这个方案会有一个缺点就是会对业务代码造成大量的侵入,深深的耦合在一起。
所以这时会有一个优化的方案,引入第三方服务,订阅(监听)MySQL master节点的binlog,当binlog产生时,按binlog顺序更新Redis数据即可。比如阿里开源的canal组件。
个人认为这里实现的【强一致性】也并不是真的【实时一致】,而是【近实时】,因为读取binlog并在Redis上执行更新,依然需要时间,只是这个时间会比较短而已。
标签:删除,数据,Mysql,Redis,更新,MySQL,一致性,保证数据 From: https://www.cnblogs.com/zhaojinhui/p/16931940.html