Redis击穿、穿透、雪崩产生原因以及解决思路
文章目录1. 前言2. 击穿1. 前言众所周知,计算机的瓶颈之一就是IO,为了解决内存与磁盘速度不匹配的问题,产生了缓存,将一些热点数据放在内存中,随用随取,降低连接到数据库的请求链接,避免数据库挂掉。需要注意的是,Redis产生击穿、穿透、雪崩情况的前提条件都是Redis做缓存使用,并且产生了高并发。2. 击穿...
1. 前言
众所周知,计算机的瓶颈之一就是IO,为了解决内存与磁盘速度不匹配的问题,产生了缓存,将一些热点数据放在内存中,随用随取,降低连接到数据库的请求链接,避免数据库挂掉。需要注意的是,Redis产生击穿、穿透、雪崩情况的前提条件都是Redis做缓存使用,并且产生了高并发
2. 击穿
2.1 原因
- key过期
- key被页面置换淘汰
Redis只要做缓存使用一定会受到内存大小的限制,所以我们在使用Redis做缓存时,无论是key的过期时间到了还是Redis内部的淘汰策略(LRU、LFU) 都会有缓存失效的一瞬间,当key失效时有大量的并发请求到达server,然而此时缓存不存在,导致大量请求直接访问数据库
2.2 解决方案
根据Redis的单线程特性,可以认为任务是在队列里依次执行的,当请求到达Redis发现key过期时,可以设置锁,具体流程如下:
- 请求到达Redis,发现key过期,查看有没有锁,没有锁的话回到队列后面排队
- 设置锁,注意,这儿应该是setnx(),而不是set(),因为可能有其他线程已经设置锁了
- 获取锁,拿到锁了就去数据库取数据,请求返回后释放锁
如果拿到锁去取数据的请求挂了导致死锁怎么办?可以在设置锁的同时添加过期时间,如果超时自动释放锁资源
这里也存在一个问题那就是过期时间设置大小的问题,设置大了,如果第一个请求挂了,会导致后面的大量请求等待时间过长而超时,如果设置时间过短,自己没处理完别的请求进来了,这样循环下去,这也会存在一定的并发请求
可以开启一个守护线程来监控数据有没有从数据库中获取出来放入缓存,如果没有完成则适当延迟锁的过期时间。这里可以使用分布式锁Redisson、zookeeper
3. 穿透
3.1 原因
大量请求访问数据库不存在的数据
例如一个卖书的商城一直被请求查询茶叶产品,由于Redis缓存主要是用来缓存热点数据,对于数据库不存在的数据,是没法缓存的,这种异常流量就会直接到达数据库并且返回NULL
3.2 解决方案
可以对访问请求加一层过滤器,例如布隆过滤器、增强版布隆过滤器、布谷鸟过滤器
除了布隆过滤器,可以增加一些参数检验,例如数据库数据id一般都是递增的,如果请求 id = -10 这种参数,势必绕过Redis,避免这种情况,可以对用户真实性检验等操作
4. 雪崩
4.1 原因
雪崩,和击穿类似,不同的是击穿是一个热点key某时刻失效,而雪崩是大量的热点key在一瞬间失效
4.2 解决方案
这里需要区分业务场景,缓存具不具有时点性,如果不具有时点性,可以随机过期时间解决
如果具有时点性,我的Redis大批量的key就要在一天内的某个点全部失效,这里只能强依赖于击穿的解决方案,引入分布式锁,策略是先过去的线程更新一下所有key
在后台更新热点key的同时,业务层将进来的请求延时一下,例如短暂的睡几毫秒或者秒,给后面的更新热点key分散压力
更多推荐
所有评论(0)