主从复制原理
🔴 困难题目描述
解释 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 # 缓冲区 TTL2. 监控延迟
# 实时监控
redis-cli --latency-distinct -i 1
# 或使用 INFO
redis-cli INFO replication | grep lag3. 读写分离
# 主节点:写操作
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 # 延迟增大