穿透、雪崩、击穿

  1. 缓存穿透:大量请求根本不存在的key
  2. 缓存雪崩:redis中大量key集体过期
  3. 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,但是热点key过期)

穿透解决方案

  1. 对空值进行缓存
    (但不能一味遇到就缓存,可以设定一个根据业务判断不会一般不会超出点最大空值进行记录,当没有且请求不在设定范围值能,着不进行数据库访问,多处新增货修改时更新该阀值)
  2. 设置白名单
  3. 使用布隆过滤器

雪崩解决方案

进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制

击穿解决方案

进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制

三者出现的根本原因:Redis命中率下降,请求直接打在DB上
正常情况下,大量的资源请求都会被redis响应,在redis得不到响应的小部分请求才会去请求DB,这样DB的压力是非常小的,是可以正常工作的(如下图)

如果大量的请求在redis上得不到响应,那么就会导致这些请求会直接去访问DB,导致DB的压力瞬间变大而卡死或者宕机。如下图:

  1. 大量的高并发的请求打在redis上
  2. 这些请求发现redis上并没有需要请求的资源,redis命中率降低
  3. 因此这些大量的高并发请求转向DB(数据库服务器)请求对应的资源
  4. DB压力瞬间增大,直接将DB打垮,进而引发一系列“灾害”

根本原因
大量的高并发的请求打在Redis上,但是发现Redis中并没有请求的数据,redis的命令率降低,所以这些请求就只能直接打在DB(数据库服务器)上,在大量的高并发的请求下就会导致DB直接卡死、宕机

情景分析

缓存穿透

缓存穿透产生的原因:请求根本不存在的资源(DB本身就不存在,Redis更是不存在)

举例(情景在线):客户端发送大量的不可响应的请求(如下图)

当大量的客户端发出类似于:http://localhost:8080/user/19833?id=-3872 的请求,就可能导致出现缓存穿透的情况。因为数据库DB中本身就没有id=-3872的用户的数据,所以Redis也没有对应的数据,那么这些请求在redis就得不到响应,就会直接打在DB上,导致DB压力过大而卡死情景在线或宕机。

缓存穿透很有可能是黑客攻击所为,黑客通过发送大量的高并发的无法响应的请求给服务器,由于请求的资源根本就不存在,DB就很容易被打垮了。

解决方式
对空值进行缓存:

类似于上面的例子,虽然数据库中没有id=-3872的用户的数据,但是在redis中对他进行缓存(key=-3872,value=null),这样当请求到达redis的时候就会直接返回一个null的值给客户端,避免了大量无法访问的数据直接打在DB上

实时监控:

对redis进行实时监控,当发现redis中的命中率下降的时候进行原因的排查,配合运维人员对访问对象和访问数据进行分析查询,从而进行黑名单的设置限制服务(拒绝黑客攻击)

使用布隆过滤器:

使用BitMap作为布隆过滤器,将目前所有可以访问到的资源通过简单的映射关系放入到布隆过滤器中(哈希计算),当一个请求来临的时候先进行布隆过滤器的判断,如果有那么才进行放行,否则就直接拦截

接口校验:

类似于用户权限的拦截,对于id=-3872这些无效访问就直接拦截,不允许这些请求到达Redis、DB上。

注意事项:

使用空值作为缓存的时候,key设置的过期时间不能太长,防止占用太多redis资源
使用空值作为缓存只能防止黑客重复使用相同的id暴力攻击,但是如果黑客使用动态的无效id攻击就没有效果(需要配合网警)
使用布隆过滤器也是有哈希冲突的可能

缓存雪崩

缓存雪崩产生的原因:redis中大量的key集体过期

举例:

当redis中的大量key集体过期,可以理解为redis中的大部分数据都被清空了(失效了),那么这时候如果有大量并发的请求来到,那么redis就无法进行有效的响应(命中率急剧下降),请求就都打到DB上了,到时DB直接崩溃

