基本概念
-
缓存导致的异常问题
- 缓存中数据不一致
- 缓存雪崩
- 缓存击穿
- 缓存穿透
为什么缓存与数据库不一致
-
一致性
- 缓存中有数据,且缓存数据和数据库数据相同
- 缓存中没有数据,数据库必须为最新值
-
根据是否接受写请求缓存分类
- 读写缓存
- 只读缓存
-
针对读写缓存 保证数据一致性需要将数据写回数据库
-
同步直写策略:写缓存时同步到数据库,保证数据一致
- 但是需要用事务保证两边都更新成功,或者两边都更新失败,否则数据还是不一致的
-
异步写回策略:等数据淘汰写回数据库
-
-
针对只读数据
-
基本概念:数据更新时,将缓存删除即可,下次读数据回写到缓存中
-
场景
-
新增数据:缓存中没有数据,数据是一致的
-
删改数据:需要保证缓存的删除和数据库的更新操作是原子的,否则会导致数据不一致\
- 删除缓存,更新数据库:缓存删除成功,数据库更新失败 返回的仍然是旧值
- 先更新数据,后更新缓存:缓存未删除掉,读到仍然是旧数据
-
-
针对只读缓存的情况
如何解决不一致
-
重试机制
- 删除的缓存或者更新的数据库只缓存到消息队列中,例如kafka,删除失败时再次重新删除
- 如果删除成功则从消息队列中去除,避免重复操作
- 失败则重试,超出重试次数后发出警报
-
先删除缓存,再更新数据库
- 问题:如果更新操作未结束,会导致将旧数据读会缓存中
- 解决办法:更新操作结束后,sleep一下删除缓存,保证b线程的数据写入缓存后再删除掉 (数据双删)
-
先更新数据库,再删除缓存
- 可能会读取到旧值,删除操作很快,不会影响
总结
-
解决方案
- 删除和更新失败可以使用消息队列进行重试
- 对于删除过程中的读操作读取旧值,可以采取延时双删
-
大部分场景下都是只读缓存,不涉及更新数据操作(尽量使用更新数据库后删除缓存)
- 先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力(即使脏数据,也读缓存)
- 双删的延迟时间不好估算
\