先抛一下结论:在满足实时性的条件下,不存在两者完全保存一致的方案,只有最终一致性方案 。根据网上的众多解决方案,总结出 6 种,直接看目录:
文章插图
不好的方案
1、先写 MySQL , 再写 redis
文章插图
如图所示:
- 这是一副时序图 , 描述请求的先后调用顺序;
- 橘黄色的线是请求 A,黑色的线是请求 B;
- 橘黄色的文字,是 MySQL 和 Redis 最终不一致的数据;
- 数据是从 10 更新为 11;
- 后面所有的图,都是这个含义,不再赘述 。
这个图已经画得很清晰了,我就不用再去啰嗦了吧,不过这里有个前提 , 就是对于读请求,先去读 Redis,如果没有,再去读 DB,但是读请求不会再回写 Redis 。大白话说一下,就是读请求不会更新 Redis 。
2、先写 Redis,再写 MySQL
文章插图
同“先写 MySQL,再写 Redis”,看图可秒懂 。
3、先删除 Redis , 再写 MySQL
这幅图和上面有些不一样,前面的请求 A 和 B 都是更新请求,这里的请求 A 是更新请求 , 但是请求 B 是读请求,且请求 B 的读请求会回写 Redis 。
文章插图
请求 A 先删除缓存 , 可能因为卡顿,数据一直没有更新到 MySQL,导致两者数据不一致 。
这种情况出现的概率比较大,因为请求 A 更新 MySQL 可能耗时会比较长,而请求 B 的前两步都是查询,会非常快 。
好的方案
1、先删除 Redis,再写 MySQL , 再删除 Redis
对于“先删除 Redis,再写 MySQL” , 如果要解决最后的不一致问题,其实再对 Redis 重新删除即可,这个也是大家常说的“缓存双删” 。
文章插图
为了便于大家看图,对于蓝色的文字,“删除缓存 10”必须在“回写缓存10”后面,那如何才能保证一定是在后面呢?网上给出的第一个方案是,让请求 A 的最后一次删除,等待 500ms 。
对于这种方案,看看就行,反正我是不会用,太 Low 了,风险也不可控 。
那有没有更好的方案?我建议异步串行化删除,即删除请求入队列 。
【直接上最优解:如何保障MySQL和Redis的数据一致性?】
文章插图
异步删除对线上业务无影响,串行化处理保障并发情况下正确删除 。
如果双删失败怎么办,网上有给 Redis 加一个缓存过期时间的方案,这个不敢苟同 。个人建议整个重试机制,可以借助消息队列的重试机制 , 也可以自己整个表,记录重试次数,方法很多 。
简单小结一下:
- “缓存双删”不要用无脑的 sleep 500 ms;
- 通过消息队列的异步&串行,实现最后一次缓存删除;
- 缓存删除失败,增加重试机制 。
文章插图
对于上面这种情况,对于第一次查询,请求 B 查询的数据是 10 , 但是 MySQL 的数据是 11,只存在这一次不一致的情况 , 对于不是强一致性要求的业务,可以容忍 。(什么情况下不能容忍呢 , 比如秒杀业务、库存服务等 。)
当请求 B 进行第二次查询时,因为没有命中 Redis , 会重新查一次 DB,然后再回写到 Reids 。
文章插图
这里需要满足 2 个条件:
- 缓存刚好自动失效;
- 请求 B 从数据库查出 10,回写缓存的耗时,比请求 A 写数据库,并且删除缓存的还长 。
3、先写 MySQL , 通过 Binlog,异步更新 Redis
这种方案,主要是监听 MySQL 的 Binlog,然后通过异步的方式,将数据更新到 Redis,这种方案有个前提 , 查询的请求,不会回写 Redis 。
推荐阅读
- 《南海归墟》闷声干大事,发文官宣好消息,粉丝直呼:终于要上了
- ?李思思被央视辞退,直言不满所给报酬,细节暴露野心难怪被弃用
- 游泳男教练被女粉丝撩,聊天感觉像初恋,直到对方发来吸氧气照片
- 汪峰家庭背景曝光!网友直呼:难怪章子怡铁了心要嫁给他!
- 免拼是什么意思 拼多多买东西直接免拼是什么意思
- 首播6集收视破亿,五星飘屏直指7.9,人气女主出手就是古装热款
- 烤地瓜用锡纸包好还是不包好 锡纸烤红薯和直接烤哪个更好
- 床上找不到虫子但一直被咬 跳蚤是洗衣机也洗不死吗
- 向佐直播被批「妈妈带货失败」气炸情绪失控怒吼:给我滚!
- 锡纸能用火直接加热吗 锡纸能直接放火上吗