3. 主从复制原理与搭建

Redis 主从复制是构建高可用集群的第一块基石。它的目标很明确:让一个或多个从节点(replica)持续跟随主节点(master)的数据变化,从而获得一份可读、可备份、可接替的副本。理解主从复制,关键要抓住两条链路——首次建立时的全量同步,以及稳定运行后的增量同步,而连接这两条链路的枢纽,就是复制积压缓冲区(repl_backlog)。

一、全量同步:从节点第一次“补齐家底”

当从节点第一次连接主节点,或断线太久、增量数据已被覆盖时,就会触发全量同步。其核心过程如下:

  1. 从节点发送 PSYNC ? -1,表示“我没有主节点信息,请给我全量数据”。
  2. 主节点执行 BGSAVE 生成 RDB 快照文件,同时把生成期间新收到的写命令缓存到复制缓冲区(注意:这是每个从节点独立的输出缓冲区,与全局的 repl_backlog 不同)。
  3. 主节点把 RDB 文件发送给从节点,从节点先清空自身旧数据,再加载 RDB。
  4. RDB 加载完成后,主节点再把期间缓存的写命令发送给从节点,从节点执行这些命令,追平到主节点当前状态。

全量同步的代价是明显的:一次 RDB 生成会带来 fork 开销和磁盘/网络传输压力。因此,应尽量避免频繁触发全量同步,这正是增量同步和复制积压缓冲区存在的意义。

二、增量同步与复制积压缓冲区

增量同步依赖三个关键量:复制偏移量(offset)、主节点运行 ID(run_id)和复制积压缓冲区(repl_backlog)。

主节点每执行一个写命令,就会把命令追加到 repl_backlog 中,并递增自己的 offset;从节点每收到并执行一个命令,也递增自己的 offset。当从节点短暂断线重连后,会发送 PSYNC <run_id> <offset>。主节点判断:

  • 如果 run_id 匹配,且从节点请求的 offset 仍然落在 repl_backlog 的范围内,则只把缺失的那部分命令发过去——这就是部分重同步(partial resync)。
  • 如果 run_id 不匹配,或 offset 已被积压缓冲区“挤出去”,则退化为全量同步。

因此,repl_backlog 的大小直接决定了从节点能容忍多长的断线时间。它由两个参数控制:repl-backlog-size(默认 1MB)和 repl-backlog-ttl(默认 3600 秒,表示最后一个从节点断开后积压缓冲区保留多久)。

估算积压缓冲区大小的经验公式:repl-backlog-size ≥ 平均写入速率(字节/秒)× 预计最长断线秒数。例如主节点平均写入 2MB/s,希望容忍 60 秒断线,则至少应设为 120MB,并留出一定余量。

三、主从配置步骤

下面以“一主一从”为例,给出可复现的配置过程。假设主节点端口 6379,从节点端口 6380,均在同一台机器上演示。

# 主节点 redis-master.conf 关键项
port 6379
bind 0.0.0.0
daemonize yes
appendonly yes
repl-backlog-size 64mb
repl-backlog-ttl 3600

# 从节点 redis-replica.conf 关键项
port 6380
bind 0.0.0.0
daemonize yes
appendonly yes
replicaof 127.0.0.1 6379
replica-read-only yes
replica-priority 100

启动两个实例后,在从节点执行 INFO replication,应看到 role:slave、master_link_status:up、master_last_io_seconds_ago 很小;在主节点执行 INFO replication,应看到 connected_slaves:1 以及从节点的 offset 信息。此时在主节点写入 SET k1 v1,在从节点读取 GET k1 应能立即得到 v1,说明复制链路已正常工作。

若需要动态调整,可在运行时执行 REPLICAOF host port 建立复制,或执行 REPLICAOF NO ONE 断开复制并提升为独立节点。

四、常见问题排查

现象可能原因排查与处理
master_link_status:down网络不通、端口未放行、主节点未启动用 redis-cli -h host -p port ping 验证连通性,检查防火墙与 bind 配置
频繁全量同步repl_backlog 太小,断线后 offset 已越界调大 repl-backlog-size,观察 sync_full 与 sync_partial_ok 计数
从节点数据落后很多主节点写入过快、从节点执行慢或网络带宽不足查看 master_repl_offset 与从节点 offset 差值,必要时增加从节点资源或限流
从节点内存暴涨输出缓冲区积压(client-output-buffer-limit)检查 client_longest_output_list,调整 client-output-buffer-limit replica
主节点 fork 阻塞明显RDB 生成频繁、实例内存过大控制单实例内存规模,避免频繁全量同步,必要时拆分实例

排查时最有效的入口是 INFO replication 中的几个字段:master_link_status、master_last_io_seconds_ago、master_sync_in_progress、slave_repl_offset 与 master_repl_offset 的差值。它们能快速告诉你链路是否健康、是否正在全量同步、以及落后了多少。

Redis 主从复制:全量同步与增量同步链路 主节点 Master (6379) 写命令 → 递增 master_repl_offset repl_backlog(环形缓冲区) BGSAVE → RDB 快照 从节点 Replica (6380) 加载 RDB → 清空旧数据 执行缓存命令 → 追平 offset slave_repl_offset 持续递增 ① 全量同步 RDB 文件传输 ② 增量同步 PSYNC run_id offset 复制积压缓冲区 repl_backlog 判定逻辑 run_id 匹配? offset 在缓冲区内? 部分重同步 是 是 任一条件不满足 → 退化为全量同步 全量同步 增量同步 部分重同步成功 回退全量

把这张图记在脑子里,主从复制的排障就有了主线:先看链路是否 up,再看是全量还是增量,最后看积压缓冲区是否够用。只要 offset 差值可控、repl_backlog 足够大,绝大多数“从节点掉队”问题都能被稳定收敛。