Appearance
主从复制详解
一、主从复制的定义与核心作用
主从复制是Redis实现数据冗余、读写分离和高可用的基础机制:
- 主节点(Master):负责处理写操作(如
SET、DEL),并将写操作同步给从节点。 - 从节点(Slave/Replica):负责处理读操作(如
GET),从主节点同步数据,默认只读(slave-read-only yes)。
核心作用:
- 数据冗余:从节点保存主节点的副本,防止单点故障导致数据丢失。
- 读写分离:主节点处理写请求,从节点处理读请求,提高系统吞吐量(适合读多写少场景)。
- 高可用基础:当主节点宕机时,从节点可通过哨兵(Sentinel)或集群(Cluster)晋升为新主节点,保证服务连续性。
二、主从复制的核心原理
主从复制的本质是主节点将写操作同步给从节点,分为初始化同步(全量复制)和增量同步两个阶段。为了实现高效同步,Redis引入了复制偏移量、运行ID、积压缓冲区等关键组件。
1. 关键概念铺垫
在讲解同步流程前,需先理解以下核心概念:
复制偏移量(Replication Offset):
- 主节点(
master_repl_offset)和从节点(slave_repl_offset)各自维护一个字节偏移量,记录已处理的命令字节数。 - 主节点每发送1字节命令,偏移量+1;从节点每收到1字节命令,偏移量+1。
- 作用:通过对比主从偏移量,判断从节点是否落后(如主偏移量1000,从偏移量800,说明从节点落后200字节)。
- 主节点(
运行ID(Run ID):
- 每个Redis实例启动时生成的唯一标识符(如
d4f4a1b2...)。 - 作用:从节点重连时,通过运行ID判断是否为同一个主节点(若主节点重启,运行ID会变化,需重新全量复制)。
- 每个Redis实例启动时生成的唯一标识符(如
积压缓冲区(Replication Backlog Buffer):
- 主节点维护的环形缓冲区(默认1MB,可通过
repl-backlog-size配置),保存最近的写命令。 - 作用:当从节点重连时,若其偏移量在缓冲区范围内,可通过缓冲区中的命令实现增量复制(避免全量复制)。
- 主节点维护的环形缓冲区(默认1MB,可通过
复制缓冲区(Replication Buffer):
- 主节点为每个从节点维护的临时缓冲区,保存即将发送给从节点的命令。
- 作用:全量复制时,主节点生成RDB文件的同时,将写命令存入复制缓冲区,待RDB发送完成后,再将缓冲区中的命令发送给从节点(保证数据完整性)。
2. 初始化同步(全量复制)
当从节点首次连接主节点或重连时无法进行增量复制(如运行ID变化、偏移量超出积压缓冲区范围),会触发全量复制,流程如下:
mermaid
sequenceDiagram
participant 从节点(Slave)
participant 主节点(Master)
从节点->>主节点: 发送PING命令(确认连通性)
主节点->>从节点: 返回PONG(连通)
从节点->>主节点: 发送AUTH命令(若主节点有密码)
主节点->>从节点: 返回OK(认证通过)
从节点->>主节点: 发送PSYNC ? -1(请求同步,?表示未知运行ID,-1表示全量复制)
主节点->>从节点: 返回FULLRESYNC <runid> <offset>(通知全量复制,携带主节点运行ID和当前偏移量)
主节点->>主节点: 执行BGSAVE(后台生成RDB文件,不阻塞主进程)
主节点->>主节点: 将BGSAVE期间的写命令存入**复制缓冲区**(避免数据丢失)
主节点->>从节点: 发送RDB文件(从节点接收并保存)
从节点->>从节点: 清空当前数据库(`FLUSHDB`/`FLUSHALL`)
从节点->>从节点: 加载RDB文件(阻塞,直到加载完成)
主节点->>从节点: 发送复制缓冲区中的命令(从节点执行,追上BGSAVE期间的写操作)
从节点->>主节点: 进入增量同步阶段(后续写命令实时同步)全量复制的开销:
- 主节点:
BGSAVE需要CPU和内存(生成RDB),发送RDB需要网络带宽。 - 从节点:加载RDB需要IO和CPU(阻塞服务)。
- 优化:尽量避免频繁全量复制(如合理设置积压缓冲区大小)。
3. 增量同步(实时同步)
全量复制完成后,主节点会将所有写命令(如SET、DEL)实时同步给从节点,保持主从数据一致,流程如下:
mermaid
sequenceDiagram
participant 主节点(Master)
participant 从节点(Slave)
主节点->>主节点: 执行写命令(如`SET key value`)
主节点->>主节点: 更新`master_repl_offset`(偏移量+命令字节数)
主节点->>主节点: 将命令写入**复制缓冲区**(每个从节点一个)
主节点->>主节点: 将命令写入**积压缓冲区**(公共环形缓冲区)
主节点->>从节点: 发送命令(通过TCP连接)
从节点->>从节点: 执行命令(如`SET key value`)
从节点->>从节点: 更新`slave_repl_offset`(与主节点偏移量一致)增量同步的关键逻辑:
- 主节点通过复制缓冲区向从节点发送命令(每个从节点独立,避免相互影响)。
- 主节点通过积压缓冲区保存最近的命令(供从节点重连时使用)。
4. 重连时的增量复制(PSYNC命令)
当从节点因网络问题断开连接,重连时会发送PSYNC命令(PSYNC <runid> <offset>),主节点根据以下逻辑判断是否进行增量复制:
mermaid
flowchart TD
A[从节点发送PSYNC <runid> <offset>] --> B{主节点runid是否匹配?}
B -->|否| C[返回FULLRESYNC,全量复制]
B -->|是| D{从节点偏移量是否在积压缓冲区范围内?}
D -->|是| E[返回CONTINUE,增量复制(发送缓冲区中从<offset>到当前偏移量的命令)]
D -->|否| C[返回FULLRESYNC,全量复制]判断条件说明:
- runid匹配:确保重连的是同一个主节点(若主节点重启,runid变化,需全量复制)。
- 偏移量在积压缓冲区范围内:积压缓冲区的起始偏移量≤从节点偏移量≤主节点当前偏移量(说明缓冲区保存了从节点缺失的命令,可增量复制)。
三、主从复制的关键机制与参数
1. 异步复制
Redis主从复制是异步的:主节点发送命令后,无需等待从节点确认,即可继续处理下一个请求。这种设计提高了主节点的吞吐量,但会导致从节点延迟(即从节点数据落后于主节点)。
延迟优化:
- 设置
repl-disable-tcp-nodelay no(默认):主节点发送命令时,立即通过TCP发送(不合并),减少延迟(但增加网络包数量)。 - 若网络带宽有限,可设置
repl-disable-tcp-nodelay yes:合并多个命令一起发送(减少网络包),但增加延迟。
2. 只读从节点
从节点默认只读(slave-read-only yes),防止从节点写入数据导致主从不一致。若需从节点写入(如特殊场景),可修改配置,但不推荐。
3. 积压缓冲区配置
repl-backlog-size:积压缓冲区大小(默认1MB)。建议设置为“主节点1分钟内的写命令字节数”(如主节点每分钟写10MB,设置为10MB),确保从节点重连时偏移量在缓冲区范围内。repl-backlog-ttl:积压缓冲区的存活时间(默认3600秒)。当没有从节点连接时,主节点会在repl-backlog-ttl秒后清空缓冲区(释放内存)。
4. 从节点优先级
slave-priority(默认100):当主节点宕机时,哨兵会选择优先级最低的从节点晋升为新主节点(优先级越低,越优先)。若设置为0,该从节点不会被晋升为主节点。
四、主从复制的拓扑结构
Redis支持多种主从拓扑结构,选择需根据业务场景:
- 一主一从:
- 最简单的结构,主节点处理写请求,从节点处理读请求。
- 适合小规模应用(如个人项目)。
- 一主多从:
- 主节点连接多个从节点(如1主5从),从节点分担读压力。
- 缺点:主节点需向多个从节点发送命令,网络开销大(适合读极多写少的场景)。
- 链式复制(树状结构):
- 主节点→从节点1→从节点2→…(从节点1作为从节点2的主节点)。
- 优点:减轻主节点的网络压力(主节点只需向从节点1发送命令,从节点1再向其他从节点发送)。
- 缺点:从节点2的延迟会比从节点1高(适合大规模集群)。
五、常见问题与优化
1. 全量复制频繁触发
原因:
- 从节点重连时,偏移量超出积压缓冲区范围(缓冲区太小)。
- 主节点重启(运行ID变化)。
- 从节点数量过多(主节点生成RDB的开销大)。
优化:
- 增大
repl-backlog-size(如设置为10MB)。 - 避免主节点频繁重启(如使用持久化机制,减少重启次数)。
- 使用链式复制(减少主节点的从节点数量)。
2. 从节点延迟过高
原因:
- 主节点写请求过多(从节点无法及时同步)。
- 网络带宽不足(主节点发送命令缓慢)。
- 从节点性能差(如CPU、内存不足,无法及时执行命令)。
优化:
- 优化主节点写请求(如合并批量写操作)。
- 提升网络带宽(如使用千兆网卡)。
- 升级从节点硬件(如增加CPU核心、内存)。
- 设置
repl-disable-tcp-nodelay no(减少命令发送延迟)。
3. 主从数据不一致
原因:
- 异步复制:主节点宕机时,从节点未收到最新命令。
- 从节点写入数据(
slave-read-only no)。 - 主节点持久化失败(如
RDB生成失败,重启后数据丢失)。
优化:
- 使用哨兵或集群(实现高可用,当主节点宕机时,快速切换到从节点)。
- 开启主节点持久化(
appendonly yes,确保数据不丢失)。 - 禁止从节点写入(
slave-read-only yes)。
六、总结
Redis主从复制的核心原理是:
- 全量复制:初始化从节点数据(通过RDB文件)。
- 增量复制:实时同步主节点的写命令(通过复制缓冲区和积压缓冲区)。
- 高效同步:通过复制偏移量(判断数据是否一致)、运行ID(判断是否为同一主节点)、积压缓冲区(避免全量复制)等机制,减少同步开销。
主从复制是Redis实现高可用和** scalability**的基础,结合哨兵(Sentinel)或集群(Cluster),可构建 robust 的分布式系统。
参考命令:
- 查看主从状态:
info replication(主从节点都可执行)。 - 设置从节点:
slaveof <master-ip> <master-port>(从节点执行,Redis 5.0后改为replicaof)。 - 取消从节点:
slaveof no one(从节点执行,变为独立节点)。
参考配置:
- 主节点:
bind 0.0.0.0(允许远程连接)、requirepass <password>(设置密码)。 - 从节点:
replicaof <master-ip> <master-port>(设置主节点地址)、masterauth <password>(主节点密码)、slave-read-only yes(只读)。
