主从复制
概述
主从复制有如下特点:一个master可以拥有多个slave,但是一个slave只能对应一个maste
r;
- 负载均衡:主数据库可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给从数据库;从数据库一般是只读的,并且接收主数据库同步过来的数据;
- 故障恢复:slave挂了不影响其他slave的读和master的读和写,重新启动后会将数据从master同步过来;
master挂了以后,不影响slave的读,但redis不再提供写服务
,master重启后redis将重新对外提供写服务;master挂了以后,不会在slave节点中重新选一个master
;
- 高可用基石:除了上述作用以外,
主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础
。
主从库之间采用的是读写分离的方式。
读操作:主库、从库都可以接收
;主节点(Master):唯一可写节点,处理所有写操作
- 写操作:首先到主库执行,然后,主库将写操作同步给从库。
从节点(Slave):只读副本,通过复制流同步主节点数据
复制流程
1.建立复制关系
从节点执行命令:
SLAVEOF <master_ip> <master_port> # 建立主从关系
连接建立过程:
- 从节点向主节点发送PING确认连通性
- 主节点响应PONG
- 从节点发送REPLCONF listening-port 声明自身端口
2. 全量同步(Full Resynchronization)
触发条件
从节点首次连接主节点
- 发送 psync 命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行ID,所以发送 psync-1;
- 主节点根据 psync-1 解析出当前为全量复制,回复 +FULLRESYNC 响应;
- 从节点接收主节点的响应数据保存运行 ID 和偏移量 offset;
主从复制ID不匹配(主节点发生过故障切换)
执行步骤:
- 主节点执行bgsave生成RDB快照
- 主节点将RDB文件发送给从节点,从节点把接收的 RDB 文件保存在本地并直接作为从节点的数据文件;
主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求
- 从节点清空旧数据,从节点清空数据后加载RDB文件
为了避免之前数据的影响,从库需要先把当前数据库清空
- 主节点将RDB生成期间的写命令存入复制缓冲区(Replication Buffer)
为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作
- RDB加载完成后,主节点发送缓冲区中的增量命令
当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。
Redis 为什么主从全量复制使用RDB而不使用AOF
RDB文件内容是经过压缩的二进制数据(不同数据类型数据做了针对性优化),文件很小。
从库在加载RDB文件时,
一是文件小
,读取整个文件的速度会很快,二是因为RDB文件存储的都是二进制数据,从库直接按照RDB协议解析还原数据即可,速度会非常快
而AOF文件记录的是每一次写操作的命令
,写操作越多文件会变得很大,其中还包括很多对同一个key的多次冗余操作。
AOF需要依次重放每个写命令,这个过程会经历冗长的处理逻辑,恢复速度相比RDB会慢得多,所以使用RDB进行主从全量复制的成本最低
另外就是RDB操作简单
假设要使用AOF做全量复制,意味着必须打开AOF功能,打开AOF就要选择文件刷盘的策略,选择不当会严重影响Redis性能。
而RDB只有在需要定时备份和主从全量复制数据时才会触发生成一次快照。
而在很多丢失数据不敏感的业务场景,其实是不需要开启AOF的。
3. 增量同步
增量同步(Partial Resynchronization):如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大
。从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。
触发条件
网络闪断后重连
- 当主从节点之间网络出现中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并中断复制连接;
- 主从连接中断期间主节点依然响应命令,但因复制连接中断命令无法发送给从节点,不过主节点内部存在的复制积压缓冲区,依然可以保存最近一段时间的写命令数据,默认最大缓存 1MB;
- 当主从节点网络恢复后,从节点会再次连上主节点;
从节点的复制偏移量(offset)仍在主节点缓冲区范围内
执行机制
- 从节点发送PSYNC
当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行 ID。因此会把它们当作 psync 参数发送给主节点,要求进行部分复制操作
- 主节点验证复制ID和offset有效性
主节点接到 psync 命令后首先核对参数 runId 是否与自身一致,如果一致,说明之前复制的是当前主节点;
根据参数 offset 在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送 +CONTINUE 响应,表示可以进行部分复制; - 有效时发送+CONTINUE并传输缺失的增量数据
主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态
实现
在这里说明一下核心步骤,具体的实现步骤可上网再自行搜索
配置步骤
- 主节点配置(无需特殊配置):打开master节点文件,文件位于vi/usr/local/redis/redis.conf目录下,然后修改配置如下:
bind 0.0.0.0 # 允许远程连接
masterauth 123456 # slave连接master密码,master可省略
requirepass 123456 # 设置master连接密码,slave可省略
- 从节点配置:
# replicaof用于追随某个节点的redis,被追随的节点为主节点,追随的为从节点。就是设置master节点
replicaof 192.168.1.100 6379 # 指定主节点信息
masterauth 123456 # 主节点密码(如果设置了认证)
# 优化配置
repl-diskless-sync yes # 无盘复制(适用于磁盘性能差的环境)
repl-diskless-sync-delay 5 # 无盘复制等待时间(秒)
- 验证:查看节点状态
# 启动redis
systemctl start redis
systemctl status redis
# 查看集群的一些数据:
# 交互式
redis-cli -h 192.168.1.110 -a 123456
192.168.182.110:6379> info replication
# 交互式
redis-cli -h 192.168.1.110
192.168.182.110:6379> auth 123456
192.168.182.110:6379> info replication
# 非交互式
redis-cli -h 192.168.1.110 -a 123456 info replication
/* 输出如下
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.101,port=6379,state=online,offset=123456,lag=0
slave1:ip=192.168.1.102,port=6379,state=online,offset=123456,lag=1
*/
哨兵模式
概述
主从模式的弊端就是不具备高可用性
,当master挂掉以后,Redis将不能再对外提供写入操作,因此sentinel模式应运而生
Redis 哨兵模式(Sentinel)是实现高可用的核心方案,
专为解决主从架构中的 自动故障转移 和 服务发现 问题而设计
。
主从复制 vs 哨兵模式
特性 | 主从复制 | 哨兵模式 |
---|---|---|
自动故障转移 | 不支持 | 支持 |
高可用保障 | 需手动干预 | 自动切换 |
复杂度 | 简单 | 需维护 Sentinel |
适用场景 | 数据备份/读写分离 | 生产环境高可用需求 |
流程
核心功能
- 节点监控:持续检测主/从节点健康状态
- 自动故障转移:主节点故障时选举新主节点
- 配置中心:向客户端提供最新的主节点地址
- 通知告警:通过API或脚本触发告警
原理
pub/sub 机制
哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制
,也就是发布 / 订阅机制。
- 在主从集群中,主库上有一个名为sentinel:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的
- 哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到sentinel:hello频道上,哨兵 2 和 3 订阅了该频道
- 哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号
- 如此,哨兵 2、3 可以和哨兵 1 建立网络连接,哨兵 2 和 3 也可以建立网络连接。它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事儿进行判断和协商。
- 哨兵监控:哨兵向主库发送 INFO 命令来完成的。如下图所示
- 哨兵 2 给主库发送 INFO 命令,主库接受到这个命令后,就会把从库列表返回给哨兵。
- 哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续地对从库进行监控。
- 哨兵 1 和 3 可以通过相同的方法和从库建立连接。
判断主库已经下线
哨兵如何判断主库已经下线
:两种概念,主观下线和客观下线
主观下线:任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断
;当某个哨兵(如下图中的哨兵2)判断主库“主观下线”后,就会给其他哨兵发送 is-master-down-by-addr 命令,其他哨兵会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。
客观下线:由哨兵集群共同决定Redis节点是否下线
;如果赞成票数是大于等于哨兵配置文件中的 quorum 配置项, 则可以判定主库客观下线了
哨兵集群的选举
选举的作用:由哪个哨兵节点来执行主从切换
为什么需要选举
- 为了避免哨兵的单点情况发生,所以需要一个哨兵的分布式集群
- 分布式集群,必然涉及共识问题(即选举问题)
- 同时故障的转移和通知都只需要一个主的哨兵节点就可以了
哨兵的选举机制:Raft选举算法
选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举
任何一个想成为 Leader 的哨兵,要满足两个条件:
- 第一,拿到半数以上的赞成票;
- 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以
分布式算法(待补充链接)
新主库的选出
选择新的主库,有下面三个选择条件,依顺序去筛选
- 选择健康节点:过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
- 选择优先级高的节点:选择salve-priority从节点优先级最高(redis.conf)的
- 选择尽量完整节点:选择复制偏移量最大,只复制最完整的从节点
故障的转移
基本概念
判断主库客观下线了,同时选出sentinel 3是哨兵leader,故障转移流程如下:
- 将slave-1脱离原从节点,升级主节点,
- 将从节点slave-2指向新的主节点slave-1
- 通知客户端主节点已更换
- 将原主节点(oldMaster)变成从节点,指向新的主节点
转移后,slave-1新主节点有两个副本slave-2和old master,而old master不再有副本
,哨兵集群仍然监控所有的主从节点
流程总结
对上述的判断到转移做一个总结
工作的流程如下所示:
-
每个sentinel以每秒钟一次的频率向它所知的master,slave以及其他sentinel实例发送一个 PING 命令;
-
如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被sentinel标记为主观下线
; -
如果一个master被标记为主观下线,则正在监视这个master的所有sentinel要以每秒一次的频率确认master的确进入了主观下线状态;
-
当有足够数量的sentinel(大于等于配置文件指定的值)在指定的时间范围内确认master的确进入了主观下线状态, 则master会被标记为客观下线
;在一般情况下, 每个sentinel会以每 10 秒一次的频率向它已知的所有master,slave发送 INFO 命令;
当master被sentinel标记为客观下线时,sentinel向下线的master的所有slave发送 INFO 命令的频率会从 10 秒一次改为 1 秒一次; -
若没有足够数量的sentinel同意master已经下线,master的客观下线状态就会被移除
;若master重新向sentinel的 PING 命令返回有效回复,master的主观下线状态就会被移除。
配置哨兵模式
哨兵模式是基于主从模式的
我们只需要在主从模式的基础上直接修改sentinel配置文件,哨兵的配置主要就是修改sentinel.conf配置文件中的参数,在Redis安装目录即可看到此配置文件,主要参数如下:
参数 | 作用 |
---|---|
sentinel monitor <name> <ip> <port> <quorum> | 定义监控的主节点和法定人数(同意故障转移的哨兵数) |
down-after-milliseconds | 主节点无响应多久后标记为主观下线(单位:毫秒) |
failover-timeout | 故障转移超时时间,超时后终止转移 |
parallel-syncs | 故障转移后,同时从新主节点同步数据的从节点数(避免带宽拥塞) |
配置如下
//端口默认为26379。
port:26379
//关闭保护模式,可以外部访问。
protected-mode:no
//设置为后台启动。
daemonize:yes
//日志文件。
logfile:./sentinel.log
//指定主机IP地址和端口,并且指定当有2台哨兵认为主机挂了,则对主机进行容灾切换。
sentinel monitor mymaster 192.168.231.130 6379 2
//当在Redis实例中开启了requirepass,这里就需要提供密码。
sentinel auth-pass mymaster pwdtest@2019
//判断master主观下线时间,默认30s
sentinel down-after-milliseconds mymaster 3000
//主备切换时,最多有多少个slave同时对新的master进行同步,这里设置为默认的1。
sentinel parallel-syncs mymaster 1
//故障转移的超时时间,这里设置为三分钟。
sentinel failover-timeout mymaster 180000
启动sentinel模式的命令如下:
/usr/local/bin/redis-sentinel /usr/local/redis/sentinel.conf
验证哨兵状态
redis-cli -p 26379 sentinel masters