1. 揭开Redis主从复制的面纱:从一条命令说起
先抛个问题:Redis单机性能再强,也有扛不住的时候。缓存雪崩、磁盘损坏、机房断电,任何一个故障都可能导致整个业务链路直接瘫痪。这时候你会想到什么?主从复制。没错,就是那个被无数人挂在嘴边,但真正理解其内部机制的人并不多的Redis高可用基石。
提到Redis主从复制,绝大多数人第一反应是执行一句SLAVEOF命令,然后从节点就开始同步数据了。这事儿看起来简单到令人发指——主节点写,从节点跟着抄一份。但如果你真的以为主从复制只是“把数据拷贝一份”这么简单,那后面遇到同步延迟、数据不一致、增量同步失效、全量同步风暴这些生产事故时,你会连排查方向都没有。
我之前在维护一套生产环境的Redis集群时,就遇到过这么个事儿:某天下午某台从节点因为网络抖动断连了大概一分钟,重连之后本以为它会自动增量同步补齐数据,结果日志里赫然出现了全量同步的字样。当时我就愣住了——斷連才一分钟,怎么就触发全量同步了?后来深挖才发现是复制积压缓冲区(Backlog)太小,复制流的偏移量已经超出了缓冲区范围,主节点只能无奈地放弃增量同步,直接走全量同步流程。那一分钟,积压缓冲区的数据被新的写入覆盖掉,而出于某种原因,从节点发来的偏移量在主节点看来已经“过期”了,于是触发全量同步。那一次事故让我意识到,主从复制背后还有太多值得解剖的细节。
这篇文章我想从头到尾把这些细节讲透:不只讲SLAVEOF怎么用,更要把 Redis 主从复制背后的运行机制挖出来——RunID 到底起什么作用、Backlog 又是如何决定增量同步能否成功、复制偏移量怎么计算、主从握手经历了哪些阶段、断线重连后增量同步的触发条件到底是什么。文章里没有什么高深莫测的理论,全都是我从实战和源码阅读中提炼出来的经验。无论你是刚入门的 Redis 使用者,还是已经在维护生产集群的工程师,这篇文章都能给你一些参考价值。
2. 主从复制整体架构:到底是“复制”还是“备份”?
2.1 一主多从的拓扑结构
先理清楚一个概念:Redis 的主从复制并不是传统意义上的“双机热备”,而是一主多从的结构。主节点(Master)负责处理写请求,从节点(Slave)负责复制主节点的数据,同时可以对外提供读服务。这种拓扑结构最直接的收益就是读写分离——把读流量分摊到多个从节点上,减轻主节点的压力。
生产环境里我见过不少团队把主从复制当成“数据备份”来用,其实这是不严谨的。主从复制解决的核心问题是数据冗余和读扩展,但它不等于持久化备份。如果主节点出现了物理故障,比如磁盘整个坏了,你不可能靠从节点找回在复制过程中丢失的数据,因为主从复制是异步的,这意味着主节点上已写入但还没来得及传播到从节点的数据,在故障发生时就是永久丢失了。
所以,一个成熟的Redis高可用方案里,主从复制通常与持久化(RDB + AOF)配套使用。先保住数据不丢,再用主从复制实现故障转移和读扩展。两者各司其职,缺一不可。
2.2 全量同步与增量同步的适用场景
Redis 主从复制看起来只有两种方式:全量同步和增量同步。但实际面试和文档里,这两个术语对应着更细分的三类过程:
- 全量同步:从节点第一次连接主节点,或者复制流严重断档时,主节点生成RDB快照发送给从节点,从节点加载RDB完成初始数据对齐。
- 增量同步:从节点已经有一部分数据、只是落后于主节点少量偏移量时,主节点将复制积压缓冲区内积压的写命令流发送给从节点,从节点继续追加执行,追平偏移量。
- 部分重同步(也可以看作增量同步的具体实现):断线重连后,从节点带上自己的复制偏移量请求主节点继续同步,主节点判断偏移量仍然在自己的Backlog有效范围内,于是仅发送断连期间积压的写命令。
很多人以为全量同步只发生在第一次建立主从关系时,其实不是。只要主节点的repl_backlog缓冲区中不包含从节点请求的偏移量之后的数据,主节点就会强制退化到全量同步。这也就是我在开头提到的那次事故的根源所在。
说个更通俗的类比:全量同步就像你要和同事对齐一份文档,你们俩手里的版本差得太多,索性把最新版整个发过去覆盖一遍;增量同步就像你们俩的版本只差了几行修改,只需要把这几处变更传过去合并一下就完事。Backlog 就是主节点上那个“最近若干条修改记录”的暂存区,它决定了你们的版本差能不能通过“传变更记录”的方式弥补。
2.3 为什么说主从复制是异步的
Redis 默认的主从复制是异步复制——主节点处理完写命令后,直接返回客户端结果,不会等待从节点确认。这个设计在性能上极为高效,但也引入了一个副作用:主从切换时,可能会有少量数据差异。
实际生产中,这个问题表现为“主从切换后的数据回滚”。举个例子,客户端写入了一个key,主节点已经返回OK,但从节点还没来得及复制这条命令,这时候主节点宕机,哨兵把从节点提升为新主节点,那这条命令就在新主上消失了。对某些业务来说这是不可接受的。
Redis 也提供了一定程度的缓解手段,比如配置min-replicas-to-write和min-replicas-max-lag——只有当从节点数量足够多且延迟足够低时,主节点才接受写请求,否则直接拒绝写入。这种方式本质上是用牺牲可用性的代价来换取数据一致性,需要结合业务场景来权衡。
3. RunID:主从复制的身份标识,缺了它就乱套
3.1 RunID 是什么,从哪里来
RunID 是 Redis 主节点在启动时生成的随机标识符,一个 40 位十六进制字符串,本质上是用来唯一标识一次“主节点运行周期”的。每次主节点重启,这个ID都会改变。
从节点的视角来看,RunID 决定了它当前跟随的是不是“同一个主节点”。这个机制非常重要:如果主节点重启,RunID 变化,从节点就会识别出主节点已经不是之前那个实例,进而重新发起全量同步。
为什么 RunID 变化了就一定要全量同步?原因在于,主节点重启后,它不知道自己重启期间从节点接收了哪些数据,也无法确认从节点的复制偏移量是否还与自己一致(尤其主节点重启前可能还有未持久化的写命令)。为了保证数据一致性的底线,Redis 选择了最保险的方式——全量重来。
3.2 RunID 在主从握手过程中的角色
先来看主从复制的握手流程,一次完整的初始同步大致经历以下阶段:
- 从节点保存主节点的
host和port,建立 socket 连接。 - 从节点发送
PING命令,主节点响应PONG,确认网络通畅且主节点服务正常。 - 从节点携带自己的配置信息执行
REPLCONF listening-port <port>,告诉主节点自己的监听端口。 - 从节点发送
REPLCONF capa eof capa psync2,声明自己支持的复制能力(比如支持PSYNC协议)。 - 从节点执行
PSYNC <runid> <offset>,其中runid是从节点记忆中的主节点ID,offset是它当前的复制偏移量。 - 主节点检查
runid和offset,决定返回FULLRESYNC(触发全量同步)还是CONTINUE(增量同步)。
RunID 在第 5 步中的作用非常关键。当从节点发送PSYNC时,携带的runid如果是第一次连接,从节点不知道主节点ID,会传?。主节点收到?后,直接判定为“不认识这个从节点”,必然会走全量同步。
如果从节点之前已经同步过,它会记录主节点的 RunID。断线重连后再次发送PSYNC,主节点拿这个 RunID 和自身当前 RunID 做比对:
- 一致:主节点进一步检查复制偏移量是否落在自己的 Backlog 区间内,是则增量同步,否则全量同步。
- 不一致:主从之间的历史关联已不复存在,主节点直接发起全量同步。
这里有个容易忽略的坑:有些运维同学在排查问题时会手动RESTART主节点,也不提前通知从节点。主节点重启后 RunID 变了,从节点重连时PSYNC携带的旧 RunID 对不上,主节点只能触发全量同步。如果主节点数据量大(比如 50GB),这个全量同步过程会持续很久,期间主节点还要同时处理RDB生成的I/O开销和网络传输带宽占用,业务侧往往会出现明显的延迟抖动。
3.3 主节点重启后如何避免全量同步
如果你需要重启主节点,但又希望从节点不要做全量同步,Redis 提供了一个很实用的配置项:repl-id和repl-backlog的配合。
实际上,Redis 在持久化 RDB 文件时,会把当前复制状态(RunID、Master 复制偏移量)一并写入。这样即使主节点正常重启,它也能够恢复这些信息——前提是你没有丢失持久化文件。
具体来说,主节点在恢复时,如果 RDB 文件里包含了repl-id和repl-offset,那么它可以把这些状态重新加载到内存中。从节点再次发送PSYNC时,主节点发现自己恢复出来的 RunID 和从节点记录的 RunID 还是一致的,复制偏移量也有对应关系,于是可能直接就进入增量同步状态,避免了一次沉重的全量同步。
所以我在生产环境里,除非万不得已,不会动不动就去动主节点的持久化文件。配置项的调整、运行参数的修改,能通过热变更解决的就优先热变更,只有那种必须重启的场景才去重启,并且会提前确认持久化配置正确、RDB/AOF 文件完好。
4. Backlog 复制积压缓冲区:增量同步的命脉
4.1 Backlog 到底是什么
Backlog 是主节点维护的一块固定大小的环形内存缓冲区,专门用于保存最近产生的写命令数据。它的大小由repl-backlog-size配置项指定,默认是 1MB。
可以这样理解:主节点每次收到一条写命令,除了执行之外,还会把这条命令追加到复制积压缓冲区中。这个缓冲区是环形的,当数据写满之后,最早的数据会被覆盖。所以它的本质是一个有容量的滑动窗口,保存的是“最近一段时间内产生的写命令流”。
所以说白了,Backlog 的容量决定了主节点可以容忍的“从节点断连时间上限”。如果从节点断连期间,主节点产生的写命令总量没有超过 Backlog 大小,那么从节点重连后就能通过增量同步追上进度。反过来,如果断连期间的写数据量超过了 Backlog 大小,最早的复制数据就被覆盖了,那么从节点重连后发现自己需要的偏移量已经不在缓冲区里了,主节点只能无奈地选择全量同步。
4.2 复制偏移量(offset)的计算机制
复制偏移量是 Redis 主从复制中衡量进度一致性的核心指标。主节点和从节点各自维护一个 offset:
- 主节点每发送一个字节的写命令流给从节点,它的 offset 就递增相应的字节数。
- 从节点每接收并执行一个字节的写命令流,它的 offset 也递增相应的字节数。
正常情况下,主从节点的 offset 保持一致,或者相差很小。如果从节点因为网络问题暂时断连,它的 offset 就会落后于主节点。重连时,从节点带着自己的 offset 向主节点请求增量数据,主节点判断这个 offset 是否还在 Backlog 的存储范围内。
这里有一个最常见的误判案例:主节点写入量非常大,比如每秒产生几百KB的写命令,而repl-backlog-size只有默认的 1MB。那么这个 Backlog 的窗口时间可能只有几秒钟。从节点只要断连超过几秒,重连时就极大概率触发全量同步。
我在线上排查类似问题时,第一步就是看监控面板里主节点的repl_backlog_active和从节点的master_repl_offset两个指标。通过对比这两个值,能快速判断出增量同步失败是不是因为 Backlog 太小。一般我会建议将 Backlog 调大到 64MB~128MB 甚至更高,但前提是主节点的内存要扛得住这个额外开销。
4.3 Backlog 参数调优的实操建议
很多运维同学不喜欢动repl-backlog-size,因为默认值 1MB 用得好好的,何必去改?但现实是,默认值在绝大多数有一定写入量的业务场景里都不够用。
调优时我一般会这么算:
- 统计业务高峰期 Redis 每秒写入的命令量(包括命令本身的字节数和参数大小)。
- 统计从节点可能断连的最长时间。比如网络故障导致的断连,一般恢复时间在几十秒到几分钟。
- 估算公式:
BacklogSize ≈ 每秒写入字节数 × 断连恢复最大时长 × 1.5(安全余量)。
举个例子,一个业务高峰期每秒产生 200KB 左右的写命令,从节点断连恢复最长可能需要 5 分钟,那么BacklogSize至少应该设置为200KB × 300s = 60MB,再乘上安全系数 1.5,就是 90MB。考虑到内存成本和风险平衡,我个人会直接设成 128MB,省心。
注意:repl-backlog-size设置得过大也不是没有代价的。Backlog 是常驻内存的缓冲区,如果你把三个主节点各自配了 256MB 的 Backlog,内存成本也不容忽视。当然这比起全量同步带来的CPU飙升、网络拥堵、业务抖动来说,还是划算得多。
4.4 查看和监控 Backlog 使用状态
现场应急的时候,我们可以通过以下命令快速查看当前复制的健康状况:
127.0.0.1:6379> INFO replication输出里主要关注这几个字段:
role:当前节点角色(master/slave)。connected_slaves:已连接的从节点数量。master_replid:主节点当前 RunID。master_repl_offset:主节点当前复制偏移量。repl_backlog_size:Backlog 配置大小。repl_backlog_active:Backlog 是否启用。repl_backlog_first_byte_offset:Backlog 中最早一字节数据的偏移量。repl_backlog_histlen:Backlog 中实际存储的数据字节数。
如果master_repl_offset与repl_backlog_first_byte_offset之间的差值接近repl_backlog_size,说明 Backlog 很快会被写满,断连的从节点重连后大概率触发全量同步。
5. PSYNC 协议演进:从 SYNC 到 PSYNC 再到 PSYNC2
5.1 老古董 SYNC:一次断连就全量
在很早的 Redis 版本里,只有SYNC命令。从节点每次请求同步,主节点都会执行一次全量同步——生成RDB、传输、加载。这个设计在今天看来非常粗暴,因为一旦从节点断线重连,哪怕只是断了 1 秒,也要全量重来一遍。要知道 RDB 生成是 CPU 和内存双密集操作,在数据量大时会显著影响主节点性能。
所以后来的版本引入了PSYNC,实现了部分重同步。这也是现代 Redis 主从复制能稳定工作的关键机制。
5.2 PSYNC 的工作流程与关键参数
PSYNC的核心优势在于,从节点可以带着自己的复制偏移量请求增量数据。如果主节点的 Backlog 中仍然包含从节点需要的复制数据,就回复CONTINUE,然后开始从对应偏移量开始发送积压数据。如果 Backlog 中已经不包含对应的数据,主节点回复FULLRESYNC,并附上新的 RunID 和偏移量,从节点清空旧数据,进入全量同步。
从节点的重连逻辑发生在replconf阶段之后,具体是一个简短的时序:
- 从节点重连主节点,完成 TCP 连接。
- 从节点发送
REPLCONF相关命令,把自己伪装成一个新连接。 - 从节点发送
PSYNC <master_replid> <offset>,开始协商同步方式。 - 主节点根据 RunID 和 offset 判断,返回
CONTINUE或FULLRESYNC。
这里有一个细节值得注意:从节点发出的offset是它自己记录的slave_repl_offset,这个值可能因为从节点在主节点发生故障转移后的角色切换而变得不准确。因此在某些情况下,从节点会发送PSYNC ? -1,强制主节点进行全量同步。这在从节点本身状态不完整时是合理的行为。
5.3 PSYNC2 解决了什么问题
Redis 4.0 引入了 PSYNC2,它的核心改进是支持“主从角色互换后的部分重同步”。什么意思呢?考虑这样一个场景:
- 主节点 A 和从节点 B 保持同步。
- A 发生故障,哨兵把 B 提升为新主节点。
- 原先的从节点 C 本来和 A、B 都在同一个复制拓扑中,A 故障后 C 需要重新同步到 B。
- 如果没有 PSYNC2,C 的 RunID 记忆和 B 的 RunID 不一致,C 只能做全量同步。
- 有了 PSYNC2,Redis 会记录“复制历史”中的 RunID 与偏移量之间的关系,B 可能识别出 C 请求的偏移量正好落在自己的复制历史中,于是直接做增量同步。
这个设计对故障转移场景非常实用——它大幅减少了主从切换后的全量同步次数,缩短了恢复时间。实际生产里,每次主从切换如果都触发全量同步,对整体可用性影响极大,PSYNC2 是这一痛点的重要缓解手段。
6. 主从复制的完整流程拆解:从握手到稳定复制
6.1 建立连接的握手阶段
把主从复制的过程串联起来看,初始同步主要分为三个阶段:连接建立、全量同步、命令传播。
连接建立阶段,从节点设置主节点的信息后,尝试建立 socket 连接。连接成功后,从节点会以模拟客户端的身份发送一系列命令,完成握手:
PING REPLCONF listening-port <port> REPLCONF capa eof capa psync2 PSYNC <replid> <offset>PING 的目的很简单——验证主节点活着且网络通畅。如果主节点响应超时,从节点会不断重试,直到建立连接。REPLCONF 阶段主要是把从节点自己的端口号告诉主节点,方便主节点执行INFO replication时展示从节点信息。
我遇到过一种情况:主从之间跨机房部署,防火墙只开放了主节点的 6379 端口,但没有开放从节点的监听端口。TCP 连接能建立,但 PING、REPLCONF 之后可能会莫名其妙地中断,因为主节点需要回连从节点端口做某些数据交换。最终排查发现是防火墙把回连的端口拦了。这类网络层面的问题,排查起来最耗时,但也最基础。
6.2 全量同步的内部过程
全量同步是整个复制流程中开销最大的阶段:
- 主节点收到
PSYNC请求,判定需要全量同步。 - 主节点回复
FULLRESYNC <replid> <offset>,把当前 RunID 和偏移量发给从节点。 - 主节点在后台触发
bgsave,生成 RDB 快照文件。 - RDB 生成期间,主节点仍然持续接收写命令,并将写命令缓冲到复制客户端缓冲区中。
- RDB 生成完成后,主节点将 RDB 文件发送给从节点。
- 从节点清空自己的旧数据,加载 RDB 文件。
- RDB 加载完成后,主节点把缓冲期间积压的写命令发送给从节点。
- 从节点执行这些命令,最终和主节点的数据保持一致。
整个过程中,有一个容易踩的坑:主节点向从节点发送 RDB 文件时,如果 RDB 文件很大(比如 20GB+),网络传输时间会很长。而网络传输 RDB 并不是一个流的——“全量同步期间的写命令缓冲”会一直堆积在主节点的输出缓冲区里。如果写命令非常多,输出缓冲区可能会爆掉,触发主节点的保护机制,直接断开与从节点的连接,最终同步失败。
针对这个问题,Redis 提供了client-output-buffer-limit slave 256mb 64mb 60这样的配置,适当调大从节点的输出缓冲区限制。但这个值不宜无脑调大,否则主节点内存会被大量积压的写命令撑爆。
6.3 命令传播与心跳机制
全量同步完成之后,主从之间的关系就进入了命令传播阶段。主节点每执行一条写命令,除了写入数据本身,还会把命令广播给所有从节点。从节点顺序执行这些命令,维持数据与主节点一致。
另外,主从之间还有心跳机制:
- 主节点每隔 10 秒向从节点发送
PING,探测从节点是否存活。 - 从节点默认每隔 1 秒向主节点发送
REPLCONF ACK <offset>,上报自己的复制偏移量。
心跳机制的价值在于:主节点通过从节点上报的 offset,可以感知到从节点的复制延迟。如果某个从节点的延迟超过了配置的阈值(如min-replicas-max-lag 10),主节点可以配合min-replicas-to-write拒绝写请求,避免数据不一致扩大化。
7. 常见问题与排查技巧实录
7.1 从节点断线重连后频繁全量同步
这是最常见的问题,也是开头提到的那个事故的主要场景。排查步骤我通常是这样走的:
- 先看主节点
INFO replication中的repl_backlog_first_byte_offset和master_repl_offset,确认 Backlog 是否已被写满覆盖。 - 看从节点的
master_repl_offset落后主节点多少。如果差值接近 Backlog 大小,那问题基本就定位了。 - 调大
repl-backlog-size,观察后续是否还有全量同步触发。
调参时直接在命令里执行:
127.0.0.1:6379> CONFIG SET repl-backlog-size 128mb这个操作是热生效的,但为了持久化,记得同步修改配置文件。否则主节点重启后参数会恢复到默认值。
7.2 从节点数据与主节点不一致
从节点数据不一致一般有两种可能:
- 复制延迟导致从节点暂时落后,属于正常现象,等追平即可。
- 程序逻辑问题,比如业务侧直接连到从节点写了数据,或者有人在从节点上执行了非只读命令。
排查时可以用INFO replication对比主从的 offset。如果从节点的延迟长期存在,且延迟量有增大趋势,优先怀疑网络带宽瓶颈或从节点自身性能问题。另外,从节点尽量开启slave-read-only yes,保证它不会接收到外部写请求。
7.3 主从同步延迟较大
命令传播阶段的主从延迟主要受网络往返时间影响。跨地域部署时,延迟会比较明显。解决思路无非是:
- 尽量避免主从跨地域部署,实在避免不了就考虑使用基于本地数据中心的同城主从结构。
- 如果业务对一致性要求较高,可以使用 Redis 的
WAIT命令阻塞等待从节点确认,但需要注意WAIT会阻塞主节点后续命令的处理,对性能有影响。
7.4 从节点一直处于 SYNC 状态
排除网络和配置问题后,一个容易忽略的原因是repl-diskless-sync配置不当。Redis 支持 diskless 全量同步,即不通过 RDB 文件落盘,而是直接在内存中生成快照流发送给从节点。如果repl-diskless-sync-delay设置过大,主节点可能会等待多个从节点同时请求全量同步后才统一开始,导致部分从节点一直停留在等待状态。
排查时可以看主节点的日志,是否有Waiting for bgthread to start之类的信息。调小repl-diskless-sync-delay或改为repl-diskless-sync no,一般就能解决。
7.5 主节点内存中 Backlog 占用过高
如果确认 Backlog 使用率高,但业务写入量并没有那么大,可以检查是否有多个从节点在同一时间请求全量同步。一个从节点全量同步时,其他从节点如果也跟着断线重连,可能会各自触发全量同步,导致主节点同时承担多份 RDB 生成和网络传输压力。此时可以设置repl-timeout和合理的从节点重连策略,避免同步风暴。
8. 主从复制在生产环境中的最佳实践与踩坑记录
8.1 配置清单参考
根据我维护生产环境的经验,一份合理的主从复制核心配置大致是这样的:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| repl-backlog-size | 64mb~128mb | 根据写入量、断连时长计算 |
| repl-backlog-ttl | 3600 | Backlog 释放前的等待时间 |
| repl-timeout | 60 | 主从连接超时时间,避免误判断连 |
| repl-diskless-sync | yes | 开启无盘同步,提高全量同步效率 |
| repl-diskless-sync-delay | 5 | 等待多从节点同时同步的窗口时间 |
| slave-read-only | yes | 强制从节点只读,防止数据被外部误写 |
| client-output-buffer-limit slave | 256mb 64mb 60 | 防止全量同步期间输出缓冲区溢出 |
| min-replicas-to-write | 1 | 主节点写保护,至少保持一个健康从节点 |
| min-replicas-max-lag | 10 | 从节点最大允许延迟秒数 |
这组配置不是万能的,需要根据业务实际情况调整。比如写入量特别大的业务,Backlog 可能需要 256MB 以上;而数据量很小、写入不频繁的业务,默认的 1MB 也未必是坑。
8.2 主从切换操作的正确姿势
主从切换是 Redis 运维的高风险操作,稍有不慎就会导致数据丢失或者长时间不可用。我总结的稳妥步骤:
- 提前备份主节点持久化文件。
- 检查所有从节点的复制延迟,确保延迟在可接受范围内。
- 在主节点上执行
CONFIG SET slave-read-only no(如果是提升某个从节点为新主节点)。 - 将从节点提升为主节点,执行
SLAVEOF NO ONE。 - 将其他从节点重新指向新的主节点。
- 更新原主节点为新主节点的从节点(或下线原主节点)。
整个切换过程中,最需要关注的是新主节点的数据完整性和其他从节点的复制起点。如果切换前从节点复制延迟过高,切换后会有部分数据丢失,业务侧必须有相应的补偿机制。
8.3 数据同步延迟的监控指标
监控是运维的眼睛。主从复制相关的监控指标,我重点看这几个:
master_repl_offset:主节点当前写入进度。slave_repl_offset:从节点当前复制进度。master_link_status:主从连接状态,up表示正常,down表示断连。slave_lag:从节点秒级延迟。
搭建告警时,我会把主从连接断开的告警级别设为 P1 级,即需要立即处理的严重告警。对于slave_lag超过一定阈值的从节点,设立 P2 级告警,先监控观察,持续上升再升级处理。
9. 个人实践经验总结
在多次排查 Redis 主从复制问题之后,我最大的体会是:很多所谓“诡异”的现象,本质上都是对基础机制理解不透彻导致的。比如 RunID 变化引发全量同步,Backlog 太小引发全量同步,这些只要我们提前把这些机制吃透,设计之初就把参数配置好,绝大多数事故根本不会发生。
另外,我个人的习惯是每配置好一套主从复制,都会在测试环境做一次从节点断连与重连演练,手动杀进程、模拟网络抖动,观察重连后是走增量还是全量。这种演练虽然费时间,但远比线上出事后再慌忙排查来得踏实。
还有一个容易被忽略的点:主从复制的日志分析。Redis 主节点的日志里其实记录了完整的同步事件,比如Partial resynchronization request from xxx accepted. Sending backlog(增量同步成功)和Full resync requested by slave(全量同步开始)。生产环境务必开启足够级别的日志,并且做好日志归档,出了事故才好回溯。
主从复制是 Redis 高可用的根基,把这个根基打牢了,后面做哨兵、集群、故障转移都会省心很多。希望这篇文章能把你在 Redis 主从复制上的“最后一公里”打通,至少下次再遇到全量同步风暴时,你能第一时间想到去检查 RunID 和 Backlog,而不是一脸懵地重启主节点。