Redis 击穿、穿透、雪崩和分布式锁

击穿

前提:当 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

你可能感兴趣的:(Redis 击穿、穿透、雪崩和分布式锁)