Redis(二)缓存雪崩、穿透与击穿

本贴最后更新于 1652 天前,其中的信息可能已经物是人非

1、什么是雪崩?

前提: 为节约内存,Redis 一般会做定期清除操作。

  1. 突然在同一段时间内大量的 key 同时失效;

  2. 当大量请求查询的值,此时 Redis 中都没有数据;

  3. 如果有 5000 个用户并发来查询时恰好都是查询这些 key 发现 redis 都不存在数据,全到 Mysql 里去查, Mysql 会挂掉,导致雪崩。

解决思路: 只让 5000 个中一个请求去访问 MySQL,其他 4999 个请求阻塞,等到第一个请求拿到了数据再放入到缓存中时其他 4999 个请求重入操作读取 redis 缓存数据。

解决方案如下:

  A:设置热点数据永远不过期。

  B:用加分布式锁保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。在加锁方法内先从缓存中再获取一次(防止另外的线程优先获取锁并写入缓存),没有再查 DB 写入缓存。

  C:MQ 分布式队列的方式,保证请求先进先出,进行流量的削峰,避免大量请求落入 DB;

  D:合理设置过期时间,尽量按照业务需求错开 key 的失效时间,解决同一时间大量 key 失效的问题;

  E:物理上的缓存是不设置超时时间的(或者超时时间比较长), 但是在缓存的对象上增加一个属性来标识超时时间(此时间相对小)。 当获取到数据后,校验数据内部的标记时间,判定是否快超时了,如果是,异步发起一个线程(控制好并发)去主动更新该缓存。(这种方式会导致一定时间内,有些请求获取缓存会拿到过期的值,看业务是否能接受而定)。

2、什么是穿透?

**前提:**黑客模拟一个不存在的查询条件,举例:userID=100000000…

导致:

  1、请求来到 Redis 中查询无此值会去 DB 查询;

  2、但是 DB 中也无此值, 所以也无法写入数据到缓存;

  3、而黑客一直通过第三方工具大量发送这个请求,导致 DB 一直被查询,一直没有数据,最后导致整个存储系统瘫痪;

解决方案:

  A:对订单表所有数据查询出来放到布隆过滤器, 经过布隆过滤器处理的数据很小(只存 0 或 1);每次查订单表前,先到过滤器里查询当前订单号状态是 0 还是 1, 0 的话代表数据库没有数据, 直接拒绝查询;

  B:进行请求过滤,比如 userid 肯定是自增的,来了一个请求 get?userId=100000000000,这样的请求肯定是在缓存中查询不出来的,就会求查数据库,数据库中也不存在,如果一直这样会导致穿透,可以对请求进行过滤,请求携带的条件现阶段绝对不存在的直接过滤掉;

  C:对于 DB 中不存在的数据直接在 redis 中写入“not data”并设置过期时间;

3、什么是缓存击穿?

前提: 一个缓存过期了,但是突然在这个时候恰好接受到了大量查询这个缓存的请求,

导致:

  1、 当大量请求查询 redis 时发现不存该值;

  2、 请求在缓存读取不到数据,去 DB 中拿数据,这个时候大量请求查询数据库轻则导致出现连接异常,重则导致 DB 宕机导致整个系统不可用;

解决方案:

  A:设置热点 key 永不过期。

  B:对于查询操作加锁,每次只让一部分请求去查询 DB。

  C:物理上的缓存是不设置超时时间的(或者超时时间比较长), 但是在缓存的对象上增加一个属性来标识超时时间(此时间相对小)。 当获取到数据后,校验数据内部的标记时间,判定是否快超时了,如果是,异步发起一个线程(控制好并发)去主动更新该缓存。(这种方式会导致一定时间内,有些请求获取缓存会拿到过期的值,看业务是否能接受而定)。

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖 • 123 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...