

🔥个人主页: 中草药
🔥专栏:【中间件】企业级中间件剖析
一、主从复制
在分布式系统之中为了解决单点问题(1、可用性问题,该机器挂掉服务会停止2、性能支持的并发量是有限的)通常会把数据复制多个副本部署在其他服务器,满足故障和负载均衡的要求。
**Redis 主从复制(Master-Slave Replication)**是一种数据同步机制,允许将一台 Redis 服务器(主节点,Master)的数据复制到其他 Redis 服务器(从节点,Slave)。主从复制在 Redis 中广泛用于数据冗余、读写分离、故障恢复和高可用性架构。

在实际业务场景之中,读操作往往比写操作更加频繁,主从模式,主要是针对"读操作"进行 并发量&可用性的提高
核心概念
主节点(Master)
-
负责处理客户端的写操作(
SET
,DEL
等)。 -
数据变更后,主节点将写命令异步发送给从节点。
-
每个 Redis 实例默认都是主节点。
从节点(Slave)
-
复制主节点的数据,默认只处理读操作(
GET
等)。 -
可以配置为级联复制(从节点作为其他从节点的主节点)。
-
一个主节点可以有多个从节点。
可读
默认情况下,从节点使用 slave-read-only=yes 配置为只读模式。即使修改此处为no,允许从节点进行写操作修改,由于复制只能从主节点到从节点,对于从节点的任何修改主节点都无法感知,修改从节点会造成主从数据不一致。所以建议线上不要修改从节点的只读模式。
传输延迟
主从节点一般部署在不同机器上,复制时的网络延迟就成为需要考虑的问题,Redis为我们提供了 repl-disable-tcp-nodelay 参数用于控制是否关闭 TCP_NODELAY(TCP内部的nagle算法),默认为 no,即开启 tcp-nodelay功能,说明如下:
当关闭 时,主节点产生的命令数据无论大小都会及时 地发送给从节点,这样主从之间延迟会变小,但增加了网络带宽的消耗。适用于主从之间的网络环境良好的场景,如同机房部署。
当开启时,主节点会合并较小的TCP 数据包从而节省带宽。默认发送时间间隔取决于Linux的内核,一般默认为 40 毫秒。这种配置节省了带宽但增大主从之间的延迟。适用于主从网络环境复杂的场景,如跨机房部署。
拓扑结构
一主一从
最简单的模式,用于数据备份和读写分离。
一主多从
主节点处理写操作,多个从节点分担读负载。

树状结构(级联复制)
从节点可以作为其他从节点的主节点,降低主节点压力。
例如:Master -> Slave1 -> Slave2
。
Slave1仍然是从节点,无法进行写操作,只是作为了slave2节点同步数据的来源

此结构主节点无需 一主多从 结构那么高的网卡带宽,但是一旦数据进行修改,同步的传输延时比其要更长
配置主从复制
1. 静态配置(redis.conf)
在从节点的配置文件中添加:
bash
slaveof <master-ip> <master-port> # 指定主节点地址
masterauth <password> # 如果主节点有密码
注意:daemonsize要设置为 yes(允许后台运行)
2. 动态配置(运行时命令)
通过 Redis 命令动态设置主从关系:
bash
# 在从节点上执行:
SLAVEOF 192.168.1.100 6379 # 将该节点设置为某个主节点的从节点
SLAVEOF NO ONE # 停止复制,恢复为主节点
示例:一主一从
bash
# 主节点(端口 6379)
redis-server --port 6379
# 从节点(端口 6380)
redis-server --port 6380 --slaveof 127.0.0.1 6379
配置成功后

注意:
如果使用 service redis-server start 启动的 redis 则同样要使用 service redis-server stop 来终止redis ,使用kill -9 会自动重启
基本流程

配置从节点 :在从节点(slave 6380
)上通过 slaveof 127.0.0.1 6379
命令配置主节点(master 6379
)的 IP 和端口 ,让从节点知道主节点位置。
保存主节点信息:从节点接收配置命令后,保存主节点的地址信息,如 IP、端口等,为后续连接做准备。
主从建立连接:从节点根据保存的主节点信息,主动与主节点建立网络连接-TCP,搭建起主从通信链路。(TCP的三次握手是为了通信双方能正常读写数据)
发送 ping 命令:连接建立后,从节点向主节点发送 ping 命令,用于检测主节点是否可达,以及检查网络连接状态是否正常 。
权限验证:若主节点设置了访问密码,从节点需进行权限验证,提供正确密码才能继续后续操作,保证数据安全。
以上都为准备操作,下面为主从复制的主要操作
同步数据集 :验证通过后,从节点向主节点发送同步请求,主节点执行 bgsave
命令生成 RDB 文件并发送给从节点,从节点接收并加载 RDB 文件,将数据恢复到自身,实现数据的初次同步 。
命令持续复制:初次同步完成后,主节点会将后续接收到的写命令持续发送给从节点,从节点执行这些命令,保证主从节点数据的实时一致性。
数据同步psync
redis提供了psync命令,去完成数据同步的过程,此命令不需要我们手动执行,再建立好主从关系之后,会自动执行
java
PSYNC replicationid offset

- 从节点发送 psync 命令给主节点,replid 和 offset 的默认值分别是?和 -1.
- 主节点根据 psync 参数和自身数据情况决定响应结果:
- 如果回复 +FULLRESYNC replid offset,则从节点需要进行全量复制流程。
- 如果回复 +CONTINUE,从节点进行部分复制流程。
- 如果回复 -ERR,说明 Redis 主节点版本过低,不支持 psync 命令。从节点可以使用 sync 命令进行全量复制。
- psync 一般不需要手动执行. Redis 会在主从复制模式下自动调用执行.
- sync 会阻塞 redis server 处理其他请求. psync 则不会.
查看主从结构信息
bash
info replication


