Redis 热Key、 穿透、雪崩

本文探讨了高并发场景下Redis面临的热key问题及其解决方案,包括互斥锁、提前使用互斥锁和永不真正过期策略。同时,讨论了缓存穿透与雪崩现象的应对方法,以及Redis的内存淘汰策略。

高并发的情况会给系统带来很高的访问流量,这就给存储这些热点信息的Redis数据造成了一些压力。

热key问题及解决方案
产生原因
用户消费的数据远大于生产的数据 (热卖商品、热点新闻、热点评论、明星直播)等。

在日常工作生活中一些突发的的事件,例如某明星突然宣布恋情,导致某新闻点击量瞬间变大,请求远超过对数据的写入。就会造成热数据问题。

我们 一般采用缓存 + 过期时间的策略来帮助我们加速接口的访问速度,减少了后端负载,同时保证功能的更新,一般情况下这种模式已经基本满足要求了。

但是有两个问题如果同时出现,可能就会对系统造成致命的危害:

访问的数据是一个热点key
构建缓存需要时间
以上两个问题如果同时出现,就可能会造成缓存失效问题,有大量线程来构建缓存,造成后端负载过大,严重还会导致系统崩溃。

在这里插入图片描述

上图简单描述了访问热点key及构建缓存的一个过程。

解决方案
解决热点key问题,可以有以下几种方案,

1、互斥锁

在上图查询数据库的过程,只让一个线程独占,这个线程构建缓存的过程,其他线程都要等待,直到第一个线程构建完成可以从中读取数据。

2、提前使用互斥锁

提前使用互斥锁,和互斥锁差不多,都是让一个线程独占构建缓存,不一样的是,在构建缓存的时候。

在value内部设置一个超时值timeout1,这个过期时间比实际的缓存过期时间短。

当从缓存中读到timeout1已经过期的时候,就认为数据也快过期了,直接执行查询数据库,进行构建缓存的过程。

这样在所有快过期的数据前,就重新构建了缓存。

3、永远不过期

永远不过期有两点

a、从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。

b、从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期

可能会出现的问题,就是会出现老数据,怎么说?

有1、2、3、4个线程,在第2个线程时,发现value中数据已经过期,通过异步更新重新构建缓存,前面有说过,线程构建缓存会需要一定时间,如果在第4个线程执行时才完成构建,那么第2、3个线程输出的就是老数据。不过对于一般的业务需求是可以接受的。

穿透和雪崩
缓存穿透
什么是缓存穿透?

在客户端和数据库中间增加一个缓存层,如果这个缓存层中保存的都是数据库命中数据,如果服务层并没有返回数据保存到缓存中,而客户端一直在访问这个数据,则每次都要直接访问数据库,在流量小时没有问题,如果流量非常大或有恶意攻击,就会利用这个漏洞,使服务端的压力增大,严重会导致系统崩溃。

解决方案

1、把查询结果为空的结果也放到缓存中,设置很短的缓存过期时间,不超过5分钟;

2、增加一个bloomfilter,任务某个key不存在,则不访问数据库;

缓存雪崩
什么是缓存雪崩?

雪崩是设置缓存失效的时间相同,造成大量的数据在短时间内同时失效,这样访问数据库的压力也会陡增。压力这么大,就像是发生了雪崩一样。

解决方案

1、采用加锁或消息队列,采用单线程的方式,防止失效时大量线程请求数据库。

2、在同样的缓存失效时间上,增加一个随机值,这样每个缓存的过期时间的重复率就会降低很多。

3、保证缓存的高可用。例如Redis Sentinel 和 Redis Cluster

淘汰机制
保存在内存中的缓存数据如果过期或失效,为了更合理利用内存空间,提高内存使用效率。

什么是淘汰机制

在内存中保存的Key被清除掉,

(1)定时去清理过期的缓存;

