读不尽天下之书
需要解决的问题点
1. 分布式缓存同步
问题:
- 在高并发的场景下,如何保证分布式场景下各个节点中本地缓存的一致性问题?
解决思路:
- 同步的目的是为了尽可能保证分布式缓存的一致性。通过
发布订阅功能
来实现分布式缓存下不同节点的缓存同步。 - 数据变更通知 + 定期刷新过期缓存的策略,尽可能的保证缓存的一致性。可以通过
Redis
+Kafka
的发布订阅功能实现。 - 框架留好扩展点,可以快速便捷的扩展其他 MQ 来实现缓存同步。
- 使用缓存,必定会存在不一致的情况,无法保证强一致性。
2. 缓存更新
问题:
- 缓存更新包含了
本地缓存
以及Redis
的操作,同时通知其他缓存节点进行缓存更新
操作;
解决思路:
- 主动更新
- 获取缓存时,若缓存不存在或缓存已过期,则重新加载缓存;
- 源数据变更后,调用
缓存刷新
接口重新加载缓存(此时只对已存在的 key 重新加载)
- 自动更新
- 定期刷新过期缓存,尽可能保证分布式缓存的一致性;
3. 缓存淘汰
问题:
- 通知其他缓存节点进行
缓存淘汰
解决思路:
- 主动淘汰
- 获取缓存时,检查缓存是否过期,如果过期则淘汰缓存;
- 结合
@CacheEvict
在源数据修改前或修改后,淘汰缓存; - 数据源变更后,调用刷新缓存接口,进行缓存淘汰;
- 自动淘汰
- 利用
Redis
的缓存淘汰策略管理 - 缓存淘汰算法
4. 缓存预热
问题:
解决思路:
- 手动预热
- 对标注了缓存注解的如
@Cacheable
或者@CachePut
的业务接口进行缓存预热。
- 自动预热
- 在系统启动完毕后,调用业务接口将数据加载到缓存中。
5. 热点数据
问题:
- 缓存集群中的某个 key 瞬间被数万甚至十万的并发请求打爆
解决思路:
- 采用本地缓存来缓解缓存集群和数据库集群的压力。使用二级缓存的形式解决。
- 应用层面做限流熔断机制,保护后面的缓存集群和数据库集群可用。
6. 缓存雪崩
问题:
- 由于大量缓存失效,导致大量请求打到数据库上,导致数据库的 CPU 和内存压力变大,从而出现一系列连锁反应,造成整个系统崩溃。
解决思路:
Caffeine
默认使用异步机制加载缓存数据,可有效防止缓存击穿(防止同一个 key 或不同 key 被击穿的场景)- 将缓存层设计成高可用,防止缓存大面积故障
- 利用本地缓存,一定程度上保证服务的可用性。但主要还是通过对源服务的访问进行限流、熔断、降级等手段。
- 提前压测,项目上线前,演练缓存层宕机后,应用以及后端的负载情况以及可能出现的问题,对高可用提前预演,提前发现问题。
7. 缓存击穿
问题:
- 在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个 key 正好失效了,就会导致大量的请求都打到数据库上面去,这种现象就是缓存击穿
解决思路:
- 解决思路同
缓存雪崩
,利用Caffeine
默认使用异步机制加载缓存数据,可以有效的防止缓存击穿。
8. 缓存穿透
问题:
- 请求根本不存在的数据,也就是在缓存和数据库中都查不到这条数据,但是请求每次都会打到数据库上面去。这种查询不存在数据的现象就是缓存穿透。
解决思路:
- 通过对不存在的 key 缓存空值,来防止缓存穿透。
- 也可以通过使用
BloomFilter
来对 key 进行过滤。 - 对于高并发系统,可以结合 Hystrix 或 Sentinel来做应用级别的限流和降级,以保护下游系统不会被大量的请求给打死。