断开主从结构

断开与主节点的复制关系,不会丢弃原有数据,只是无法再从主节点上获取到数据变化
此处的修改是临时性的,如果重新启动该服务,仍然会按照最初在配置文件设置的内容来建立主从关系
replicationid
也叫 replid
,是用于标识主节点身份的唯一标识符 ,是主节点自动生成的(从节点升级为主节点也会生成,且主节点每次重启生成的replicationid都是不同的)。描述数据的来源
其中,replicationid2 一般是用不到,可以用于因网络波动的原因导致从节点升级为主节点生成的replicationid会取代原先的位置,而此时replicationid2会记录之前的replicationid,后续可以据此重新建立主从关系--哨兵机制会自动完成这个过程
offset
即复制偏移量 ,以字节为单位。
主节点每处理一个写命令,就将命令的字节长度累加到 master_repl_offset
,它表示主节点已向从节点发送了多少字节的数据,体现主节点的写入进度 ;
从节点接收并执行主节点传来的写命令后,也会累加更新 slave_repl_offset
,代表从节点的复制进度。
这两个参数共同描述了一个**数据集,**当这两个数据相同,表示数据状态是一致的,并且同步状态良好
主从复制分为两个阶段:全量复制 (初次同步)和 增量复制(持续同步)。
全量复制(Full Resynchronization)

当从节点首次连接主节点或复制关系中断后需要重新同步时触发:
-
从节点发送 psync 命令给主节点进行数据同步,由于是第一次进行复制,从节点没有主节点的运行 ID 和复制偏移量,所以发送 psync ? -1。
-
主节点根据命令,解析出要进行全量复制,回复 +FULLRESYNC 响应。
-
从节点接收主节点的运行信息进行保存。
-
主节点执行 bgsave 进行 RDB 文件的持久化。(防止传输的RDB文件为旧文件)
-
主节点发送 RDB 文件给从节点,从节点保存 RDB 数据到本地硬盘。
-
主节点将从生成 RDB 到接收完成期间执行的写命令,写入缓冲区中,等从节点保存完 RDB 文件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的二进制格式追加写入到收到的 rdb 文件中.保持主从一致性。
-
从节点清空自身原有旧数据。
-
从节点加载 RDB 文件得到与主节点一致的数据。
-
如果从节点加载 RDB 完成之后,并且开启了 AOF 持久化功能,它会进行 bgrewrite 操作,得到最近的 AOF 文件。
全量复制的无磁盘复制 (diskless)
默认情况下,进行全量复制需要主节点生成 RDB 文件到主节点的磁盘中,再把磁盘上的 RDB 文件通过发送给从节点。
Redis 从 2.8.18 版本开始支持无磁盘复制。主节点在执行 RDB 生成流程时,不会生成 RDB 文件到磁盘中了,而是直接把生成的 RDB 数据通过网络发送给从节点。这样就节省了一系列的写硬盘和读硬盘的操作开销(但实际上,由于全量复制需要大规模数据的网络传输,因此整个操作还是比较重的)。
注意 部分资料会把 runId 和replicationid混淆,但是通过源码阅读可知,run id
是一个随机生成的,他的主要作用是支持哨兵机制的,并不在主从复制功能起到一定作用
部分复制(Partial Resynchronization)

1)当主从节点之间出现网络中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并终端复制连接。
2)主从连接中断期间主节点依然响应命令,但这些复制命令都因网络中断无法及时发送给从节点,所以暂时将这些命令滞留在repl-backing-buffer(是内存中一个基于数组构成的环形队列,会记录一段时间修改的数据,随着时间的推移会删除之前的旧数据)复制积压缓冲区中。
3)当主从节点网络恢复后,从节点再次连上主节点。
4)从节点将之前保存的 replicationId 和 复制偏移量作为 psync 的参数发送给主节点,请求进行部分复制。
5)主节点接到 psync 请求后,进行必要的验证。随后根据 offset 去复制积压缓冲区查找合适的数据,并响应 +CONTINUE 给从节点。
6)主节点将需要从节点同步的数据发送给从节点,最终完成一致性。
实时复制
全量复制完成后,主节点持续将新的写命令发送给从节点:
实时同步
主节点每执行一个写命令,就异步将该命令发送给所有从节点。从节点接收并执行这些命令,保持数据同步。
在进行实时复制的时候,需要保证连接处于可用状态
心跳包机制
主节点:默认,每隔 10s 给从节点发送一个 ping 命令。从节点收到就返回 pong
从节点:默认,每隔 1s 就给主节点发起一个特定的请求,就会上报当前从节点复制数据的进度 (offset)
关键配置参数
参数 | 说明 |
---|---|
repl-backlog-size |
复制积压缓冲区大小(影响断线后增量复制能力) |
repl-timeout |
复制超时时间(默认 60 秒) |
min-slaves-to-write |
主节点至少需要 N 个从节点连接才允许写操作 |
min-slaves-max-lag |
从节点最大延迟时间(秒) |
局限性
异步复制
主从节点数据同步是异步的,从节点数据可能短暂落后(最终一致性)。且当从节点数量增多,复制数据的延时会非常明显
主节点单点故障
主节点宕机后,从节点不能自动升级,需手动切换从节点为主节点,非常繁琐(需配合 Sentinel 或 Cluster 实现自动故障转移)。
Redis的哨兵机制--自动对挂了的主节点进行替换
补充
主从节点断开连接的情况有两种
1)主动修改redis的组成结构,通过slave no one,这种情况 从节点会自动升级为主节点
2)主节点挂掉后,需要通过人工干预
欲变世界,先变其身。 ------圣雄甘地
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