大前提
- 如果要求强一致性,就不要使用redis,使用redis代表可以接受最终一致性
- 使用redis作为缓存,必须设置过期时间,原因: 即使程序有问题,不能保证redis的最终一致性,key也会自己失效
保证redis与mysql数据最终一致性,有以下几种方案
方案一
先更新redis,再更新mysql
流程图
最后mysql是请求1的数据,redis是请求2的数据,不能保证最终一致性
方案二
先更新mysql,再更新redis
流程图
最后mysql是请求2的数据,redis是请求1的数据,不能保证最终一致性
方案三
先删redis,再更新mysql
流程图
最后mysql是新数据,redis是旧数据,不能保证最终一致性
方案四
先更新mysql,再删redis
流程图
最后mysql是新数据,redis是旧数据
方案五
延迟删除: 先更新mysql,然后sleep一段时间,再删除redis
流程图
sleep时间,由业务侧决定,最好是大于查询接口的耗时。
方案六
方案五的问题是: 更新mysql后,删除redis之前,查询请求从redis查到的是旧数据,虽然可以保证最终一致性,但是查到旧数据的时间较长。
基于方案五的问题,方案六提出了延迟双删: 先删redis,然后更新mysql,然后sleep一段时间,再删除redis。
本方案可以让用户更早查询到新数据。
方案六看起来是所有方案中最优的,但其实还是有问题,比如下面的情况(出现概率极低),如果确实发生了这种情况,只能等key到达过期时间自己失效,或者引入mq等中间件对删除redis失败做重试。
最后,友情提示一下,这个问题是面试高频题,但是面试没法画图,很难描述清楚各种场景,可以用下面的表达方式
请求1: 更新redis--------------------------------------更新mysql
请求2: -------------更新redis--------------更新mysql
最后redis是请求2的数据,mysql是请求1的数据