mysql和redis双写一致性问题
今天阅读了一下关于mysql和redis双写一致性问题的几个回答。整理下自己的理解
首先要先了解什么是一致性
强一致性:写入什么,读取就是什么
弱一致性:写入之后,经过一定时间级别,数据达到一致
最终一致性:弱一致性的特例,在一定时间内达到一致
由于CAP原理即一致性,可用性和分区容错性无法同时满足,在同时使用mysql和redis的情况下,为了保证可用性和分区容错性(mysql和redis可能在不同机器)
所以我们常常会使用BASE来保证最终一致性。
那么如何实现呢
根据操作顺序以及操作缓存的方式,删除还是更新。将情况分成4种
1、先写缓存、再写数据库
2、先写数据库、再写缓存
3、先删缓存,再写数据库
4、先写数据库,再删缓存
1、先写缓存、再写数据库
写入缓存成功,但是写入数据库失败会导致数据库存在脏数据
最终是要用数据库做持久化的,所以这种方式问题很大。
2、先写数据库、再写缓存
为什么使用删除缓存替代更新缓存
1、更新缓存可能失败
2、并发场景下可能存旧数据
3、浪费性能
一、1、A更新数据库。2、A更新缓存。3、B更新数据库。4、B更新缓存
二、1、A更新数据库。2、B更新数据库。3、A更新缓存。4、B更新缓存
三、1、A更新数据库。2、B更新数据库。3、B更新缓存。4、A更新缓存
一、二、更新缓存可能失败
三 缓存存的是旧值是脏数据
写入的缓存需要复杂计算,更新频率太高,浪费性能
读多写少的场景,数据没被读入就更新了。浪费性能。写多场景不需要缓存
所以使用删除缓存来替代更新缓存
3、先删缓存,再写数据库
1、A删除缓存。2、B查询缓存。3、B读数据库更新缓存。4、A写数据库
也是会导致缓存存在脏数据
缓存延时双删
写请求-删除缓存-更新数据库-一段时间后,删除缓存
最后的删除缓存操作是为了确保读请求结束后,写请求可以删除
读请求带来的脏数据
为啥要延时,删除太快,可能导致在写入缓存前删除了,那就没意义了
4、先写数据库、再删缓存
缓存到期被删除后,A查询数据库,来不及更新缓存。B写数据库并删除
缓存。A此时才写入缓存。此时缓存的是旧数据
需要满足缓存到期并且读请求更新缓存时间比写请求删除缓存还长(比较罕见)
处理删除缓存失败
1、重试机制 通过写入表用定时任务重试,重试超过一定次数,人工介入
2、失败后发送mq消息,mq消费者实现重试,重试超过一定次数,进入死信队列。
3、订阅binlog加上mq重试机制
所以一般都使用延时双删的策略配合binlog订阅加mq重试解决一致性问题