(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。

可以通过redis.conf设置# maxmemory 这个值来开启内存淘汰功能

redis数据淘汰策略
volatile-lru 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl 从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random 从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru 从所有数据集中挑选最近最少使用的数据淘汰
allkeys-random 从所有数据集中任意选择数据进行淘汰
noeviction 禁止驱逐数据

原文:https://blog.youkuaiyun.com/mayfla/article/details/80112241

### 三级标题:Redis缓存击穿、穿透雪崩的区别与解决方法 Redis缓存是高并发系统中提高性能的重要工具,但其在特定场景下可能引发缓存击穿、缓存穿透和缓存雪崩等问题。这些问题虽然都与缓存失效有关,但其触发条件和影响范围各不相同,解决方案也各有侧重。 #### 缓存击穿 缓存击穿指的是某个点数据在缓存中过期后,短时间内有大量请求直接访问数据库,导致数据库压力骤增[^2]。这种情况通常发生在访问频率极高的数据上,例如双十一期间的商品信息。解决缓存击穿的方法包括: - **永不过期策略**:将点数据设置为永不过期,或者通过后台异步更新机制来刷新缓存,避免因过期而引发数据库压力[^2]。 - **互斥锁(Mutex)**:当缓存未命中时,第一个线程获取互斥锁并查询数据库,其他线程等待锁释放后再从缓存中获取数据,从而避免并发请求直接访问数据库[^3]。 #### 缓存穿透 缓存穿透是指查询一个既不在缓存也不在数据库中的数据,导致每次请求都直接访问数据库[^1]。攻击者可以通过构造不存在的查询来恶意攻击数据库。常见的解决方法有: - **布隆过滤器(Bloom Filter)**:在请求到达数据库之前,使用布隆过滤器判断数据是否存在。如果布隆过滤器返回不存在,则直接返回错误,不查询数据库[^1]。 - **缓存空值(Null Value)**:对于查询结果为空的情况,可以将空值也缓存一段时间,并设置较短的过期时间,以减少对数据库的无效查询[^1]。 #### 缓存雪崩 缓存雪崩是指大量缓存数据在同一时间过期,或者Redis服务宕机,导致所有请求都转发到数据库,可能引发数据库崩溃[^1]。这种情况通常发生在系统时间同步或缓存集中失效时。解决缓存雪崩的方法包括: - **分散过期时间**:为缓存数据设置随机的过期时间,避免所有缓存同时失效。例如,在基础过期时间上加上一个随机值。 - **集群部署与高可用**:通过Redis集群部署和主从复制机制,确保即使某个节点宕机,其他节点仍能提供服务,从而避免缓存雪崩[^1]。 - **降级熔断机制**:当Redis服务不可用时,系统可以启用降级模式,例如返回默认值或缓存中的历史数据,以减轻数据库压力[^1]。 #### 总结 缓存击穿、穿透雪崩虽然都与缓存失效有关,但它们的触发条件和影响范围不同: - **缓存击穿**:点数据过期后引发大量请求访问数据库。 - **缓存穿透**:查询不存在的数据,导致请求直接访问数据库。 - **缓存雪崩**:大量缓存同时失效或Redis服务宕机,导致请求全部转发到数据库。 针对不同的问题,需要采取相应的解决方案,例如互斥锁、布隆过滤器、分散过期时间和高可用部署等。 ```java // 示例:使用互斥锁解决缓存击穿问题 public String getData(String key) { String data = redis.get(key); if (data == null) { synchronized (this) { data = redis.get(key); if (data == null) { data = db.query(key); // 从数据库中查询数据 redis.set(key, data, 60); // 设置缓存 } } } return data; } ``` ```java // 示例:使用布隆过滤器解决缓存穿透问题 BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), 1000000); public String getDataWithBloomFilter(String key) { if (!bloomFilter.mightContain(key)) { return "Key does not exist"; } String data = redis.get(key); if (data == null) { data = db.query(key); redis.set(key, data, 60); } return data; } ``` ```java // 示例:分散过期时间解决缓存雪崩问题 public void setCacheWithRandomExpire(String key, String value) { int expireTime = 60 + new Random().nextInt(20); // 基础过期时间加上随机值 redis.setex(key, expireTime, value); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值