Redis 主从复制详细解析
一、主从复制核心概念
1. 本质与特点
- 单向数据流:数据只能从主节点(Master)流向从节点(Slave)。
- 异步复制:主节点写入后立即响应客户端,后台异步同步到从节点。
- 读写分离:主节点处理写请求,从节点默认只读(
replica-read-only yes
)。
2. 核心作用
作用 | 说明 |
---|---|
数据冗余 | 实现热备份,是RDB/AOF之外的额外数据保护层。 |
故障恢复 | 主节点宕机时可手动/自动(哨兵)提升从节点为主节点。 |
负载均衡 | 读多写少场景下,通过多个从节点分担读负载(需客户端支持读写分离)。 |
高可用基石 | 为哨兵和集群模式提供底层复制能力。 |
二、主从复制全流程
1. 建立复制关系
- 保存主节点信息:从节点配置
replicaof
后记录主节点IP和端口。 - 建立Socket连接:从节点内部定时任务(每秒1次)检测到新主节点后发起连接。
- 发送PING命令:
- 检测网络连通性。
- 检测主节点是否可处理命令(如主节点正在加载数据会返回LOADING错误)。
- 权限验证:若主节点设置
requirepass
,从节点需配置masterauth
对应密码。 - 数据同步:分为全量复制和部分复制(见下文详解)。
- 命令持续复制:同步完成后,主节点通过复制积压缓冲区持续发送写命令。
2. 数据同步机制
(1)全量复制(初次同步)
- 发送 psync 命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行 ID,所以发送 psync-1。
- 主节点根据 psync-1 解析出当前为全量复制,回复+FULLRESYNC 响应。
- 从节点接收主节点的响应数据保存运行 ID 和偏移量 offset
- 主节点执行 bgsave 保存 RDB 文件到本地
- 主节点发送 RDB 文件给从节点,从节点把接收的 RDB 文件保存在本地并直接作为从节点的数据文件
- 对于从节点开始接收 RDB 快照到接收完成期间,主节点仍然响应读写命令,因此主节点会把这期间写命令数据保存在复制客户端缓冲内,当从节点加载完 RDB 文件后,主节点再把缓冲区内的数据发送给从节点,保证主从之间数据一致性。
- 从节点接收完主节点传送来的全部数据后会清空自身旧数据
- 从节点清空数据后开始加载 RDB 文件
- 从节点成功加载完 RDB 后,如果当前节点开启了 AOF 持久化功能, 它会立刻做 bgrewriteaof 操作,为了保证全量复制后 AOF 持久化文件立刻可用。
- 触发场景:
- 从节点首次连接主节点。
- 从节点复制偏移量(offset)不在主节点的复制积压缓冲区范围内。
- 风险点:
- 主节点内存峰值:bgsave fork可能引发短暂阻塞(建议关闭THP)。
- 网络带宽占用:大数据量时RDB传输可能影响业务。
(2)部分复制(断点续传)
- 当主从节点之间网络出现中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并中断复制连接
- 主从连接中断期间主节点依然响应命令,但因复制连接中断命令无法发送给从节点,不过主节点内部存在的复制积压缓冲区,依然可以保存最近一段时间的写命令数据,默认最大缓存 1MB。
- 当主从节点网络恢复后,从节点会再次连上主节点
- 当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行 ID。因此会把它们当作 psync 参数发送给主节点,要求进行部分复制操作。
- 主节点接到 psync 命令后首先核对参数 runId 是否与自身一致,如果一 致,说明之前复制的是当前主节点;之后根据参数 offset 在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送+CONTINUE 响应,表示可以进行部分复制。
- 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。
- 核心依赖:
- 复制积压缓冲区:主节点维护的环形队列(默认1MB),存储最近写命令。
- 主从RunID匹配:确保从节点之前连接的是当前主节点。
- 优化建议:
- 调大
repl-backlog-size
(如512MB)以适应网络抖动。
- 调大
三、主从复制问题与解决方案
Redis的主从复制是一种重要的数据复制机制,用于实现数据备份、读写分离等功能,但在实际应用中会面临一些问题,以下是对上述文档中主从复制相关问题及解决方案的详细解释:
数据不一致
- 原因:Redis主从复制默认是异步复制方式。主节点在处理写命令后,会立即将结果返回给客户端,同时将写命令异步发送给从节点。这就导致在某些情况下,从节点可能还未及时接收到并执行主节点发送的写命令,从而出现从节点数据滞后于主节点的情况,进而造成数据不一致。
- 监控手段:
redis - cli info replication
命令用于获取Redis复制相关的信息。其中master_repl_offset
表示主节点已复制的偏移量,它会随着主节点处理写操作而不断增加;slave_repl_offset
表示从节点已复制的偏移量。通过对比这两个值的差值,就可以知道从节点数据滞后的程度。例如,差值为20表示从节点比主节点滞后20字节的数据。 - 解决方案:
- 强一致性:
WAIT
命令可以让客户端阻塞,直到指定数量的从节点完成数据同步。WAIT 1 5000
表示客户端会等待,直到至少1个从节点将主节点发送的写命令同步完成,或者等待时间超过5秒。这样能确保在一定程度上数据的强一致性,但会影响客户端的响应速度,因为客户端需要等待同步完成。 - 最终一致性:通过监控
slave_repl_offset
与master_repl_offset
的差值,设置一个合理的阈值。当差值超过该阈值时,说明从节点滞后过多,可能会影响业务数据一致性,此时可以触发告警,提醒运维人员进行处理。这种方式虽然不能保证实时一致性,但能保证数据在一定时间后趋于一致,满足大多数对一致性要求不是极高的场景。
- 强一致性:
脑裂问题(Split - Brain)
- 现象:当网络出现分区故障时,从节点可能无法与主节点通信。如果此时 Sentinel(哨兵)系统未能及时准确判断主节点故障,或者在判断主节点故障后,网络又恢复正常,就可能出现原主节点和被哨兵提升为新主节点的从节点同时存在且都可写的情况,即多个主节点同时写入数据。
- 危害:由于两个“主节点”都能接受写操作,对于同一个key,可能在不同主节点上被修改为不同的值。当网络恢复正常,进行数据合并时,就会产生数据冲突,导致数据不一致,严重影响数据的准确性和完整性。
- 解决方案:
- 哨兵模式:Sentinel通过
quorum
配置来确定主节点是否真正故障。quorum
表示至少需要多少个哨兵节点认为主节点不可达,才会触发故障转移。只有多数哨兵确认主节点故障,才会进行从节点升级等操作,这样可以减少因网络短暂波动等原因导致的误判,降低脑裂问题发生的概率。 - min - slaves配置:
min - slaves - to - write 1
表示主节点至少需要有1个从节点连接,才会接受写入操作。min - slaves - max - lag 10
表示从节点的复制延迟不能超过10秒,否则主节点将拒绝写入。通过这种配置,当主节点发现没有合格的从节点(如从节点数量不足或复制延迟过高)时,就会拒绝写请求,从而避免脑裂情况下原主节点继续写入导致数据冲突。
- 哨兵模式:Sentinel通过
读写分离陷阱
- 问题:在读写分离场景下,从节点用于处理读请求。但如果从节点与主节点同步出现问题,如网络中断、主节点负载过高导致同步延迟等,从节点上的数据可能就不是最新的,可能会读取到过期数据。另外,在一些特殊情况下,如Redis的键过期策略处理不及时等,也可能导致从节点返回脏数据。
- 规避方法:
- 从节点配置
replica - serve - stale - data no
后,当从节点与主节点的同步中断或复制延迟过高时,会拒绝处理读请求,这样可以避免客户端读取到过期或脏数据,但可能会影响部分读请求的可用性。 - 客户端可以采取策略,优先从主节点读取数据,对于一些允许有一定延迟的查询,如统计类查询、历史数据查询等,再交由从节点处理。这样可以在保证关键数据读取准确性的同时,充分利用从节点分担读压力的功能。
- 从节点配置
总结
- 主从复制是Redis高可用的基础,通过异步复制实现数据冗余和读写分离。
- 全量复制用于初始化同步,部分复制优化断网恢复后的效率。
- 脑裂问题需通过
min-slaves
和哨兵机制规避,数据一致性依赖监控与WAIT命令。 - 生产环境中建议结合哨兵或集群模式,构建完整的高可用架构。