解决方式:

  1. 将失效时间分散开

    通过使用自动生成随机数使得key的过期时间是随机的,防止集体过期

  2. 使用多级架构 使用多级架构

    使用nginx缓存+redis缓存+其他缓存,不同层使用不同的缓存,可靠性更强

  3. 设置缓存标记

    记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去跟新实际的key

  4. 使用锁或者队列的方式

    如果查不到就加上排它锁,其他请求只能进行等待

缓存击穿

产生缓存雪崩的原因:redis中的某个热点key过期,但是此时有大量的用户访问该过期key

举例:

类似于“某男明星塌房事件”上了热搜,这时候大量的“粉丝”都在访问该热点事件,但是可能优于某种原因,redis的这个热点key过期了,那么这时候大量高并发对于该key的请求就得不到redis的响应,那么就会将请求直接打在DB服务器上,导致整个DB瘫痪。

解决方案:

  1. 提前对热点数据进行设置

    类似于新闻、某博等软件都需要对热点数据进行预先设置在redis中

  2. 监控数据,适时调整

    监控哪些数据是热门数据,实时的调整key的过期时长

  3. 使用锁机制

    最后的防线,当热点key过期,那么就使用锁机制防止大量的请求直接打在DB

缓存预热

缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统。
避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决方案

  1. 直接写个缓存刷新页面,上线时手工操作下。
  2. 数据量不大,可以在项目启动的时候自动进行加载。
  3. 定时刷新缓存。

缓存会面临冷启动问题

冷启动:服务刚刚启动时,Redis中并没有缓存,如果所有商品数据都在第一次查询时添加缓存,可能会给数据库带来较大压力。


缓存预热:在实际开发中,我们可以利用大数据统计用户访问的热点数据,在项目启动时将这些热点数据提前查询并保存到Redis中。

我们数据量较少,并且没有数据统计相关功能,目前可以在启动时将所有数据都放入缓存中。


如果不进行预热,那么 Redis 初始状态数据为空,系统上线初期,对于高并发的流量,都会访问到数据库中, 对数据库造成流量的压力。

在缓存预存预热时,不能将所有数据都写入 Redis,因为数据量大时,写入 Redis 耗时较长,且 Redis 容纳不下所有数据。实际上应该在日常统计数据访问记录,统计访问频度较高的热点数据,将之先加载到缓存中。

缓存预热解决方案

数据量不大的时候,工程启动的时候进行加载缓存动作(比如在一个组件的方法上使用 @PostConstruct 注解,在工程启动的时候,其中代码就会执行,可以加载缓存)或者上线时写个接口,手动触发加载缓存;
数据量大的时候,设置一个定时任务脚本,进行缓存的刷新(不定期刷新,缓存可能会失效);

Redis的高并发

高并发

官方数据表示Redis读的速度是110000次/s,写的速度是81000次/s 。
redis尽量少写多读,符合缓存的适用要求。
单机redis支撑万级,如果10万+就需要用redis replication模式,也就是集群模式;

replication 模式

10万+的部署方式:开启主从模式(redis replication ),一主多从,开启读写分离;主负责写,从负责读;多个slave支持水平扩容。
master和多个slave的数据同步是异步进行。同步时,不会阻塞master,也不会阻塞slave(slave提供原副本服务)

持久化

因为存在数据的同步,master要开启持久化;如果不持久化,数据可能会丢失:

  1. 是master重启后,master中空数据同步到slave,导致slave为空;
  2. master挂了,slave还没来得及切换为master,master就已经重启了,也会导致数据被同步而清空。
    master本身持久化,还需要做多副本备份,完全确保master本身的数据是可靠存在的。

replication(主从)原理

