Redis 击穿、穿透、雪崩和分布式锁
2020-04-06 本文已影响0人
Robin92
击穿
前提:当 Redis 做缓存时,挡在 DB 之前,当有查数据请求时,Redis 有的话直接返回,从而避开请求 DB,没有时再去请求 DB,请求回来后缓存在 Redis 中。
击穿:Redis 缓存刚刚过期的时候有大量请求同一查询过来,就会直接 击穿 去访问 DB。
解决方法:
- 在 Redis 中上锁(
setNX + expire
),只有获得锁的人才能去请求。 - 后面请求的没获得锁,等待(睡眠)后再取。
- 请求 DB 者,请求回来后,将数据放到 Redis 中。
但有例外:如果 Expire 太小怎么办?
解决:请求者开启另一个线程,如果请求 DB 时间过长,则更新 Expire。
穿透
情景:Redis 作为缓存时,业务请求的是系统根本不存在的东西,它在 Redis 中找不到,在数据库中也找不到,这样并发的请求过来的时候,就会造成穿透。
解决:可以在客户端加算法,直接返回无结果;也可以用 布隆过滤器 将可查询的字段映射到 bitmap 中。
缺点:布隆过滤器不支持删除,所以可以换一个过滤器,如布谷鸟。
雪崩
情景:Redis 在做缓存时,大量的 Key 同时失效(比如零点 key 要换成第二天的),此时有大量并发都在访问 DB,这种情况叫雪崩。
解决:可以的话可以均匀分布过期时间(有些情景是到时间点必须换);可以用击穿的方案,第一个请求者加锁并查回数据缓存下来;还可以在客户端加判断在零点延时。
综上,它们的区别主要在:击穿是一个点;穿透是本来就不存在的一组数据;雪崩是一批数据在更换没有阻挡住。
分布式锁:RedLock
基础:
- SetNx
- Expire
- 守护线程延长过期时间
步骤,假如有 N 个 Redis 节点:
- 获取当前时间
- 按顺序去 N 个节点获取锁(访问的超时时间应远小于锁的过期时间)
- 获取 N/2+1 个锁成功就认为成功
- 成功后更新锁的时间。(最初锁的有效时间减去获取锁中间消耗的时间)
- 失败后立即释放成功上锁节点的锁
其他方式:换 Zookeeper