系统架构

Redis 缓存雪崩、缓存击穿、缓存穿透、缓存预热

2019-07-25  本文已影响205人  大鱼炖海棠

常规的缓存处理流程是:客户端向服务端请求数据 ,服务端先从缓存中 get 数据,缓存命中则直接返回结果,否则从 DB 中取,DB 获取到数据就去更新缓存并返回结果,否则返回空。

这个流程放在本地环境研究学习还行,如果要部署到生产,就需要考虑缓存雪崩、缓存击穿和缓存穿透的致命问题!

一、缓存雪崩

缓存雪崩是指某一时刻发生了大规模的缓存失效,比如发生了 Redis 服务器宕机、缓存数据同时到期被删除这种情况,此时大量的请求直接转发到数据库,数据库一旦撑不住就会导致整个服务瘫痪。


缓存雪崩

解决方案:

PS:对服务降级前需做系统梳理,比如:哪些业务是核心,哪些业务可以容许暂时不提供服务(利用静态页面替换)等,以及配合服务器核心指标,来设置整体预案,比如:
1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
3)错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

二、缓存击穿

对于一些设置了过期时间的热点 key,需要考虑缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里是针对某个 key 的缓存,前者则是很多 key。

解决方案:

String get(String key) {
    String value = redis.get(key);
    if (value == null) {
        if (redis.setnx(key_max, "1")) {
            redis.expire(KEY_MUTEX, 3 * 60);
            value = pg.get(key);
            redis.set(key, value);
            redis.delete(KEY_MUTEX);
        } else {
            // 其他线程 50ms 后重试
            Thread.sleep(50);
            get(key);
        }
    }
}

上述两种方案对比:

方案 优点 缺点
使用互斥锁(mutex key) 保证一致性 程序复杂度高,存在死锁和线程阻塞的风险
设置 key 永不过期 异步构建缓存,线程不会阻塞 无法保证一致性,代码复杂度增加,每个 key 占用的空间增加

三、缓存穿透

缓存穿透是指查询一个一定不存在的数据。出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义,也很容易被攻击者作为系统漏洞进行攻击。

解决方案:

四、缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统,避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题,用户直接查询事先被预热的缓存数据。

上一篇 下一篇

猜你喜欢

热点阅读