缓存雪崩
缓存雪崩是指某一时刻发生了大规模的缓存失效,比如发生了 Redis 服务器宕机、缓存数据同时到期被删除这种情况,此时大量的请求直接转发到数据库,数据库一旦撑不住就会导致整个服务瘫痪。
过期时间错峰:
分析用户行为,制定策略为 key 设置不同的过期时间,尽量让缓存失效的时间均匀分布
高可用
采用主从架构 + Sentinel 或者 Redis Cluster 实现HA,避免 Redis 单点故障
缓存降级
设置本地缓存(ehcache) + 限流(hystrix)。如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。服务降级的最终目的是保证核心服务可用
备份和恢复
开启 Redis 持久化机制,服务重启后快速恢复缓存数据
缓存击穿
对于一些设置了过期时间的热点 key,需要考虑缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里是针对某个 key 的缓存,前者则是很多 key。
使用互斥锁(mutex key):
让一个线程构建 Redis 缓存,其他线程等待构建缓存的线程执行完,然后直接从缓存获取数据
设置 key 永不过期
永不过期既要保证 key 一直持有在缓存中,又要能对 key 的 value 进行及时的更新。实现的方式是不为 key 设置物理过期时间,即不通过redis.expire(key, timeout) 命令设置过期时间;但是要设置一个逻辑的过期时间,可以把 key 的过期时间拼接到 value 中,程序访问缓存时,从 value 中解析出过期时间并根据规则判定 key 是否需要更新
两种方案对比:
方案 | 优点 | 缺点 |
---|---|---|
使用互斥锁 | 保证一致性 | 程序复杂度高,存在死锁和线程阻塞的风险 |
设置key永不过期 | 异步构建缓存缓存,线程不会阻塞 | 无法保证一致性,代码复杂度增加,每个 key 占用的空间增加 |
缓存穿透
缓存穿透是指查询一个一定不存在的数据。出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义,也很容易被攻击者作为系统漏洞进行攻击。
- key校验,key设定一定的规则,不符合规则的倍屏蔽。
- 接口层增加校验,如用户鉴权校验,id 做基础校验,id<=0 的直接拦截
- 即便存储层查不到这个数据,也将返回的空对象设置到缓存里。下次再请求的时候,直接从缓存取到空对象返回,这种情况一般会将空对象设置一个较短的过期时间,这样可以防止攻击者反复用同一个 id 暴力攻击。
缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统,避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题,用户直接查询事先被预热的缓存数据。