优化技术-缓存

缓存

缓存击穿

  1. 一瞬间的请求压力将缓存击穿,比如指冷门数据突然间变成热门数据。在开始的一瞬间会有大量请求查新数据库,导致数据库压力大;
  2. 热门数据过期

优化手段:

  • 加锁:控制缓存更新的并发访问,防止多个线程同时访问数据库
  • 设置空值:对于缓存在没有但是数据库中有的数据,缓存在设置空值;
  • 异步加载:查询时实时返回中间值,然后启用异步mq加载数据到缓存;
  • 内存预热

缓存穿透

用户访问的数据是不存在的,导致请求数据时,每次都查询数据库加载数据,导致大量请求到数据库加载数据,导致数据库压力大;

优化手段:

  • 限制非法请求,对请求的数据进行校验过滤
  • 缓存在对没有的数据设置空值,当然这在大量请求攻击时会导致缓存资源耗尽
  • 使用布隆过滤器,但是布隆过滤器会有准确率的问题

缓存雪崩

  1. 缓存在数据在同一时间过期时,这些数据的请求会直接打到数据库,导致数据库压力大\
  2. 缓存中间件宕机

优化手段:

  • 缓存数据过期时间添加随机值,将数据的过期时间打散
  • 服务熔断或请求限流机制;
  • 构建缓存高可靠集群

多级缓存

  • 客户端缓存:如浏览器、APP内部缓存;一致性保证:设置过期时间;请求资源添加版本信息
  • CDN分发:一致性保证:请求资源添加版本信息;服务商提供接口刷新
  • Nginx缓存:

缓存和数据库的⼀致性问题

  1. 想要提高应用的性能,可以引入「缓存」来解决

  2. 引入缓存后,需要考虑缓存和数据库一致性问题,可选的方案有:「更新数据库 + 更新缓存」、「更新数据库 + 删除缓存」

  3. 更新数据库 + 更新缓存方案,在「并发」场景下无法保证缓存和数据一致性,解决方案是加「分布锁」,但存在「缓存资源浪费」和「机器性能浪费」的情况

  4. 采用「先删除缓存,再更新数据库」方案,在「并发」场景下依旧有不一致问题,解决方案是「延迟双删」,但这个延迟时间很难评估

    • 延迟双删:先删除缓存,再更新数据库,再删一次缓存。第二次删除不是立即删,而是延迟一定时间后删除,保证DB数据一致后再删
  5. 采用「先更新数据库,再删除缓存」方案,为了保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据最终一致

  6. 采用「先更新数据库,再删除缓存」方案,「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率

  • 性能和一致性不能同时满足,为了性能考虑,通常会采用「最终一致性」的方案
  • 掌握缓存和数据库一致性问题,核心问题有 3 点:缓存利用率并发缓存 + 数据库一起成功问题
  • 失败场景下要保证一致性,常见手段就是「重试」,同步重试会影响吞吐量,所以通常会采用异步重试的方案
  • 订阅变更日志的思想,本质是把权威数据源(例如 MySQL)当做 leader 副本,让其它异质系统(例如 Redis / Elasticsearch)成为它的 follower 副本,通过同步变更日志的方式,保证 leader 和 follower 之间保持一致