这里是Redis学习笔记的第四篇,主要讲Redis主从复制和哨兵。
为什么需要主从复制
单机redise风险与问题
- 问题1 机器故障
- 问题2 容量瓶颈
为了避免单点redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,链接在一起,并保证数据是否同步的,即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份。
但是多台服务器怎么保证这么多服务器的数据同步呢?让每个数据库的数据都读写数据并且保持一致是一件很难的事情,于是有一种方案:我们让一台主服务器写,多台从服务器读 (这也考虑到数据库大大部分操作都是查询操作),然后主服务器写操作更新数据同步给从服务器。所以我们有了主从复制。
什么是主从复制
考虑上面我们的解决方案。主从复制即将master中的数据即时,有效的复制到slave中。从而达到各个服务器数据同步的目的。
特征:一个master可以拥有多个slave,一个slave只对应一个master
master的职责:
写数据
执行写操作时,将出现变化的数据自动同步到slave
读数据(可忽略)
slave的职责:
读数据
写数据(禁止)
主从复制的作用
读写分离:master写,slave读,提高服务器的读写负载能力
负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
数据冗余:实现数据热备份,时持久化之外的一种数据冗余方式
高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案
主从复制工作流程
主从复制过程大体可以分为3个阶段
1,建立连接阶段(即准备阶段) 2,数据同步阶段 3,命令传播阶段
我们来稍微详细第讲一下这三个过程。
1,建立连接阶段
保存主节点信息
从节点服务器内部维护了两个字段,即masterhost和masterport字段,用于存储主节点的ip和port信息。
slaveof是异步命令,从节点完成主节点ip和port的保存后,向发送slaveof命令的客户端直接返回OK,实际的复制操作在这之后才开始进行。
建立socket连接
从节点每秒1次调用复制定时函数replicationCron(),如果发现了有主节点可以连接,便会根据主节点的ip和port,创建socket连接。如果连接成功:
从节点:为该socket建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收RDB文件、接收命令传播等。
主节点:接收到从节点的socket连接后(即accept之后),为该socket创建相应的客户端状态,并将从节点看做是连接到主节点的一个客户端,后面的步骤会以从节点向主节点发送命令请求的形式来进行。
发送ping命令
从节点成为主节点的客户端之后,发送ping命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。
从节点发送ping命令后,主结点一般返回pong:说明socket连接正常,且主节点当前可以处理请求,复制过程继续。
身份验证
如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证;没有设置该选项,则不需要验证。
从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续;如果不一致,则从节点断开socket连接,并重连。
发送从节点端口信息
身份验证之后,从节点会向主节点发送其监听的端口号,主节点将该信息保存到该从节点对应的客户端的slave_listening_port字段中;该端口信息除了在主节点中执行info Replication时显示以外,没有其他作用。
这一阶段的指令/配置为:
主从连接(slave连接master) 方式一:客户端发送命令 slaveof <masterip> <masterport> 方式二:启动服务器参数 redis-server -slaveof <masterip> <masterport> 方式三:服务器配置 slaveof <masterip> <masterport> 还有一些其他的配置信息: slave系统信息 master_link_down_since_seconds masterhost masterport master系统信息 slave_listening_port(多个)
客户端发送命令:
slaveof no one
说明:slave断开连接后,不会删除已有数据,只是不再接受master发送的数据
2,数据同步阶段
这一步的主要目的就是把,从结点的数据库更新成主节点的数据。简单划分这一阶段有5步:
1,请求同步 2,创建RDB同步数据 3,恢复RDB同步数据 4,请求部分同步数据 5,恢复部分同步数据
这一阶段的重点是:全量复制和部分复制。
- 全量复制:用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。
- 部分复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。
全量复制:
(1)从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行全量复制;
(2)主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令
(3)主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态
(4)主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态
(5)如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态
部分复制:
部分复制依赖于三个重要的概念:服务器运行ID,复制积压缓冲区,复制偏移量
服务器运行ID(runid)
概念:服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id
组成:运行id由40位字符组成,是一个随机的十六进制字符 例如:fdc9ff13b9bbaab28db42b3d50f852bb5e3fcdce
作用:运行id被用于在服务器间进行传输,识别身份。如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别
实现方式:运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info Server命令,可以查看节点的runid
复制缓冲区
概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
复制缓冲区默认数据存储空间大小是1M,由于存储空间大小是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列
由来:每台服务器启动时,如果开启有AOF或被连接成为master节点,即创建复制缓冲区
作用:用于保存master收到的所有指令(仅影响数据变更的指令,例如set,select)
数据来源:当master接收到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中
主从服务器复制偏移量(offset)
概念:一个数字,描述复制缓冲区中的指令字节位置
master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个)
slave复制偏移量:记录slave接收master发送过来的指令字节对应的位置(一个)
作用:同步信息,比对master与slave的差异,当slave断线后,恢复数据使用
3,命令传播阶段
数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING和REPLCONF ACK。
主->从:PING
每隔指定的时间,主节点会向从节点发送PING命令,这个PING命令的作用,主要是为了让从节点进行超时判断。
PING发送的频率由 repl-ping-slave-period 参数控制,单位是秒,默认值是10s。
从->主:REPLCONF ACK
在命令传播阶段,从节点会向主节点发送REPLCONF ACK命令,频率是每秒1次;命令格式为:REPLCONF ACK {offset},其中offset指从节点保存的复制偏移量。
REPLCONF ACK命令的作用包括:
(1)实时监测主从节点网络状态:该命令会被主节点用于复制超时的判断。此外,在主节点中使用info Replication,可以看到其从节点的状态中的lag值,代表的是主节点上次收到该REPLCONF ACK命令的时间间隔,在正常情况下,该值应该是0或1。
(2)检测命令丢失:从节点发送了自身的offset,主节点会与自己的offset对比,如果从节点数据缺失(如网络丢包),主节点会推送缺失的数据(这里也会利用复制积压缓冲区)。注意,offset和复制积压缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。
(3)辅助保证从节点的数量和延迟:Redis主节点中使用min-slaves-to-write和min-slaves-max-lag参数,来保证主节点在不安全的情况下不会执行写命令;所谓不安全,是指从节点数量太少,或延迟过高。例如min-slaves-to-write和min-slaves-max-lag分别是3和10,含义是如果从节点数量小于3个,或所有从节点的延迟值都大于10s,则主节点拒绝执行写命令。而这里从节点延迟值的获取,就是通过主节点接收到REPLCONF ACK命令的时间来判断的,即前面所说的info Replication中的lag值。
哨兵模式
为什么需要哨兵
在我们上诉的主从复制解决方案中,很容易想到可能会出现:主服务器宕机了怎么办?那么我们有以下工作要做:
1,关闭master和所有slave 2,找一个slave作为master 3,修改其他slave的配置,连接新的主 4,启动新的master与slave 5,全量复制*N+部分复制*N
但是这些工作要思考几个问题:
关闭期间的数据服务谁来承接?
找一个主?怎么找法?
修改配置后,原始的主恢复了怎么办?
所以我们有了哨兵模式来解决。
什么是哨兵模式
哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
哨我们通常讲兵的作用有三个:
1,监控
不断的检查master和slave是否正常运行。
master存活检测、master与slave运行情况检测
2,通知(提醒)
当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知。
3,自动故障转移
断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址
注意:哨兵也是一台redis服务器,只是不提供数据服务。通常哨兵配置数量为单数
启用哨兵模式
这个指令能启动哨兵
redis-sentinel sentinel- 端口号 .conf
我们需要的配置项
哨兵主从切换的工作流程
哨兵在进行主从切换过程中经历三个阶段
1,监控:Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
2,通知:当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3,故障转移:当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
这一部分黑马程序员的视频和PPT讲解十分生动:
参考资料:
Bilibili黑马程序员的Redis视频:https://www.bilibili.com/video/BV1CJ411m7Gc
Redis主从复制:https://www.cnblogs.com/wade-luffy/p/9639986.html (好文章)