参考地址redis延时双删第一个删除是为了什么? - 知乎
https://www.ngui.cc/el/3080262.html?action=onClick
可能有两种方案:
1.先删缓存,后更新数据库
2.先更新数据库,后删缓存
第1种的缺陷:删了缓存,另一个请求来查,发现缓存为空,查到旧数据保存到缓存中。
第2种的缺陷:从更新数据库到删缓存的时间内,查询到的缓存为旧数据,也就是造成查询延迟。
其实第二种是可以接受的。不过有一种少见的极端情况,即缓存到期,读请求先来然后延迟,导致写入旧数据。
至于为什么不是先更新数据再更新缓存。因为更新缓存可能因为线程切换等延迟导致旧请求的数据覆盖新数据。而且每次都更新缓存可能导致浪费资源。 先更新缓存再更新数据就更不可以了。因为可能导致更新数据库失败回滚,但缓存没办法回滚。
延迟双删
为了解决这两种方案的缺陷,可以使用延迟双删,即先进行缓存清除,再执行update,最后(延迟N秒)再执行缓存清除。进行两次删除,且中间需要延迟一段时间。
延迟删就是为了解决方案1的缺陷,即其他请求查到了旧数据,并写入缓存。本请求要等其写完缓存后再删除掉它。因此延迟时间应该大于该写入请求的时间。
删缓存失败
重试机制
可以将删除失败的缓存写入重试表,用定时任务如elastic-job定时重试。
可以将删除失败的缓存发到mq,由消费者进行重试。
订阅binlog
这种方案可以不在业务中关心缓存处理,而是直接订阅mysql的binlog日志,发现有数据更新,就删除对应缓存。可以使用canal中间件订阅。当然也要加上重试机制。