先更数据库,再删除缓存
问题
缓存删除后,尚未更新数据库,并发读请求,从数据库读到了旧值,并且更新到缓存导致后续请求都是旧值。
| 时间 从上 到下, 越来 越晚 |
更新操作 |
|
| 删除redis |
读取操作 |
| |
缓存没有数据 |
| |
从数据库读到旧值 |
| |
回写redis |
| 更新mysql |
返回 |
| 返回 |
|
解决方式
经典的延迟双删。就是:先更新数据线,再删缓存,之后延迟一段时间再删缓存。
| 时间 从上 到下, 越来 越晚 |
更新操作 |
|
| 删除redis |
读取操作 |
| |
缓存没有数据 |
| |
从数据库读到旧值 |
| |
回写redis |
| 更新mysql |
返回 |
| 延迟一段时间 |
|
| |
|
| 删除redis |
|
| |
读取操作 |
| |
缓存没有数据 |
| |
从数据库读到新值 |
| |
回写redis |
| |
返回 |
延迟一段时间,挺重要不能拍脑袋,需要考虑2个因素
考虑查询接口响应时间
| 时间 从上 到下, 越来 越晚 |
更新操作 |
|
| 删除redis |
读取操作 |
| |
缓存没有数据 |
| |
从数据库读到旧值 |
| 更新mysql |
|
| 延迟一段时间, 小于从数据读取数据的时间, 延迟策略失效 |
|
| 删除redis |
|
| |
回写redis |
| |
返回 |
考虑mysql主从同步事件
自建mysql集群,配置不当,会出现mysql主从同步延迟大的情况。
| 时间 从上 到下, 越来 越晚 |
更新操作 |
|
| 删除redis |
读取操作 |
| |
缓存没有数据 |
| |
从数据库读到旧值 |
| |
回写redis |
| 更新mysql主库 |
返回 |
| 延迟一段时间, 小于mysql主从同步时间 延迟策略失效 |
|
| |
|
| 删除redis |
读取操作 |
| |
缓存没有数据 |
| |
从库读到旧值 |
| mysql主从同步完成 |
回写redis |
| |
返回 |
延迟时间必须大于查询接口的响应时间。
并且要大于mysql主从同步的时间,防止主从同步延迟造成,读到旧值的情况
--- 温安适 20210225
先删缓存,再更新数据库
注意:建议查询接口要从主库进行读取
| 时间 从上 到下, 越来 越晚 |
更新操作 |
|
| 更新mysql主库 |
读取操作 |
| |
缓存有数据,读到旧值 |
| 删除redis |
返回 |
| |
|
| |
读取操作 |
| |
缓存没有数据 |
| |
主库读到新值 |
| |
回写redis |
| |
返回 |
存在的问题:
等待缓存删除完成,期间数据库会有不一致数据短暂存在,但是一般可以不处理。
总结:
| 策略 |
潜在问题 |
解决方式 |
注意事项 |
| 先删缓存, 再更数据库 |
并发条件下 数据库更新还没有完成 有并发读请求,从数据库读到了旧值 |
延迟双删 |
延迟时间必须 大于查询接口的响应时间。 并且大于mysql主从同步的时间 |
| 先更数据库, 再删缓存 |
并发条件下 缓存没有删除完成,并发读 从缓存读到了旧值 |
不处理, 最终会一致 |
查询接口建议读主库,存在不一致, 但是一般不需处理 |