master和slave之间,当slave第一次连接master时,会触发全量备份。若是中途连接,就只会同步新增的命令数据;
全量备份的方式分为落磁盘和不落磁盘两种。

  • 默认是落磁盘,master会生成一个RDB文件到磁盘中,然后把这个RDB文件传送到各个slave,slave加载文件恢复数据;

  • 还有一种是不落磁盘,RDB文件在内存中,直接传送到各个slave上恢复数据;这两种方式是可配的。
    slave接收文件并加载时,如果文件太大,导致接收和加载超过设置的默认值(60秒),就会同步失败。可以修改这个值。按照千兆带宽计算(100m/s),4-6G的文件传输就会超过一分钟。在文件同步过程中,master还会继续缓存新的命令数据在内存中,最后再把这些新的数据同步到slave。
    支持断点续传。
    由于是RDB文件传输,所以支持断点续传,不用担心网络连接会断掉;

  • 过期key策略。
    slave不会主动执行过期key策略,而是master删除过期key的时候发送del到slave进行同步删除。
    rdb文件可以做冷备。
    master会生成rdb文件,可以把这些rdb文件按时间点进行多分冷备,在需要的时候可以恢复指定时间点的rdb文件。
    master每10秒发一次心跳,slave每1秒发1次心跳。

高并发几种思路

全量同步和增量同步

全量同步:就是在上线的时候把查询的所有数据都存到redis中,设置永不失效。

增量同步:在MySql中的binlog日志记录着程序所有的增删改语句,cannal对binlog进行实时监控,如果binlog有更改,就会触发canal同步系统,redis中的内容进行同步更新。

解决问题:缓存雪崩缓存击穿

主从原理

主节点:master 用来写
从节点:slave 用来读

主节点只能有一个,从节点可以有多个

使用场景:当QPS(每秒查询率)达到一定高度时,一台服务器不够用时,需要搭建多台服务器时,就用到了主从复制。

原理
首先让用户访问从服务器,从服务器和主服务器建立了连接,主服务器发送数据副本,做到实时更新,这样就有额外的从服务器处理读请求,通过将读请求分发到不同的从服务器上进行处理,以达到分担压力,性能增强。
用户请求的写功能,从服务器会将这个请求交给主服务器去做。

实现高可用

高可用(HA)是分布式系统架构设计中必须考虑的因素之一,它是通过架构设计减少系统不能提供服务的时间。

保证高可用通常遵循下面几点:

  1. 单点是系统高可用的大敌,应该尽量在系统设计的过程中避免单点。
  2. 通过架构设计而保证系统高可用的,其核心准则是:冗余。
  3. 实现自动故障转移

我们现在已经给Redis实现了主从复制,可将主节点数据同步给从节点,从节点此时有两个作用:

  1. 从节点扩展主节点的读能力,分担主节点读压力。
  2. 一旦主节点宕机,从节点作为主节点的备份可以随时顶上来。(高可用)

哨兵机制(Sentinel)

应用场景:当主节点宕机,从节点晋升为主节点,同时修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,这个过程都是由Sentinel来进行实时监控的。

哨兵监控

哨兵有三个定时监控任务完成对各节点的发现和监控

任务1,每个哨兵节点每10秒会向主节点和从节点发送info命令获取最新拓扑结构图,哨兵配置时只要配置对主节点的监控即可(sentinel monitor mymaster 192.168.1.3 26379 2),通过向主节点发送info,获取从节点的信息,并当有新的从节点加入时可以马上感知到;

任务2,每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断,其实就是通过消息publish和subscribe来完成的;

任务3,每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据

故障转移

由Sentinel节点定期监控发现主节点是否出现了故障,sentinel会向master发送心跳PING来确认master是否存活,如果master在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了,会要求其他sentinel确认该节点是否丢失,如果确认,则认为是客观下线,的确不可用了,开始进行故障转移


返回 redis 系列
avatar
懒觉猫先生
欢迎你们的到来!
关注我吧
最新文章
最新评论
正在加载中...
网站资讯
文章数目 :
172
已运行时间 :
本站总字数 :
111.4k
本站访客数 :
本站总访问量 :
最后更新时间 :