• 【redis-06】redis进阶知识点-订阅、主从、哨兵、缓存穿透击穿和雪崩


    【redis-06】redis进阶知识点-订阅、主从、哨兵、缓存穿透击穿和雪崩

    【一】Redis如何实现高可用

    在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、 99.99%、 99.999%等等)。但是在Redis语境中, 高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展,数据安全不会丢失等。

    在Redis中,实现高可用的技术有两个含义:
    【1】数据尽量不丢失
    1)持久化:
    持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
    【2】服务尽可能可用
    1-)主从复制模式:
    主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。
    缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
    2)哨兵模式:
    在主从复制的基础上,哨兵实现了自动化的故障恢复。
    缺陷 :写操作无法负载均衡;存储能力受到单机的限制。
    3)集群模式:
    通过集群, Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善 的高可用方案。

    【一】Redis持久化之RDB和AOF

    【1】redis为什么需要持久化

    Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以 Redis 提供了持久化功能,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘,当下次Redis重启时,利用持久化文件实现数据恢复。

    【2】实现持久化的两种方式

    (1)快照RDB持久化(Redis DataBase):原理是将Redis在内存中的数据库记录定时保存到磁盘上。
    (2)追加文件AOF持久化(append only file) :原理是将Redis的操作日志以追加的方式写入文件,类似于MySQL的binlog。

    总结:由于AOF 持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地 。

    RDB和AOF两种相比较:
    (1)RDB注重结果、体积小、安全性低、优先级相比而言较高
    (2)AOF 除了结果外话注重过程、体积大、安全性高、优先级高

    【3】快照RDB(Redis DataBase)

    (1)介绍

    RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是 rdb ;当Redis重新启动时,可以读取快照文件恢复数据。

    RDB持久化的触发分为:手动触发和自动触发两种。

    (2)手动触发

    (1)save命令和bgsave命令都可以生成RDB文件。
    (2)save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
    (3)bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程 (即Redis主进程) 则继续处理请求。也就是说bgsave可以异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间
    (4)bgsave命令执行过程中,只有fork 子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用!!!

    (3)自动触发

    在自动触发RDB持久化时,Redis也 会选择bgsave而不是save来进行持久化

    save  m   n
    
    • 1

    自动触发最常见的情况是在配置文件中通过 save m n,指定当m秒内发生n次变化时,会触发bgsave。

    (1)首先我们进入服务器找到dump.rdb文件:
    在这里插入图片描述
    (2)测试触发rdb操作:vim打开redis.conf配置文件
    在这里插入图片描述在这里插入图片描述

    为了方便测试,我们将其改为 :

    save 60 5  #意思是在60秒内进行了5次操作,即写入rdb文件中进行持久化保存
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

    (4)其他触发机制:

    (1)save的规则满足的情况下,会自动触发rdb规则,测试如下:
    先手动删除dump.rdb文件,实验触发规则!
    在这里插入图片描述在Redis中操作5次命令!
    在这里插入图片描述查看是否生成dump.rdb文件!
    在这里插入图片描述成功!

    (2)执行flushall命令,也会触发rdb规则
    再次删除dump.rdb文件!
    在这里插入图片描述执行flushall操作命令!
    在这里插入图片描述正常生成成功!
    在这里插入图片描述执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义

    (3)退出Redis,也会触发rdb规则
    删除:
    在这里插入图片描述退出:
    在这里插入图片描述生成成功!
    在这里插入图片描述

    (5)数据丢失如何恢复rdb文件

    (1)只需将备份的rdb文件放在我们的redis启动目录即可,Redis启动的时候会自动检查dump.rdb文件并恢复其中的数据!
    (2)查找文件位置的命令:

    127.0.0.1:6379> config get dir
    1) "dir"
    2) "/usr/local/bin"  # 如果在这个目录下存在 dump.rdb 文件,启动就会自动恢复其中的数据
    
    • 1
    • 2
    • 3

    (6)优缺点

    优点:
    1、适合大规模的数据恢复!
    2、对数据的完整性要求不高!

    缺点:
    1、需要一定的时间间隔进程操作!如果redis意外宕机了,这个最后一次修改数据就没有的了!
    2、fork进程的时候,会占用一定的内容空间!

    (7)总结

    Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。
    这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。我们默认的就是RDB,一般情况下不需要修改这个配置!

    在生产环境我们会将这个文件进行备份!

    【4】文件追加AOF(Append Only File)

    (1)介绍

    (1)RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录;
    (2)当Redis重启时再次执行AOF文件中的命令来恢复数据;
    (3)与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。

    (2)Redis默认使用的是RDB模式,所以需要手动开启AOF模式!

    将no改为yes即可!
    在这里插入图片描述
    在这里插入图片描述

    重启服务器!
    在这里插入图片描述发现新文件appendonly.aof!
    在这里插入图片描述

    (3)查看aof文件内容:

    先进行一些添加的操作:
    在这里插入图片描述
    然后我们可以vim打开appendonly.aof文件看看里面是什么?
    在这里插入图片描述里面存储的就是我们先前操作的命令!

    (4)修复aof文件:

    (1)如果aof文件被意外修改了,如何进行修复?
    在这里插入图片描述
    (2)重启下Redis看看:发现重启失败!报错配置信息加载失败!
    在这里插入图片描述
    (3)我们可以使用redis-check-aof文件来进行修复!

    redis-check-aof --fix appendonly.aof  #修复appendonly.aof文件
    
    • 1

    返回修复成功!
    在这里插入图片描述
    (4)我们再看看aof文件里面的内容!
    在这里插入图片描述可以看到错误的内容被修复了,但是一部分正确的记录也丢失了!所以这个修复是无法做到百分百修复的!丢一小部分好丢全部,两害相权取其轻

    (5)再次重启
    在这里插入图片描述

    (5)AOF重写规则

    aof默认的就是文件的无限追加,文件会越来越大!在配置文件中可以设置文件的大小!
    在这里插入图片描述

    # appendfsync always # 每次修改都会 sync。消耗性能 
    appendfsync everysec # 每秒执行一次 sync,可能会丢失这1s的数据! # appendfsync no # 不执行 sync,这个时候操作系统自己同步数据,速度最快!
    
    appendfilename "appendonly.aof" # 持久化的文件的名字
    appendonly no # 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下, rdb完全够用!
    
    auto-aof-rewrite-percentage 100  #写入百分比
    auto-aof-rewrite-min-size 64mb  #写入的文件最大值是多少,一般在实际工作中我们会将其设置为5gb左右!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (6)分析执行流程

    由于需要记录Redis的每条写命令,因此A0F不需要触发,AOF的执行流程如下:
    (1)命令追加(append): 将Redis的写命令追加到缓冲区 aof_ buf;
    (2)文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;
    (3)文件重写(rewrite): 定期重写AOF文件,达到压缩的目的。

    (1)命令追加(append)

    (1)Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
    (2)命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点。在A0F文件中,除了用于指定数据库的select命令 (如select0为选中0号数据库) 是由Redis添加的,其他都是客户端发送来的写命令。

    (2)文件写入(write) 和文件同步 (sync)
    (3)文件重写 (rewrite)

    随着时间流逝,Redis服务器执行的写命令越来越多,AOF文件也会越来越大:过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。

    文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作!

    关于文件重写需要注意的另一点是:对于AOF持久化来说,文件重写虽然是强烈推荐的,但并不是必须的;即使没有文件重写,数据也可以被持久化并在Redis启动的时候导入:因此在一些实现中,会关闭自动的文件重写,然后通过定时任务在每天的某一时刻定时执行。

    (4)文件重写能压缩AOF文件的原因

    (1)过期的数据不再写入文件;
    (2)无效的命令不再写入文件:如有些数据被重复设值(set mykey test1, set mykey test2)、有些数据被删除了(sadd myset vtest, del myset) 等。
    (3)多条命令可以合并为一个:如sadd myset test1, sadd myset test2, sadd myset test3可以合并为sadd myset test1 test2 test3

    通过上述内容可以看出,由于重写后AOF执行的命令减少了,文件重写既可以减少文件占用的空间,也可以加快恢复速度。

    (5)文件重写的触发

    (1)手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
    (2)自动触发:通过设置auto-aof-rewrite-min-size选项和auto-aof-rewrite-percentage选项来自动执行BGREWRITEAOF。只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。

    (7)启动时加载

    当AOF开启时,Redis启 动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据。当AOF开启,但AOF文 件不存在时,即使RDB文件存在也不会加载。

    Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败。但如果是AOF文件结尾不完整 (机器突然宕机等容易导致文件尾部不完整),且aof-load- truncated参数开启,则日志中会输出警告,Redis 忽略掉AOF文件的尾部,启动成功。

    aof-load-truncated参数默认是开启的。

    (8)优缺点

    (1)优点
    1、每一次修改都同步,文件的完整性会更加好!
    2、每秒同步一次,最多会丢失一秒的数据!
    3、从不同步,效率最高的!

    (2)缺点
    1、相对于数据文件来说,aof远远大于 rdb,修复的速度也比 rdb慢!
    2、Aof 运行效率也要比 rdb 慢,所以我们redis默认的配置就是rdb持久化!

    【5】总结

    (1)RDB持久化的优缺点

    (1)优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比, RDB最 重要的优点之一是对性能的影响相对较小。

    (2)缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。 对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。

    (2)AOF持久化的优缺点

    与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。

    对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题。

    AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的I0压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。

    (3)总结

    1、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储
    2、AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis 协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
    3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化
    4、同时开启两种持久化方式

    • 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
    • RDB 的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的Bug,留着作为一个万一的手段。

    (4)性能建议

    1-因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留 save 900 1 这条规则。
    2-如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
    3-如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。

    【二】Redis如何实现发布订阅功能?

    【1】简单介绍

    Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接受消息。
    Redis客户端可以订阅任意数量的频道!
    在这里插入图片描述

    【2】实现方式

    (1)命令

    这些命令被广泛用于构建即时通信应用,比如网络聊天室(chatroom)和实时广播、实时提醒等。
    在这里插入图片描述

    (2)发布订阅的实现

    1-订阅端

    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379> SUBSCRIBE dingdada  #订阅名字为 dingdada 的频道
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "dingdada"
    3) (integer) 1
    #等待推送的信息
    1) "message"  #消息
    2) "dingdada"  #来自哪个频道的消息
    3) "hello world\xef\xbc\x81"  # 消息的具体内容
    1) "message"
    2) "dingdada"
    3) "my name is dyj\x81"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    2-发送端

    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379> PUBLISH dingdada "hello world!"  #发送消息到dingdada 频道
    (integer) 1
    127.0.0.1:6379> PUBLISH dingdada "my name is dyj"  #发送消息到dingdada 频道
    (integer) 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    (3)PSUBSCRIBE 命令:订阅指定频道!

    PSUBSCRIBE + 频道。。 #订阅给定的模式,可多个
    
    • 1

    在这里插入图片描述

    (4)PUBLISH 命令:发送消息至指定频道!

    PUBLISH + 频道 +消息  #将信息 message 发送到指定的频道 channel
    
    • 1

    在这里插入图片描述

    (5)PUNSUBSCRIBE命令:退订!

    #指示客户端退订指定模式,若果没有提供模式则退出所有模式。
    
    • 1

    在这里插入图片描述

    (6)SUBSCRIBE:订阅,同上一致。不细讲!

    在这里插入图片描述

    (7)UNSUBSCRIBE:退订,同上一致,不细讲!

    在这里插入图片描述

    (8)总结

    Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。

    【三】主从复制模式

    默认情况下,每台redis服务器都是主节点。以单机集群作为演示,实际工作中不会这样配置,而是使用哨兵模式,仅借此学习主从复制的概念

    【1】概念

    (1)主从复制

    是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave 以读为主,所有slave节点的数据都是从master节点同步过来的。

    (2)结构图

    在这里插入图片描述
    上图是一种简单的主从结构模式,它的slave节点都挂在master节点上,这样做的优点是slave节点与master节点的数据延迟较小。缺点是如果slave节点数量很多,master同步一次数据的时间花费较长。可以只在master节点下只挂载一个slave节点,其他节点挂载在这个salve节点上,数据同步经过传递完成,如下图所示。Redis和大部分中间件的主从模式中的数据同步都是由slave节点主动发起的,这样可以减少master的性能消耗。

    在这里插入图片描述

    (3)主从模式的作用

    (1)支持数据备份:主从复制实现了数据的热备份,防止出现服务器宕机导致数据丢失
    (2)故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
    (3)支持读写分离:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
    (4)高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

    (4)优点

    (1)实现读写分离,降低master节点的读数据压力,提高系统的性能。写操作交给master节点,读操作交给slave节点,提供多个副本。
    (2)配置简单,容易搭建。只需要在slave节点上维护master节点的地址信息就可实现。

    (5)缺点

    (1)当master节点宕机时,由于无法选择哪一个slave节点当master节点,无法保证高可用。
    (2)所有的写数据的压力都集中在master节点,没有解决master节点写的压力。

    【2】环境配置(单机集群)

    (1)基本查看命令

    在这里插入图片描述

    127.0.0.1:6379> ping  #测试是否连接成功!
    PONG
    127.0.0.1:6379> info replication  #查看当前redis信息
    # Replication
    role:master  #角色--主机
    connected_slaves:0  #从机数量为0
    master_replid:b9565cf2edea63b7e9860f3ef1a170d59ff7a4d4  #唯一标识的id
    master_replid2:0000000000000000000000000000000000000000
    #下面的这些咱不用管他是啥
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    (2)开启三台服务

    (1)复制三个配置文件
    在这里插入图片描述(2)修改以下配置
    端口
    在这里插入图片描述pid名
    在这里插入图片描述log文件名
    在这里插入图片描述dump.rdb名
    在这里插入图片描述
    (3)全部启动并查看
    在这里插入图片描述查看所有Redis端口:证明启动成功啦!
    在这里插入图片描述

    【3】一主二从(单机测试)

    (1)确认主机

    在这里插入图片描述

    127.0.0.1:6380> ping
    PONG
    127.0.0.1:6380> slaveof 127.0.0.1 6379  #让本机认6379的机器为大哥!
    OK
    127.0.0.1:6380> info replication  #查看信息
    # Replication
    role:slave  #从机
    master_host:127.0.0.1  #主机ip
    master_port:6379   #主机端口
    master_link_status:up
    master_last_io_seconds_ago:3
    master_sync_in_progress:0
    slave_repl_offset:14
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (2)第二台机器同理,我们看看主机的信息

    在这里插入图片描述

    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379> info replication
    # Replication
    role:master  #主机
    connected_slaves:2  #有两台从机
    #从机的ip、端口等信息
    slave0:ip=127.0.0.1,port=6380,state=online,offset=56,lag=1  
    #从机的ip、端口等信息
    slave1:ip=127.0.0.1,port=6381,state=online,offset=56,lag=1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    出现以上内容,证明我们配置成功了!

    (3)注意点

    这种通过命令的配置是‘一次性的’,如果机器宕机、断电等,就需要重新设置主机和从机!
    在实际工作中,我们都是通过配置文件中修改指定配置的!如下图:
    在这里插入图片描述可以修改以上配置来实现主从机的配置!

    (4)测试读写操作

    (1)主机写,从机读
    在这里插入图片描述证明主从复制成功了!

    (2)如果主机断开
    在这里插入图片描述
    从机可以正常读数据
    在这里插入图片描述查看从机信息:
    在这里插入图片描述在这里插入图片描述证明,虽然主机断开了,但是从机还是可以正常读取原先就有的数据的!

    (3)如果断开的主机重新连接上
    在这里插入图片描述
    从机也可正常连接上主机,因为配置了,会自动寻找主机。

    (4)如果从机断开重连呢?
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    证明:如果从机断开重连,不会自动连接上主机!因为我们的配置是在从机上写的,而且是命令写的,重启时会重置!

    (5)从机能写嘛?
    在这里插入图片描述从机只能读,不能写!

    (5)复制原理

    Slave 启动成功连接到 master 后会发送一个sync同步命令

    Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

    **全量复制:**而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

    增量复制: Master 继续将新的所有收集到的修改命令依次传给slave,完成同步但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中
    看到!

    (6)层层链路

    在这里插入图片描述这时候也可以完成我们的主从复制!

    (7)从机替换主机

    如果主机断开了连接,我们可以使用

     SLAVEOF no one
    
    • 1

    让自己变成主机!其他的节点就可以手动连接到最新的这个主节点(手动)!如果这个时候原来的老大修复了,那就重新连接成为小弟!!
    在这里插入图片描述注意!!!
    即使原来的主机没有挂,也可以使用这个命令直接让从机变成主机。

    【4】总结

    一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:

    1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;

    2、从容量上,单个Redis服务器内存容量有限,就算一Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该20G。

    主从复制,读写分离! 80% 的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用! 一主二从!

    只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis!

    【四】哨兵模式(自动实现主从切换)

    【1】概述

    (1)哨兵模式

    上一章主从模式中说到,主机断开后,我们得手动设置另一个从机变成主机!这是不智能的,在实际工作中,是使用哨兵模式来自动切换主机。

    主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑 哨兵模式 。Redis从2.8开始正式提供了Sentinel(哨兵) 架构来解决这个问题。

    哨兵机制用于对主从模式中每个节点进行监控,当出现故障时通过投票机制,选择新的master节点,并将所有的slave节点连接到master节点

    哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的 进程 ,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

    在这里插入图片描述

    (2)哨兵模式的三个作用:监控、通知和自动故障转移

    (1)监控(Monitoring):不断地检查master和salve是否运行正常。master存活检测、master和slave运行情况检测。
    (2)通知(Notification):当被监控的某个节点出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
    (3)自动故障转移(Automatic failover):断开master与slave之间的连接,选取一个salve作为master,将其他slave连接到新的master,并告知客户端新的节点地址。

    (3)优缺点

    (1)优点
    哨兵机制,保证高可用。能够监控各个节点运行状况,进行自动故障转移。

    (2)缺点
    1-中心化集群实现方式,基于主从模式,切换节点时,会发生数据的丢失。
    2-集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响master的性能。
    3-数据写的操作都集中在master上,仍然没有解决master写数据的压力。

    【2】配置哨兵的过程

    (1)添加哨兵配置文件 sentinel.conf
    在这里插入图片描述
    内容如下

    # sentinel monitor 被监控的名称 host port 1 (代表自动投票选举大哥!)
    sentinel monitor myredis 127.0.0.1 6379 1
    
    • 1
    • 2

    (2)启动哨兵

    redis-sentinel dyjConfig/sentinel.conf   #和启动Redis一致
    
    • 1

    启动成功后如下图
    在这里插入图片描述
    (3)前提准备条件
    开启一台主机,两台从机
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    (4)测试主机宕机后自动选取新的主机,如果主机此时回来了,只能归并到新的主机下,当做从机,这就是哨兵模式的规则!

    在这里插入图片描述
    等待哨兵的默认配置时间时 30 秒!
    在这里插入图片描述
    再次查看redis信息
    在这里插入图片描述

    可以发现8381变成主机,8380依旧是从机!

    我们将老大哥主机连接试试!可以发现6379变成从机了,由大哥变为小弟!
    在这里插入图片描述
    而6381成功成为主机大哥大
    在这里插入图片描述

    【3】哨兵机制的原理详细版

    (1)判断master节点是否下线

    (1)每个 sentinel 哨兵节点每隔1s 向所有的master、slave以及其他 sentinel 节点发送一个PING命令,作用是通过心跳检测,检测主从服务器的网络连接状态

    (2)如果 master 节点回复 PING 命令的时间超过 down-after-milliseconds 设定的阈值(默认30s),则这个 master 会被 sentinel 标记为主观下线,修改其 flags 状态为SRI_S_DOWN

    (3)当sentinel 哨兵节点将 master 标记为主观下线后,会向其余所有的 sentinel 发送sentinel is-master-down-by-addr消息,询问其他sentinel是否同意该master下线
    (4)每个sentinel收到命令之后,会根据发送过来的 ip和port 检查自己判断的结果,回复自己是否认为该master节点已经下线了
    (5)sentinel收到回复之后,如果同意master节点进入主观下线的sentinel数量大于等于quorum,则master会被标记为客观下线,即认为该节点已经不可用。

    (6)在一般情况下,每个 Sentinel 每隔 10s 向所有的Master,Slave发送 INFO 命令。当Master 被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次。作用:发现最新的集群拓扑结构

    (2)基于Raft算法选举领头sentinel

    (1)判断客观下线的sentinel节点向其他 sentinel 节点发送 SENTINEL is-master-down-by-addr ip port current_epoch runid

    注意:这时的runid是自己的run id,每个sentinel节点都有一个自己运行时id

    (2)目标sentinel回复是否同意master下线并选举领头sentinel,选择领头sentinel的过程符合先到先得的原则。举例:sentinel1判断了客观下线,向sentinel2发送了第一步中的命令,sentinel2回复了sentinel1,说选你为领头,这时候sentinel3也向sentinel2发送第一步的命令,sentinel2会直接拒绝回复

    (3)当sentinel发现选自己的节点个数超过 majority 的个数的时候,自己就是领头节点

    (4)如果没有一个sentinel达到了majority的数量,等一段时间,重新选举

    (3)故障转移

    有了领头sentinel之后,下面就是要做故障转移了,故障转移的一个主要问题和选择领头sentinel问题差不多,到底要选择哪一个slaver节点来作为master呢?按照我们一般的常识,我们会认为哪个slave节点中的数据和master中的数据相识度高哪个slaver就是master了,其实哨兵模式也差不多是这样判断的,不过还有别的判断条件,详细介绍如下:
    (1)在进行选择之前需要先剔除掉一些不满足条件的slaver,这些slaver不会作为变成master的备选

    1-剔除列表中已经下线的从服务
    2-剔除有5s没有回复sentinel的info命令的slave
    3-剔除与已经下线的主服务连接断开时间超过 down-after-milliseconds * 10 + master宕机时长 的slaver

    (2)选主过程:

    ① 选择优先级最高的节点,通过sentinel配置文件中的replica-priority配置项,这个参数越小,表示优先级越高
    ② 如果第一步中的优先级相同,选择offset最大的,offset表示主节点向从节点同步数据的偏移量,越大表示同步的数据越多
    ③ 如果第二步offset也相同,选择run id较小的

    (4)修改配置

    新的master节点选择出来之后,还需要做一些事情配置的修改,如下:
    (1)领头sentinel会对选出来的从节点执行slaveof no one 命令让其成为主节点
    (2)领头sentinel 向别的slave发送slaveof命令,告诉他们新的master是谁谁谁,你们向这个master复制数据
    (3)如果之前的master重新上线时,领头sentinel同样会给起发送slaveof命令,将其变成从节点

    【4】哨兵机制的原理简略版

    哨兵会检测主从的状态,如果发现主节点宕机,就会找从节点来替换,这里就用到了raft算法,3台哨兵在发现主节点宕机后,就会先给自己投一票,然后再去寻求其他哨兵来给自己投票,只要其中一个哨兵的票数超过了半数,它就能成为master,由这个哨兵来选取一个从节点服务器来进行升级成主节点服务器。

    如果每个哨兵都是给自己投了一票,那它们就会在一个随机的时间后,进入下一个选取纪元,每个哨兵都会休眠一个随机时间,醒来后再次去请求对方的支持,直到有一个哨兵超过了半数的票,越早醒来的哨兵越容易获得投票。

    哨兵一般都是配置的单数,这样可以保证投票的时候更快的得出投票结果,如果是双数就可能会出现平票的情况,也就是出现了脑裂现象。

    【4】总结

    (1)优点
    1-哨兵集群,基于主从复制模式 ,所有的主从配置优点,它全有
    2-主从可以切换,故障可以转移 ,系统的 可用性 就会更好
    3-哨兵模式就是主从模式的升级,手动到自动,更加健壮!

    (2)缺点
    1-Redis 不好在线扩容 的,集群容量一旦到达上限,在线扩容就十分麻烦!
    2-实现哨兵模式的配置其实是很麻烦的,里面有很多选择!

    (3)注意点
    以上所有的配置因为条件所限都是基于单机集群的前提下!有兴趣的可以自己搭建下正式集群下的多哨兵模式来监控!如下图:
    在这里插入图片描述(4)哨兵的配置文件解析(网上找的,只需要关注几个重点!)

    # Example sentinel.conf 
    
    # 哨兵sentinel实例运行的端口 默认26379 
    port 26379 
    
    # 哨兵sentinel的工作目录 
    dir /tmp 
    
    # 哨兵sentinel监控的redis主节点的 ip port 
    # master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。 
    # quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了 
    # sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor mymaster 127.0.0.1 6379 2 
    
    # 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供 密码
    # 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码 
    # sentinel auth-pass <master-name> <password> 
    sentinel auth-pass mymaster MySUPER--secret-0123passw0rd 
    
    # 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒 
    # sentinel down-after-milliseconds <master-name> <milliseconds> 
    sentinel down-after-milliseconds mymaster 30000 
    
    # 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步
    #这个数字越小,完成failover所需的时间就越长,
    # 但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。 
    #可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 
    # sentinel parallel-syncs <master-name> <numslaves> 
    sentinel parallel-syncs mymaster 1 
    
    
    # 故障转移的超时时间 failover-timeout 可以用在以下这些方面: 
    #1. 同一个sentinel对同一个master两次failover之间的间隔时间。 
    #2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那 里同步数据时。 
    #3.当想要取消一个正在进行的failover所需要的时间。 
    #4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时, slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了 
    # 默认三分钟 # sentinel failover-timeout <master-name> 
    sentinel failover-timeout mymaster 180000 
    
    
    # SCRIPTS EXECUTION #配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知 相关人员。 
    #对于脚本的运行结果有以下规则: 
    #若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10 #若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 
    #如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。 
    #一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。 
    #通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等), 将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信 息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配 置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无 法正常启动成功。 
    #通知脚本 
    # shell编程 
    # sentinel notification-script <master-name> <script-path> 
    sentinel notification-script mymaster /var/redis/notify.sh 
    
    
    # 客户端重新配置主节点参数脚本 
    # 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已 经发生改变的信息。 
    # 以下参数将会在调用脚本时传给脚本: 
    # <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> 
    # 目前<state>总是“failover”, 
    # <role>是“leader”或者“observer”中的一个。 
    # 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通 信的
    # 这个脚本应该是通用的,能被多次调用,不是针对性的。 
    # sentinel client-reconfig-script <master-name> <script-path> 
    sentinel client-reconfig-script mymaster /var/redis/reconfig.sh 
    # 一般都是由运维来配置!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    【五】集群模式

    【1】概述

    哨兵模式基本已经实现了高可用,但是每个节点都存储相同的内容,很浪费内存。而且,哨兵模式没有解决master写数据的压力。为了解决这些问题,就有了集群模式,实现分布式存储,每个节点存储不同的内容。

    集群部署的方式能自动将数据进行分片,每个master上放一部分数据,提供了内置的高可用服务,即使某个master宕机了,服务还可以正常地提供,架构如下图所示:

    在这里插入图片描述
    集群模式中数据通过数据分片的方式被自动分割到不同的master节点上,每个Redis集群有16384个哈希槽,进行set操作时,每个key会通过CRC16校验后再对16384取模来决定放置在哪个槽。数据在集群模式中是分开存储的,那么节点之间想要知道其他节点的状态信息,包括当前集群状态、集群中各节点负责的哈希槽、集群中各节点的master-slave状态、集群中各节点的存活状态等是通过建立TCP连接,使用gossip协议来进行集群信息传播。

    故障判断方法:判断故障的逻辑其实与哨兵模式有点类似,在集群中,每个节点都会定期的向其他节点发送ping命令,通过有没有收到回复来判断其他节点是否已经下线。具体方法是采用半数选举机制,当A节点发现目标节点疑似下线,就会向集群中的其他节点散播消息,其他节点就会向目标节点发送命令,判断目标节点是否下线。如果集群中半数以上的节点都认为目标节点下线,就会对目标节点标记为下线,从而告诉其他节点,让目标节点在整个集群中都下线。

    【2】集群模式搭建的过程

    集群模式搭建的过程

    【3】集群模式的原理

    【4】总结

    优点如下:
    (1)无中心结构,部署简单。所有的Redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
    (2)可扩展性,可扩展master节点,释放单个master的写数据压力,节点可动态添加或删除。
    (3)能够实现自动故障转移,节点之间通过gossip协议交换状态信息,用投票机制完成slave到master的角色转换。

    【六】总结哨兵模式和集群模式的区别

    【七】Redis缓存穿透、击穿和雪崩

    【1】缓存穿透(恶意访问不存在的数据)

    在这里插入图片描述

    (1)缓存穿透概念

    用户需要查询一个数据,但是redis中没有(比如说mysql中id=-1的数),直接去请求MySQL,当很多用户同时请求并且都么有命中!于是都去请求了持久层的数据库,那么这样会给持久层数据库带来非常大的压力。一般出现这样的情况都不是正常用户,基本上都是恶意用户!

    (2)解决方案

    (1)布隆过滤器
    在这里插入图片描述布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;

    补充专门介绍布隆过滤器的知识

    (2)缓存空对象
    在这里插入图片描述
    当存储层查不到,即使是空值,我们也将其存储起来并且在Redis中设置一个过期时间,之后再访问这个数据将会从Redis中访问,保护了持久层的数据库!

    (3)存在的问题
    1-如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
    2-即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
    3-注意:缓存穿透前提是:Redis和MySQL中都没有,然后不停的直接请求MySQL。

    【2】redis的缓存击穿(热点key失效)

    在这里插入图片描述

    (1)缓存击穿概念

    是指一个非常热点的key,在不停的扛着大并发,当这个key失效时,一瞬间大量的请求冲到持久层的数据库中,就像在一堵墙上某个点凿开了一个洞!

    (2)解决方案

    (1)设置热点key永不过期
    从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

    (2)加互斥锁
    在这里插入图片描述在查询持久层数据库时,保证了只有一个线程能够进行持久层数据查询,其他的线程让它睡眠几百毫秒,等待第一个线程查询完会回写到Redis缓存当中,剩下的线程可以正常查询Redis缓存,就不存在大量请求去冲击持久层数据库了!

    (3)缺点
    其实设置永不过期不合理!

    【3】redis的缓存雪崩(大量key同时过期)

    在这里插入图片描述

    (1)缓存雪崩

    在某一个时间段,缓存的key大量集中同时过期了,所有的请求全部冲到持久层数据库上,导致持久层数据库挂掉!
    范例:双十一零点抢购,这波商品比较集中的放在缓存,设置了失效时间为1个小时,那么到了零点,这批缓存全部失效了,而大量的请求过来时,全部冲过了缓存,冲到了持久层数据库!

    (2)解决方案

    (1)Redis高可用集群+数据预热(事前):搭建Redis集群,尽量保证整个 redis 集群的高可用性,发现机器宕机后有从机代替。
    (2)数据预热(事前):在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,并且在失效时间上增加一个 1 到 5 分钟的随机值避免热点key同时失效。
    (3)限流降级(事中):在缓存失效后,通过加锁或者hystrix限流&降级来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。避免所有请求直接打到数据库上。
    (4)持久化恢复(事后):利用 redis 持久化机制RDB或者AOF保存的数据尽快恢复缓存

  • 相关阅读:
    Python旅游门票收费问题
    LeetCode 319 周赛
    【目标检测】——Gold-YOLO为啥能超过YOLOV8
    【Java基础知识 23】缓冲区数据结构bytebuffer
    【STM32】PWM输出
    毕业设计源码基于JAVA的课程设计管理系统的设计与实现
    Opengl ES之FBO
    抖音小店开店最新一套运营教程,低成本的风口项目,直接套用就行
    winSCP创建用密钥访问的站点
    web前端期末大作业【足球网页】学生网页设计作业源码
  • 原文地址:https://blog.csdn.net/weixin_44823875/article/details/127858748