3. 主从复制原理与搭建
Redis 主从复制是构建高可用集群的第一块基石。它的目标很明确:让一个或多个从节点(replica)持续跟随主节点(master)的数据变化,从而获得一份可读、可备份、可接替的副本。理解主从复制,关键要抓住两条链路——首次建立时的全量同步,以及稳定运行后的增量同步,而连接这两条链路的枢纽,就是复制积压缓冲区(repl_backlog)。
一、全量同步:从节点第一次“补齐家底”
当从节点第一次连接主节点,或断线太久、增量数据已被覆盖时,就会触发全量同步。其核心过程如下:
- 从节点发送
PSYNC ? -1,表示“我没有主节点信息,请给我全量数据”。 - 主节点执行
BGSAVE生成 RDB 快照文件,同时把生成期间新收到的写命令缓存到复制缓冲区(注意:这是每个从节点独立的输出缓冲区,与全局的 repl_backlog 不同)。 - 主节点把 RDB 文件发送给从节点,从节点先清空自身旧数据,再加载 RDB。
- 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 秒,表示最后一个从节点断开后积压缓冲区保留多久)。
三、主从配置步骤
下面以“一主一从”为例,给出可复现的配置过程。假设主节点端口 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 的差值。它们能快速告诉你链路是否健康、是否正在全量同步、以及落后了多少。
把这张图记在脑子里,主从复制的排障就有了主线:先看链路是否 up,再看是全量还是增量,最后看积压缓冲区是否够用。只要 offset 差值可控、repl_backlog 足够大,绝大多数“从节点掉队”问题都能被稳定收敛。