Redis 缓存雪崩、击穿、穿透
Redis 缓存雪崩、击穿、穿透
雪崩
什么是redis缓存雪崩现象呢?
当Redis在某一时间段内,出现大量的key失效了,所以导致请求全部涌入到了数据库当中,此时数据库压力巨大,可能会导致崩溃。
雪崩现象的本质就是 某一时间,大量的key过期了。
我们要解决这个问题就需要合理的管理每一个key在redis缓存中的生命周期,避免大量的key同一时间过期。
产生的原因
- 给大量的
key设置相同的过期时间,所以导致会在同一时间缓存过期。 Redis服务宕机了,所有请求都会绕过缓存直接到数据库中。
解决方案
针对相同时间过期
首先问题出现在了大量的key过期时间一致,我们一般设置key过期时间时,一般会指定它生存多久,而不会指定在什么时刻失效,所以我们可以在指定过期时间时不要设置N时间过期,而是在这个时间上加一个随机值,这个随机值可以根据业务需求来定,比如1-5分钟。
针对Redis宕机了
Redis宕机了,也就是说当前Redis服务器部署,不满足高可用性。那么我们可以通过Redis高可用组件来避免一台服务器宕机了,就导致业务崩溃。比如可以采用Redis的哨兵模式或者Redis集群模式。
当主库挂了,可以第一时间让从库升级为主库,继续为业务提供缓存服务。
当然为了最大化提升缓存的高可用性,可以在业务服务器当中,再添加一层缓存,这里的缓存由于内存硬件限制,不能存储大量的数据,但是可以存储一些热点key。使这些热点key长时间驻留在缓存中,不会因为Redis服务器宕机了,导致请求全部涌向了数据库中。
还有一种策略,它属于兜底的策略。使用限流和熔断。
限流:可以在网关层对请求进行限流(令牌桶等方法),这样不会导致大量的请求同一时间涌入数据库中。
熔断机制:当下游服务出现故障时,为了它不影响当前服务,可以直接放弃访问下游服务,直接返回错误给用户。避免长时间等待下游服务的恢复,导致上游服务崩溃。
击穿
我在最初学习Redis缓存的时候,分不清楚击穿和穿透,有时会会记混。
在这里我尽可能把这两个概念,写清楚,让之后的自己或者读者能够一眼分清楚什么是击穿什么是穿透。
穿透可以联想渗透测试(一种提前防止黑客攻击的安全测试-找漏洞),它是大量请求访问不存在的数据。一般是由黑客进行攻击时造成的。
缓存击穿主要问题是针对热点key突然过期了,大量访问该热点key的请求只能涌向数据库,导致数据库压力上升。
解决方案
-
最简单的方式是针对热点
key设置长时间过期时间或者设置为永不自动过期,可以手动删除key。 -
在业务服务器中,添加一个缓存,里面存储着所有的热点key,然后设置为永不过期,虽然
redis中的过期了,不影响业务服务器里的缓存获取。 -
加互斥锁,当一个请求访问热点
key发现它过期了,然后加锁,从数据库获取数据,并且放入Redis缓存中,之后释放锁。这样其它请求就可以直接从Redis中访问热点key了。但是该方法,会有加锁-释放锁操作。会导致性能在某一时刻(等待锁)的时候会下降很多。
- 逻辑过期:在数据字段,加一个逻辑过期时间,如果请求访问热点
key发现,逻辑过期了,可以另起一个协程去更新这个key,然后返回旧的数据,可能会导致数据短暂的不一致,但是保证了可用性。
穿透
缓存穿透主要问题是大量请求访问不存在的数据,然后这些请求涌入数据库中,破坏数据库的可用性。
一般是有黑客攻击,所造成的正常用户请求无法及时响应,因为服务器资源被黑客的大量求请所占用。
解决方案
-
我第一个想法是在风控系统中,直接判断一些用户短时间内大量请求不存在的数据,直接拒绝该用户访问下游服务。
-
也可以采用布隆过滤器,将大量的数据映射是否存在映射到小内存中。布隆过滤器就类似于一个漏斗,将请求过滤成更少的请求。将访问不存在的数据在网管层,就直接返回数据不存,不需要将该请求传递给具体的服务。但是布隆过滤器有误判的可能。
-
缓存一个空的对象(
cache null)。如果数据库查不到该数据,就直接在缓存中缓存一个null对象,也就是说第一次访问数据库不存在的数据,那么就在缓存中缓存一个key的null值,然后后续的访问就直接在缓存层直接获取null了不需要将请求传递到数据库中。 -
在接口前端,进行参数校验,比如
ID >0等措施。