导航菜单

主从复制原理

🔴 困难

题目描述

解释 Redis 主从复制的原理。全量同步和增量同步有什么区别?

示例操作

# 主节点配置
port 6379
daemonize yes

# 从节点配置
port 6380
daemonize yes
replicaof 127.0.0.1 6379

# 查看复制状态
INFO replication

# 主节点输出
# role:master
# connected_slaves:1
# slave0:ip=127.0.0.1,port=6380,state=online,offset=100,lag=0

# 从节点输出
# role:slave
# master_host:127.0.0.1
# master_port:6379
# master_link_status:up

提示

  • 全量同步:发送 RDB 文件
  • 增量同步:发送写命令
  • 复制偏移量:记录同步位置
  • 复制缓冲区:暂存写命令

解法

参考答案 (3 个标签)
主从复制 全量同步 增量同步

复制流程

1. 建立连接

# 从节点执行
REPLICAOF 127.0.0.1 6379

# 内部流程
1. 从节点保存主节点信息
2. 从节点建立与主节点的连接
3. 从节点发送 PING,检测主节点是否可用
4. 从节点发送认证信息(如果需要)
5. 从节点发送监听端口
6. 从节点发送 SYNC 请求同步

2. 全量同步

# 触发条件
- 从节点首次连接主节点
- 从节点复制偏移量丢失
- 复制缓冲区溢出

# 同步流程
主节点                    从节点
   |                          |
   |        PING             |
   |<-------------------------|
   |        PONG             |
   |------------------------->|
   |        SYNC             |
   |<-------------------------|
   |    fork 子进程           |
   |        RDB              |
   |------------------------->|
   |    发送写命令            |
   |------------------------->|
   |                         |  加载 RDB
   |                         |  执行写命令
   |                         |  同步完成

3. 增量同步

# 触发条件
- 从节点有部分数据
- 复制偏移量在复制缓冲区内

# 同步流程
主节点                    从节点
   |                          |
   |    PSYNC <offset>        |
   |<-------------------------|
   |  检查 offset             |
   |  在缓冲区内?            |
   |  YES: 发送增量           |
   |  NO: 全量同步            |
   |    发送写命令            |
   |------------------------->|
   |                         |  执行写命令
   |    继续发送命令          |
   |------------------------->|

关键概念

复制偏移量(Replication Offset)

# 主节点维护
master_repl_offset: 1000

# 从节点维护
slave_repl_offset: 1000

# 作用
# 记录主节点发送的命令字节数
# 用于判断增量同步是否可行

复制缓冲区(Replication Buffer)

# 主节点维护
repl_backlog_active: 1
repl_backlog_size: 1048576  # 1MB
repl_backlog_first_byte_offset: 1000
repl_backlog_histlen: 1000

# 作用
# 暂存主节点的写命令
# 支持部分同步(增量)

运行 ID(Run ID)

# 主节点 ID
run_id: 0123456789abcdef0123456789abcdef

# 作用
# 判断主节点是否变更
# 如果 run_id 变化,强制全量同步

扩展:主从延迟

延迟原因

# 1. 网络延迟
# 主从之间网络延迟

# 2. 全量同步
# 从节点首次同步,需要加载 RDB

# 3. 主节点压力
# 主节点处理大量写操作,从节点处理不过来

# 4. 复制缓冲区溢出
# 从节点处理慢,复制偏移量超出缓冲区

# 查看延迟
INFO replication
# slave_lag_seconds: 10  # 从节点延迟 10 秒

解决方案

1. 优化复制缓冲区

# 增大缓冲区
repl-backlog-size 10mb  # 默认 1mb
repl-backlog-ttl 3600   # 缓冲区 TTL

2. 监控延迟

# 实时监控
redis-cli --latency-distinct -i 1

# 或使用 INFO
redis-cli INFO replication | grep lag

3. 读写分离

# 主节点:写操作
redis-cli -h master -p 6379 SET key value

# 从节点:读操作
redis-cli -h slave -p 6380 GET key

# 注意:可能读到旧数据

哨兵机制

Sentinel 原理

# Sentinel 配置
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 30000

# 故障检测
1. Sentinel 定期 PING 主节点
2. 主节点超时(down-after-milliseconds)
3. Sentinel 标记主节点为主观下线
4. 多数 Sentinel 确认,标记为客观下线
5. 选举 Leader Sentinel
6. Leader 执行故障转移

故障转移

# 步骤
1. 从节点中选出新主节点(复制偏移量最大)
2. 其他从节点复制新主节点
3. 通知客户端新主节点地址
4. 原主节点恢复后,作为从节点

实战案例

案例 1:主从切换

# 场景:主节点故障
# Sentinel 自动切换

# 原主节点(127.0.0.1:6379)
# 从节点 1(127.0.0.1:6380)
# 从节点 2(127.0.0.1:6381)

# 切换前
# master: 127.0.0.1:6379
# slaves: 127.0.0.1:6380, 127.0.0.1:6381

# 切换后
# master: 127.0.0.1:6380
# slaves: 127.0.0.1:6381, 127.0.0.1:6379

# 查看切换
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 127.0.0.1
# 6380

案例 2:主从延迟监控

# 脚本监控延迟
#!/bin/bash
while true; do
    lag=$(redis-cli -p 6380 INFO replication | grep slave_lag_seconds | awk -F: '{print $2}')
    echo "$(date): Lag $lag seconds"
    sleep 1
done

# 输出
# 2024-01-01 10:00:00: Lag 0 seconds
# 2024-01-01 10:00:01: Lag 0 seconds
# 2024-01-01 10:00:02: Lag 5 seconds  # 延迟增大

搜索