【Redis分布式】主从复制
🔥个人主页: 中草药
🔥专栏:【中间件】企业级中间件剖析
一、主从复制
在分布式系统之中为了解决单点问题(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)
在从节点的配置文件中添加:
slaveof <master-ip> <master-port> # 指定主节点地址
masterauth <password> # 如果主节点有密码
注意:daemonsize要设置为 yes(允许后台运行)
2. 动态配置(运行时命令)
通过 Redis 命令动态设置主从关系:
# 在从节点上执行:
SLAVEOF 192.168.1.100 6379 # 将该节点设置为某个主节点的从节点
SLAVEOF NO ONE # 停止复制,恢复为主节点
示例:一主一从
# 主节点(端口 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命令,去完成数据同步的过程,此命令不需要我们手动执行,再建立好主从关系之后,会自动执行
PSYNC replicationid offset
- 从节点发送 psync 命令给主节点,replid 和 offset 的默认值分别是?和 -1.
- 主节点根据 psync 参数和自身数据情况决定响应结果:
- 如果回复 +FULLRESYNC replid offset,则从节点需要进行全量复制流程。
- 如果回复 +CONTINUE,从节点进行部分复制流程。
- 如果回复 -ERR,说明 Redis 主节点版本过低,不支持 psync 命令。从节点可以使用 sync 命令进行全量复制。
- psync 一般不需要手动执行. Redis 会在主从复制模式下自动调用执行.
- sync 会阻塞 redis server 处理其他请求. psync 则不会.
查看主从结构信息
info replication
断开主从结构
断开与主节点的复制关系,不会丢弃原有数据,只是无法再从主节点上获取到数据变化
此处的修改是临时性的,如果重新启动该服务,仍然会按照最初在配置文件设置的内容来建立主从关系
replicationid
也叫 replid
,是用于标识主节点身份的唯一标识符 ,是主节点自动生成的(从节点升级为主节点也会生成,且主节点每次重启生成的replicationid都是不同的)。描述数据的来源
其中,replicationid2 一般是用不到,可以用于因网络波动的原因导致从节点升级为主节点生成的replicationid会取代原先的位置,而此时replicationid2会记录之前的replicationid,后续可以据此重新建立主从关系--哨兵机制会自动完成这个过程
offset
即复制偏移量 ,以字节为单位。
主节点每处理一个写命令,就将命令的字节长度累加到 master_repl_offset
,它表示主节点已向从节点发送了多少字节的数据,体现主节点的写入进度 ;
从节点接收并执行主节点传来的写命令后,也会累加更新 slave_repl_offset
,代表从节点的复制进度 。
这两个参数共同描述了一个数据集,当这两个数据相同,表示数据状态是一致的,并且同步状态良好
主从复制分为两个阶段:全量复制(初次同步)和 增量复制(持续同步)。
全量复制(Full Resynchronization)
当从节点首次连接主节点或复制关系中断后需要重新同步时触发:
1) 从节点发送 psync 命令给主节点进行数据同步,由于是第一次进行复制,从节点没有主节点的运行 ID 和复制偏移量,所以发送 psync ? -1。
2) 主节点根据命令,解析出要进行全量复制,回复 +FULLRESYNC 响应。
3) 从节点接收主节点的运行信息进行保存。
4) 主节点执行 bgsave 进行 RDB 文件的持久化。(防止传输的RDB文件为旧文件)
5) 主节点发送 RDB 文件给从节点,从节点保存 RDB 数据到本地硬盘。
6) 主节点将从生成 RDB 到接收完成期间执行的写命令,写入缓冲区中,等从节点保存完 RDB 文件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的二进制格式追加写入到收到的 rdb 文件中.保持主从一致性。
7) 从节点清空自身原有旧数据。
8) 从节点加载 RDB 文件得到与主节点一致的数据。
9) 如果从节点加载 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)主节点挂掉后,需要通过人工干预
欲变世界,先变其身。 ——圣雄甘地
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