缓存异常
缓存一致性问题
只要是缓存都会存在这种问题,数据库与缓存之间同步的问题,这里主要有四种情况,每种情况会具体分析其存在的问题,可以根据业务情况选择使用。
先更新数据库,后更新缓存
问题: 在并发访问的情况下,会将脏数据刷新到缓存中。(应该没人使用)
先更新缓存,后更新数据库
问题: 如果更新缓存成功,但是数据库更新失败则会导致数据不一致问题。(应该没人使用)
先删除缓存,后更新数据库
改方案也会出现问题,此时来个两个请求,请求A 更新操作;请求B 查询操作。
- 请求A进行写操作,删除缓存
- 请求B查询操作发现缓存不存在
- 请求B去数据库可查询得到旧值
- 请求B将旧值写入到缓存
- 请求A将新值写入数据库
删除情况导致不一值的问题出现,如果不采用给缓存设置过期策略,那么改缓存中永远都是脏数据。
解决方案:
- 延迟双删除: 在更新数据库后间隔1s再次删除缓存,那么可以将1s内的脏数据清除。
先更新数据库,后删除缓存
这种情况下,如果更新数据库成功了,但是在删除缓存阶段出错没有删除成功,那么此时在读取缓存的时候每次都是错误的数据。
解决方式:
- 删除补偿:针对删除Redis删除失败的情况,将key作为消息发送到消息队列中,进行删除补偿。
缓存雪崩
概念:
指缓存中大量的数据失效,导致大量请求直接访问数据库,造成数据库压力过大。通常是由于缓存中大量的数据在同一时间失效,导致大量请求直接访问数据库。
解决方式:
- 可以采用多级缓存架构,减少缓存层的压力
- 或者设置热点数据的过期时间为随机时间,避免在同一时间大量数据同时失效(常用方式)
- 另外可以在缓存层和数据库层之间添加限流、熔断等措施
- 避免因突发流量导致系统崩溃
缓存击穿
概念:
指缓存中某个热点数据失效,此时有大量并发请求同时访问这个失效的数据,导致这些请求直接访问数据库,造成数据库压力过大,甚至导致数据库崩溃。
通常是由于缓存中某个热点数据过期失效,同时有大量并发请求访问该数据。
解决方式:
- 可以使用锁机制或者分布式锁机制,避免大量并发请求同时访问失效的热点数据
- 或者不设置TTL,设置逻辑上过期标识,需要过期的时候直接删除标识
缓存穿透
概念:
指查询一个不存在的数据,由于缓存中没有数据,所以这个查询请求会直接穿过缓存层,到达数据库层,造成了数据库的压力。
攻击者可以通过构造恶意请求,使得缓存层无法命中任何数据,从而导致请求直接访问数据库,从而引起数据库压力过大。
解决方式:
- 可以在查询缓存之前,先对请求的参数进行合法性检查,如过滤非法字符、判断参数范围等
- 或者使用BloomFilter等数据结构,对查询参数进行过滤,只有在BloomFilter中判断有可能存在的情况下才会去查询数据库。