ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Redis主从复制原理详解:从全量同步到生产实践

Redis主从复制原理详解:从全量同步到生产实践 “Redis 主从复制原理”这六个字在面试题里出现的频率有多高不用我多说。但说实话很多资料把它讲成一句话主节点负责写从节点负责读。等你真把一主两从的架构搭进生产环境会发现这句话根本撑不住场面——为什么从节点只是断了几分钟恢复后主节点 CPU 飙到90%为什么明明网络没断从节点的复制偏移量却长时间不动为什么从节点连得好好的读到的缓存还是旧值“Redis 主从复制”背后是一整套状态机、缓冲区、异步协议和故障恢复机制不是一句“读写分离”能带过的。这篇文章我想把主从复制的原理从头串一遍从握手、全量同步、部分重同步到命令传播和数据一致性问题最后落到生产环境的配置治理、监控指标和几个我实际踩过的复制坑。无论是准备 Redis 面试题还是想在业务里做缓存治理、读写分离、高可用建设这篇都能直接抄作业。1. 单机 Redis 的短板主从复制到底解决的是哪一类问题先把问题摆清楚。单机 Redis 不是不能用而是有几个硬伤CPU 再强也只能用一个核处理命令读 QPS 高到一定程度就顶不住进程一挂缓存直接冷启动后端数据库瞬间被打满磁盘坏了、机器被回收内存里的数据连恢复的机会都没有。主从复制本质上就是在回答这三个问题分摊读请求、提供冗余副本、为故障转移铺路。1.1 三个关键业务场景第一类是读写分离。把写请求打到主节点把读请求分给从节点业务读多写少时效果立竿见影。我自己见过一个比较典型的数据看板系统写量不大读量是写的几十倍主节点一个线程处理不过来加了三个从节点之后主节点 CPU 从 85% 降到 30%。这就是主从复制最朴素的价值把单线程的 Redis 横向拉成多份读能力。第二类是故障转移的基础。Redis 的哨兵Sentinel模式就是靠监控主从节点的状态来做的自动切换。主节点挂了哨兵从一堆从节点里挑一个提升为新主节点整个过程依赖的就是“从节点手里有一份接近实时的数据副本”。没有复制就没有高可用切换的基础数据。第三类是数据备份与容灾。每天凌晨从节点做 BGSAVE 生成 RDB 快照比直接在主节点上做备份要安全得多——至少不会因为备份期间的磁盘 IO 拖慢主节点响应。异地容灾场景也常见主节点在一个可用区从节点放到另一个可用区主区整体断电时至少还有一份完整数据能顶上。1.2 主从复制解决不了的事这里必须先给预期“降降温”。主从复制只解决“数据从主节点流向从节点”的问题不解决以下问题脑裂后自动仲裁主节点和从节点之间的网络分区了业务还在写主节点哨兵又把某个从节点提升成了新主两边同时接受写入旧主恢复后数据怎么合并主从复制不管这事这是哨兵与分布式一致性要处理的难题。存储容量扩展主从只是把同一份数据复制多份不是分片。内存总容量没有任何增加数据量超过单机内存照样得靠 Redis Cluster 的分片机制。强一致性保证复制是异步的主节点写成功不代表从节点立刻有这中间存在天然延迟窗口。想靠纯主从做到“写主立即读从一致”从机制上就不现实。1.3 对“一致性”的预期校准很多刚接触 Redis 的同学会下意识认为主从复制了两边就应该每分钟都一模一样。真实情况是Redis 主从复制默认就是最终一致而且是“松最终一致”——正常情况下延迟可以压到毫秒级但网络抖一下、从节点在做 RDB 加载、或者主节点写吞吐突然暴涨时延迟会被瞬间放大到秒级甚至分钟级。我常用的一个类比是主节点像个直播主播从节点是观众主播说话观众通过直播流听到正常情况下延迟一两秒但网络一卡画面就会卡住甚至重新缓冲。“重新缓冲”对应到 Redis 就是全量重同步。理解了这个模型再去看后面的机制就不会跑偏。2. 建立复制链路从 REPLICAOF 到 PSYNC握手时到底交换了什么很多人一上来就敲命令却不知道从节点和主节点建立连接时背后其实是一套完整的握手协议。把这条链路的每个细节搞清楚你才能真正理解后面所有故障现象。2.1 最小可运行配置先给一份最基础的一主一从配置在从节点 redis.conf 里加上这几行# 声明主节点地址和端口 replicaof 10.0.0.5 6379 # 如果主节点开启了 requirepass这里要填主节点的密码 masterauth your-redis-password # 从节点默认只读强烈建议保持开启 replica-read-only yes也可以运行时临时生效不用重启进程redis-cli -p 6380 replicaof 10.0.0.5 6379Redis 5.0 之前这个命令叫 slaveof5.0 之后逐步换成了 replicaof语义上就强调“副本”关系。如果你的代码里还在用 SLAVEOF新版 Redis 依然兼容但新项目建议直接用 replicaof。配置完后到主节点执行INFO replication如果看到connected_slaves:1说明链路已经建立。2.2 握手协议拆解从节点建立连接不是发一条命令就完事的完整握手过程是这样的从节点发起 TCP 连接到主节点的 6379 端口。从节点发送PING确认主节点进程还活着、能正常响应命令。如果主节点开启了密码认证从节点发送AUTH完成身份认证。这里的密码就是前面配置里的masterauth不是从节点自己的 requirepass。从节点发送REPLCONF listening-port port告诉主节点“我在哪个端口监听”主节点会记录这个地址用于 INFO 输出和后续哨兵发现副本。从节点发送REPLCONF capa eof capa psync2这是能力协商告诉主节点“我支持 EOF 格式的 RDB 传输、支持新版 PSYNC 协议”。最后从节点发送PSYNC replid offset正式请求同步。这里面第 5 步很容易被忽略。capability协商的意义在于老版本 Redis 和新版本 Redis 的复制协议细节有差异如果不协商老主节点会按老逻辑走新从节点可能拿到无法识别的数据格式。生产环境主从版本不一致时很多诡异问题都出在这里。我的建议很简单主从版本尽量保持一致至少也要保证 Redis 4.0 以上因为 PSYNC2 带来的部分重同步能力是一个分水岭。2.3 复制 ID 与复制偏移量的核心作用握手最后一步里的replid和offset是整个复制机制最核心的两个概念。复制 IDreplid相当于主节点复制历史的“身份证号”一个 40 字符的随机十六进制字符串。主节点初次启动或从节点被提升为主节点时会生成新的复制 ID。复制偏移量offset从节点已经消费到的复制流字节数主节点每写一条命令偏移量就往后挪。它不是命令条数是累计的字节数。主从双方各自维护 offset从节点会通过REPLCONF ACK offset周期性回报自己的进度。所以判断主从落后多少最直接的办法就是比较两者的master_repl_offset和slave_repl_offset。2.4 为什么需要 replid2新老身份切换Redis 4.0 引入 PSYNC2 之后每个实例不再是单一复制 ID而是有一主一备两个复制 IDmaster_replid和master_replid2。这是为了解决一个非常现实的场景主节点挂掉某个从节点被哨兵提升为新主老主节点网络恢复后又回来当从节点此时新主节点手下的其他从节点可能还保留着老主节点的复制 ID。新主节点会把自己的master_replid换成新的同时把旧老主节点的复制 ID 存进master_replid2这样老主节点回来请求部分重同步时新主节点一看“你的 replid 是我记录的 replid2”就知道你是我之前的同源兄弟只要 offset 还在 backlog 里就能走增量不必让所有从节点从头再来一次全量同步。这个机制很不起眼但非常重要。没有它每次主从切换都可能引发所有节点集体全量重同步生产环境就是一次复制风暴。面试里如果能把 replid2 讲明白基本能看出你是真用过而不是背过。3. 全量同步当从节点什么都没有时主节点做了什么从节点第一次挂上来、或者主从断开太久导致 backlog 丢失时就会触发全量同步。这也是对主节点影响最大的一种同步方式很多线上故障都发生在这一环节。3.1 全量同步的完整生命周期一次全量同步拆开来看有六个关键阶段从节点发送PSYNC ? -1表示“我什么都不知道给我来份全量”。主节点返回FULLRESYNC replid offset把当前复制 ID 和偏移量发给从节点同时触发后台保存。主节点 fork 一个子进程子进程把内存中的数据生成 RDB 快照。主进程继续服务正常读写。在生成和传输 RDB 期间主进程收到的新写入命令会不断累积到复制积压缓冲区backlog里。RDB 生成完成后主节点把 RDB 文件发给从节点。从节点先清空自己原有的旧数据再把 RDB 加载进内存。从节点加载完 RDB 后主节点把 backlog 里累积的增量命令继续发给从节点从节点追上最新 offset同步完成。整个流程里有一个细节特容易误解从节点在加载 RDB 的这段时间它自己是阻塞的不会响应任何命令。如果从节点配置了replica-serve-stale-data yes默认值它会继续用旧数据对外服务如果配了no客户端会直接收到MASTERDOWN错误。很多业务把从节点当读缓存用却没想到全量同步期间从节点要么给旧数据、要么直接不可用这个窗口要提前做好预案。3.2 fork 生成 RDB 的代价为什么大实例全量同步会卡RDB 保存不是主进程自己在那里写磁盘而是 fork 一个子进程来做。看起来不影响主进程但这里有两个隐藏代价第一fork 瞬间需要复制父进程的页表内存越大fork 耗时越长。几十 GB 的 Redis 实例fork 一次可能要几百毫秒甚至几秒期间主进程短暂阻塞慢查询日志里会出现一条阻塞时间特别长的记录。第二子进程做 RDB 期间父进程的内存如果持续被修改Linux 的写时复制机制会让物理内存翻倍增长。极端场景下本来 20GB 的实例做一次全量同步让内存冲到 40GB直接把机器内存打满。所以全量同步不是“从节点自己吃点数据”这么轻描淡写而是会波及主节点的服务质量和整个机器的内存水位。这也是为什么我一直强调监控 Redis 实例内存的时候必须同时看 used_memory 和 RSS实际物理内存占用RSS 暴涨往往就是全量同步的征兆。3.3 全量传输的两种模式磁盘型与无盘同步全量同步传输 RDB 的方式在 Redis 2.8.18 之后有两种选择由repl-diskless-sync控制配置RDB 生成位置传输方式适用场景repl-diskless-sync no子进程写磁盘主节点读磁盘文件再发送从节点少、网络慢、磁盘快repl-diskless-sync yes子进程直接写套接字RDB 不落盘直接发给从节点从节点多、磁盘 IO 慢、希望减少磁盘写无盘同步的优势在于省掉了“写磁盘再读磁盘”两道 IO但缺点也明显从节点无法从磁盘上拿快照恢复主节点如果中途断连整个流程要重来。另外无盘同步默认有一个repl-diskless-sync-delay 5秒的等待窗口目的是让多个从节点一起同步时能复用同一份 RDB减少重复 fork。如果你的主节点从节点数量比较多我建议把无盘同步打开并且根据实际业务调整 delay。默认 5 秒是“再等等看有没有别的从节点来”如果你希望快速同步可以把它调小到 1-2 秒。3.4 全量同步风暴的成因“同步风暴”是 Redis 运维里最典型的故障之一它长这样一个主节点下面挂了五个从节点某个瞬间所有从节点几乎同时断开又重连触发全量同步。主节点被 fork 了五次RDB 同时生成五份内存翻好几倍网络带宽占满结果主节点自己先被打挂然后从节点再次重连再次全量整个集群雪崩。形成风暴的常见原因有三个主节点重启复制 ID 变化所有从节点被迫全量重同步。网络设备抖动所有从节点同时断线断线时间超过 backlog 容量部分重同步全部失效。批量发布或者批量重启从节点没有做错峰。对策也对应有三条主节点升级重启前评估复制 ID 影响调大repl-backlog-size让断线恢复尽量走增量从节点重启时手动错峰不要在同一个维护窗口里全部一起重启。另外主节点 maxmemory 触发大量淘汰时淘汰命令也会沉重地压到复制链路上这属于容易被忽略的隐性全量同步诱因——因为从节点处理不过来积压offset 差距越拉越大最终 backlog 被覆盖又退化成全量。4. 部分重同步断网恢复后如何用 backlog“接着聊”全量同步代价大所以 Redis 设计了一个轻量级的恢复方式部分重同步。理解它你就理解了为什么断线几秒和断线几小时的结局完全不同。4.1 断线恢复的两类结局当从节点与主节点断开连接时它本地不会丢失已经收到的数据只是复制偏移量停在了断线前的位置。等网络恢复从节点会重新发起握手然后向主节点发送PSYNC master_replid slave_repl_offset主节点收到后做判断如果你的复制 ID 和我的对得上而且你要求的偏移量离我不算太远我 backlog 里还有那段数据我就回复CONTINUE然后只把这期间的增量命令发给你这就是部分重同步。如果主节点发现复制 ID 对不上或者你的 offset 太旧、backlog 里的数据已经被覆盖了就只能回复FULLRESYNC老老实实再走一遍全量。同一个故障最终走的是增量还是全量完全取决于 backlog 里有没有覆盖断线时段的写入。4.2 backlog 缓冲区的环形结构backlog 是主节点上的一个环形缓冲区默认大小只有 1MB由repl-backlog-size控制。每一条写命令在主节点执行后会被追加进这个缓冲区也会发给所有从节点。因为它是环形结构新数据会覆盖旧数据所以它只能保存最近一段时间内的复制流。打个比方backlog 就像一个容量固定的电视录像带旧的节目会不断被覆盖。如果从节点断线太久它想补看的时段已经被覆盖了那对不起只能重新看全量。repl-backlog-size应该设多大我的经验公式很简单期望容忍断线秒数 × 峰值写入流量字节/秒 合理的 backlog 大小比如你期望断线 5 分钟内不要触发全量峰值写入在 2MB/s那 backlog 至少要300 × 2MB ≈ 600MB。当然这是理论值实际还要留 1.5-2 倍余量。很多生产事故就是这么来的默认 1MB 的 backlog业务写几下就填满了断线两分钟回来还想走增量结果直接全量主节点 CPU 瞬间被打满。另外有个repl-backlog-ttl 3600的配置含义是当没有任何从节点连接时backlog 最多保留 3600 秒。这个参数的意义是省内存如果所有从节点都断光了主节点没必要一直留着积压数据。4.3 部分重同步的完整判定过程把判定逻辑拆得更细一点从节点上报的复制 ID 与主节点当前master_replid一致如果不一致但刚好等于master_replid2且 offset 匹配也算一致——这就是主从切换后老从节点能接着续传的关键。从节点上报的 offset 必须落在 backlog 的有效范围内offset repl_backlog_first_byte_offset。如果 offset 比 backlog 最老的数据还早说明断线期间写入量太大断点已经被覆盖。以上两个条件同时满足主节点返回CONTINUE否则返回FULLRESYNC replid offset。从节点收到CONTINUE后会接着从断点处消费主节点发来的增量数据。对业务侧来说这次网络抖动几乎无感。4.4 offset 差太多为什么只能全量这个问题我经常拿来反问自己能不能让主节点再多存一些历史数据总可以从某些持久化文件里补答案是不能。因为主节点自己的复制流就只有 backlog 这么一份内存缓冲没有外部存储记录更早的命令流。从节点主动发行数据去别的源头的机制是有的——比如从节点可以先从另一个从节点同步 RDB但这是运维层面的手工方案不改变协议本身的限制。所以 offset 差太多只能全量这是机制决定的不是配置没调好。能做的只有把 backlog 调大、把断线恢复时间压缩、把网络稳定性提升尽量减少走到全量的概率。5. 命令传播和数据一致性为什么你会读到旧数据主从之间不可能永远靠 RDB 同步日常运行靠的是命令传播。理解了传播机制才算真正理解了主从复制的数据一致性边界。5.1 命令传播与 ACK 心跳全量同步完成后主节点会把每一条写命令SET、DEL、EXPIRE 等实时转发给所有从节点。从节点执行相同的命令后就和主节点保持了数据一致。这条链路上有一个重要的心跳机制从节点默认每隔一秒向主节点发送一次REPLCONF ACK offset告诉主节点“我已经执行到多少字节了”。主节点收到 ACK 后就能在INFO replication里计算出每个从节点的滞后情况。ACK 除了让主节点感知从节点状态还有一个看似不起眼的作用保证网络连接活跃防止长时间没有写入时 TCP 连接被中间设备断开。你观察 Redis 主从连接即使业务完全没有写流量链路上也会每秒有 ACK 包在走。如果你发现master_last_io_seconds_ago大于 10基本可以断定心跳出了问题。5.2 主节点的写缓冲和从节点的执行阻塞命令传播不是“主节点说一句话、从节点马上听到”这么简单。主节点对每个从节点都维护了一个独立的输出缓冲区写命令先进缓冲区再由网络层发送。如果从节点消费速度跟不上这个缓冲区的数据会越积越多最终可能触达上限client-output-buffer-limit replica 256mb 64mb 60这条配置的含义是对从节点类型的客户端如果缓冲持续超过 64MB 且在 60 秒内没有降到限制以下或者硬限制超过 256MB主节点会直接断开这个从节点。从节点执行速度跟不上最常见的原因是从节点上跑了慢命令。很多人觉得从节点只读就不会拖垮复制但复制过来的命令也要在从节点单线程里执行。如果从节点同时被业务用KEYS *、SMEMBERS大集合、或者BLPOP长时间阻塞了事件循环它处理复制命令的速度就会严重下降ACK 发得慢主节点输出缓冲区不断膨胀最终把自己断开。这个坑我踩过不止一次排查思路往往不是看网络而是看从节点的慢查询日志。5.3 过期键与驱逐策略主从不是同时删的这里有一个很容易被忽视的数据不一致来源过期键。主节点删除一个 key原因无非两种键到了 TTL 过期或者内存达到 maxmemory 被淘汰。无论哪种主节点在真正删除后都会往复制流里写一条 DEL 命令通知从节点删除。但反向不对从节点不会主动执行过期删除哪怕它本地时钟已经超过了 key 的 TTL。它只会等待主节点的 DEL 命令到达。这样设计的初衷是为了严格跟随主节点的删除时序避免主从各自删除导致的数据不一致。代价就是如果你拿从节点做缓存读取会读到一些“在主节点那边已经过期、但从节点还没来得及删掉”的旧数据。另一个坑是如果你给从节点也单独配了maxmemory而每个从节点的淘汰策略和主节点不一致就可能出现从节点自己淘汰了一些主节点还没淘汰的 key而主节点的淘汰命令到达后从节点会收到一个“我根本不存在的 key 的 DEL”执行也没关系。真正需要担心的是从节点因为自己做淘汰导致数据集的 key 分布和主节点产生偏差。所以生产环境我建议主从节点的 maxmemory 策略保持一致不要各玩各的。5.4 延迟度量offset 差值不是万能的常见的主从延迟度量方法是比较主从节点各自的master_repl_offset。差值就是从节点落后的字节数。但它只能反映“复制流消费到哪了”不等于“业务读到的数据有多旧”。更接近业务延迟的做法是写一个带时间戳的 key然后在从节点读出来对比# 主节点执行 redis-cli -p 6379 set probe:$(date %s%N) 1 ex 60 # 从节点执行 redis-cli -p 6380 get probe:$(date %s%N)当然这属于临时验证手段不适合长期监控。长期来说看INFO replication里的 offset 差值和master_last_io_seconds_ago就够用了。如果业务对一致性很敏感有两个方案写后必须立即读到的请求强制走主节点或者使用WAIT命令主动等待从节点确认WAIT 1 1000WAIT后面的参数含义是“等待至少 1 个从节点确认最长等待 1000 毫秒”返回确认的从节点数量。它可以把异步复制临时变成“半同步”但代价是写延迟上升而且只适用于非集群模式。我这里没有把 WAIT 当默认方案因为大部分业务用不到但它是一个一问出来就能加分的知识点。6. 生产环境的复制治理配置、监控与排障实录前面讲了原理最后落回生产。这里把我实际用下来的一套配置、监控方法和排障案例整理出来。6.1 一组可以直接抄的复制相关配置# 从节点 replicaof 10.0.0.5 6379 masterauth your-redis-password replica-read-only yes replica-serve-stale-data no # 主节点 repl-backlog-size 256mb repl-backlog-ttl 3600 repl-diskless-sync yes repl-diskless-sync-delay 5 client-output-buffer-limit replica 512mb 128mb 60 repl-timeout 60几个参数逐个说明replica-serve-stale-data no从节点在断线或全量同步期间拒绝服务旧数据。如果你的从节点本来就是给非核心读业务用的可以保持yes但要让业务知道读到的可能是旧数据。我个人倾向在生产核心链路用no宁可暂时不可用也不能给脏数据。repl-diskless-sync yes配合repl-diskless-sync-delay使用适合从节点较多的场景能省掉反复写盘的 IO。client-output-buffer-limit replica我习惯把硬限制从默认的 256MB 提到 512MB给网络抖动留出更大缓冲但不会无限制放大否则从节点卡死时主节点内存会被输出缓冲拖垮。repl-timeout 60超过 60 秒没有收到从节点的 ACK 或 IO主节点判定从节点超时断开。这套配置不是银弹不同业务要按流量模型调整但至少不会一上来就被默认参数坑到。6.2 INFO replication 关键字段解读在主节点执行INFO replication输出大概是这样# Replication role:master connected_slaves:2 slave0:ip10.0.0.2,port6379,stateonline,offset123456,lag0 slave1:ip10.0.0.3,port6379,stateonline,offset123000,lag1 master_replid:7b2f7c6a9e5d4f3a2b1c0d9e8f7a6b5c4d3e2f1a master_replid2:0000000000000000000000000000000000000000 master_repl_offset:123456 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:268435456 repl_backlog_first_byte_offset:100000 repl_backlog_histlen:23456从节点上执行重点看这些role:slave master_host:10.0.0.5 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_read_repl_offset:123456 slave_repl_offset:123456我把这些字段整理成一张速查表方便排障时对照字段含义值得警惕的状态role当前节点角色master/slave 与预期不符master_link_status与主节点的连接状态down 说明复制链路断了master_last_io_seconds_ago距上次与主节点通信的秒数大于 10 要查心跳和网络master_sync_in_progress是否正在进行全量同步长期为 1 要查 RDB 大小和带宽slave_repl_offset从节点已消费的复制偏移量长时间不变查从节点慢命令master_repl_offset主节点当前复制偏移量与从节点差值持续拉大要告警repl_backlog_histlenbacklog 里还有多少有效数据接近 0部分重同步随时失效监控告警我建议至少覆盖三件事master_link_status变 down、主从 offset 差值超过阈值按字节数比如落后 64MB 以上、master_last_io_seconds_ago超过 10 秒。这三条能兜住绝大多数复制异常。6.3 三个我实际遇见的复制故障第一个故障从节点 offset 长时间不动但连接状态是 up。排查过程先在从节点INFO replication看到master_last_io_seconds_ago: 35说明心跳已经断了。再查网络TCP 连接还在但数据不通典型的半开连接。Redis 自身的超时检测没触发是因为repl-timeout还没到 60 秒。处理方式是调低repl-timeout到 30 秒左右让断线被更快识别从而触发重连和增量同步。这个案例给我的教训是连接状态 up 不代表复制正常必须结合master_last_io_seconds_ago一起看。第二个故障全量同步反复触发。主节点日志里不停出现从节点重连和 FULLRESYNC。排查后发现是主节点输出缓冲打满了从节点某个从节点在执行耗时巨大的 Lua 脚本事件循环被卡住几秒钟ACK 发不回来主节点输出缓冲膨胀触发了client-output-buffer-limit replica限制把从节点断开。从节点重连时offset 已经落后到 backlog 之外只能全量。处理方法是把那个 Lua 脚本拆小同时适度调大输出缓冲区限制并给从节点单独禁用耗时命令。负重前行的从节点撑不了大脚本这个平衡要心里有数。第三个故障主节点重启后所有从节点同时全量。重启前主节点有四个从节点重启后复制 ID 变化四个从节点同时发起 PSYNC主节点瞬间被 fork 四次CPU 和内存全部报警。Redis 4.0 之后部分场景可以从持久化的 RDB 里恢复复制 ID但在我们当时的版本还是避免不了全量。此后我们的上线规范里加了一条主节点重启前先摘流量再从节点错峰重连避免集中风暴。6.4 拓扑设计与落地建议链式复制是主从架构里一个容易踩坑的设计。A 是主节点B 是 A 的从节点C 又是 B 的从节点拓扑变成了 A → B → C。链路延长C 的数据延迟天然会比 B 高出一截。如果 B 或 A 之间断线C 的恢复路径更加复杂部分重同步的成功率也会下降。我的建议是能不用链式就不用让所有从节点直连主节点。只有跨机房网络条件真的很差、或者主节点连接数受限时才考虑中间层从节点作为转发。再提一条实战经验不要在主从复制环境中随意使用FLUSHALL或者DEBUG FLUSHALL。这个命令会在主节点执行然后被复制到每一个从节点所有副本数据一扫而光。操作前不仅要 double check而且要想清楚是不是还要把从节点一个个恢复。Redis 客服从同步删除中恢复的方式是先断开复制、再本地全量重建过程很痛苦。如果你刚上手我建议把一主两从在本地 Docker 环境搭一遍然后手动做几个动作停掉从节点几秒再启动观察INFO replication里的 offset 变化CONFIG SET repl-backlog-size 1故意把 backlog 调到极小再断线重连观察它退化成全量同步的过程用DEBUG SLEEP模拟主节点阻塞观察从节点延迟和输出缓冲的连锁反应。做过一轮你对主从复制的理解会比看十篇文档都深。我个人的体会是主从复制真正难的不是配置本身而是对“异步”这两个字的敬畏。所有高可用方案都在和延迟窗口赛跑Redis 用 backlog、replid、offset 这套机制把成本尽量压低但它终究不是强一致系统。所以线上设计时永远要给复制中断留出退路核心读请求能降级到主节点、从节点挂掉时读流量能快速切换、全量同步期间资源消耗能被监控提前发现。把最坏的情况想清楚主从复制才真正成为了可靠的地基而不是一个看起来能用、一抖就碎的玻璃板。
返回列表