改进延时双删的一些思考
延时双删的问题
延时双删也不能保证完全数据一致——第二次删除失败就可能不一致了。
我思考了一个方法可以保证始终数据一致。
改进方法
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 新增Redis 键 useCacheFlag = 1;
- 查询时,先查useCacheFlag,如果为 1,则查询缓存。否则查询 DB。如果useCacheFlag = 1,不更新缓存。
更新数据过程
-
在一个Redis事务中:删除缓存,并set useCacheFlag = 0。事务成功才下一步,否则一直重试。
-
修改 DB,在修改完成前,缓存都一直为空。此时查询全部走 DB,且useCacheFlag = 0时,不更新到缓存。即使 DB 更新失败也没关系,重试。
-
在一个 Redis 事务中,更新缓存,再设置useCacheFlag = 1。事务不成功一直重试。
整个过程 DB 和缓存数据都是一致的,不管更新 DB 失败,还是Redis 事务失败,数据都是始终一致的。Redis 事务失败可能只执行部分。且不会回滚。
异常情况
最坏的情况,应用服务器和 Redis服务器都可能宕机。
Redis 宕机,只可能导致查数据库,或一直重试,没问题。
应用如果宕机,在 1,2步完成之前宕机,都没关系。如果第二部完成了宕机,会导致一直查数据库,而缓存作废了,因为useCacheFlag = 0。
解决方法:
新增 Redis 变量 queryTime 记录数据库查询的时间
在查询数据库时,如果queryTime ==null,set Redis 变量 queryTime=本次查询的时间。
如果queryTime 不为空,就不更新queryTime。
比较 queryTime 和 当前时间,超过 3 分钟(根据业务时间调整),认为缓存废弃已经时间过长,重新开始使用缓存:
此时 在一个Redis 事务中
1、先更新 DB 查询值到缓存
2、set useCacheFlag = 1
3、并清空queryTime
如果失败,重试
以上思路如果问题,请帮忙指出!感谢!