优化技术-缓存
缓存
缓存击穿
- 一瞬间的请求压力将缓存击穿,比如指冷门数据突然间变成热门数据。在开始的一瞬间会有大量请求查新数据库,导致数据库压力大;
- 热门数据过期
优化手段:
- 加锁:控制缓存更新的并发访问,防止多个线程同时访问数据库
- 设置空值:对于缓存在没有但是数据库中有的数据,缓存在设置空值;
- 异步加载:查询时实时返回中间值,然后启用异步mq加载数据到缓存;
- 内存预热
缓存穿透
用户访问的数据是不存在的,导致请求数据时,每次都查询数据库加载数据,导致大量请求到数据库加载数据,导致数据库压力大;
优化手段:
- 限制非法请求,对请求的数据进行校验过滤
- 缓存在对没有的数据设置空值,当然这在大量请求攻击时会导致缓存资源耗尽
- 使用布隆过滤器,但是布隆过滤器会有准确率的问题
缓存雪崩
- 缓存在数据在同一时间过期时,这些数据的请求会直接打到数据库,导致数据库压力大\
- 缓存中间件宕机
优化手段:
- 缓存数据过期时间添加随机值,将数据的过期时间打散
- 服务熔断或请求限流机制;
- 构建缓存高可靠集群
多级缓存
- 客户端缓存:如浏览器、APP内部缓存;一致性保证:设置过期时间;请求资源添加版本信息
- CDN分发:一致性保证:请求资源添加版本信息;服务商提供接口刷新
- Nginx缓存:
缓存和数据库的⼀致性问题
想要提高应用的性能,可以引入「缓存」来解决
引入缓存后,需要考虑缓存和数据库一致性问题,可选的方案有:「更新数据库 + 更新缓存」、「更新数据库 + 删除缓存」
更新数据库 + 更新缓存方案,在「并发」场景下无法保证缓存和数据一致性,解决方案是加「分布锁」,但存在「缓存资源浪费」和「机器性能浪费」的情况
采用「先删除缓存,再更新数据库」方案,在「并发」场景下依旧有不一致问题,解决方案是「延迟双删」,但这个延迟时间很难评估
- 延迟双删:先删除缓存,再更新数据库,再删一次缓存。第二次删除不是立即删,而是延迟一定时间后删除,保证DB数据一致后再删
采用「先更新数据库,再删除缓存」方案,为了保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据最终一致
采用「先更新数据库,再删除缓存」方案,「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率
- 性能和一致性不能同时满足,为了性能考虑,通常会采用「最终一致性」的方案
- 掌握缓存和数据库一致性问题,核心问题有 3 点:缓存利用率、并发、缓存 + 数据库一起成功问题
- 失败场景下要保证一致性,常见手段就是「重试」,同步重试会影响吞吐量,所以通常会采用异步重试的方案
- 订阅变更日志的思想,本质是把权威数据源(例如 MySQL)当做 leader 副本,让其它异质系统(例如 Redis / Elasticsearch)成为它的 follower 副本,通过同步变更日志的方式,保证 leader 和 follower 之间保持一致