ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Redis主从复制实战:高可用部署配置与故障演练全解析

2026/10/5 15:31:43 拓冰建站 浏览量
Redis主从复制实战:高可用部署配置与故障演练全解析 凌晨两点被告警电话叫醒这应该是每个后端开发都怕的体验。那台Redis单机挂了接口层一堆超时数据库CPU直接被拖爆。恢复业务之后我做的第一件事就是打开redis.conf把主从配置彻底搞明白。这篇文章把我实操的全过程写出来为什么必须做、不同部署方式怎么选、redis.conf里哪些配置是真命脉、主从复制的底层机制、验证和故障演练怎么做以及上线之后我踩过的坑。如果你正在搭建或优化Redis高可用方案这篇可以直接当操作清单来用。1. 单机Redis的脆弱点为什么必须做主从1.1 一次真实故障引发的思考那台出问题的实例其实负载一直不高内存占用才2GB多一点。但宕机之后连锁反应很吓人所有请求直接穿过缓存打到数据库数据库连接池瞬间被打满服务雪崩的不是一个接口是整整两个服务。事后复盘就一个结论——单点部署的Redis无论你业务逻辑写得多漂亮缓存命中率多高都是整个链路里最脆的那一环。不少人对缓存的理解还停留在快这个层面觉得Redis就是个加速器。实际上一旦缓存层没有副本你就等于把全部读请求都押在一台机器上。主从复制解决的核心问题不是性能而是可用性和容错能力数据有了冗余其中一台节点出问题另一台还能扛住读流量。1.2 主从能解决什么不能解决什么先明确边界这比记配置命令更重要。主从复制解决的是这三方面问题数据冗余主节点上的数据通过异步复制同步到从节点磁盘故障、误操作删库从节点上还有一份相对完整的数据。读扩展大部分业务场景读写比悬殊把读流量分到从节点后主节点压力明显下降。高可用基础设施哨兵、Redis Cluster都是基于多副本演进出来的没有主从这个底座后面那些高阶方案都无从谈起。同时必须认清主从不解决什么不解决自动故障转移。主节点挂了从节点不会自己上位变成主节点。要不要自动切换是哨兵的事不是主从复制本身的功能。不解决写扩展。写操作永远在主节点上主从架构下写能力没任何增强这点经常被误解。不解决缓存治理问题。缓存穿透、击穿、雪崩这些是缓存策略层面的问题主从配置救不了你。比如穿透问题更靠谱的办法是空值缓存加布隆过滤器。明确了这些再去做配置心里就有底了。后面所有操作我都围绕数据冗余读扩展可验证这三个目标展开。2. 搭建前的选型本机双实例、Docker Compose还是云托管2.1 纯本机双实例最适合理解和验证如果你是想学原理最直接的方式是在一台机器上跑两个Redis实例一个6379做主节点一个6380做从节点。我用的是Linux环境macOS操作也完全一样只是配置文件路径不同。准备两个目录分别放日志和持久化文件mkdir -p /opt/redis/master mkdir -p /opt/redis/replica主节点配置不做任何复制相关的改动保持纯默认即可。从节点的redis.conf里核心就是一行replicaof 127.0.0.1 6379然后分别启动redis-server /opt/redis/master/redis.conf --port 6379 redis-server /opt/redis/replica/redis.conf --port 6380启动后连到6380执行info replication如果看到role:slave且master_link_status:up说明复制链路已经建立。这种部署适合做测试和验证缺点也很明显同一个宿主机上磁盘和网络栈是共享的真出物理故障两台实例一起挂。所以生产环境别这么干只当实验环境用。2.2 Docker Compose接近生产的一键方案在实际项目中用Docker Compose拉两个容器做主从是目前最省事也最接近生产的方式。使用7.2版本镜像同时带密码验证这是我的基础配置version: 3.8 services: redis-master: image: redis:7.2 container_name: redis-master ports: - 6379:6379 command: redis-server --requirepass masterpass --appendonly yes redis-replica: image: redis:7.2 container_name: redis-replica ports: - 6380:6379 depends_on: - redis-master command: redis-server --replicaof redis-master 6379 --masterauth masterpass --requirepass replicapass --appendonly yes启动命令docker compose up -d验证命令docker exec -it redis-replica redis-cli -a replicapass info replication这里有个细节值得注意depends_on只保证容器启动顺序不保证主节点端口已经就绪所以如果用了脚本化的自动化验证最好加个重试逻辑。服务跑起来之后第一次同步可能还需要几秒别急着下结论。2.3 选型建议我给不同场景的选型建议如下场景推荐方式原因学习原理、做实验本机双实例无额外依赖配置直观能随时改配置重启验证本地开发、版本管理Docker Compose环境一致性好配置可写成代码团队协作方便生产环境自建物理机/云主机双节点加哨兵需要稳定的网络和足够的磁盘副本间尽量跨机架云上业务云托管Redis主从免运维自带监控和切换但要注意实例规格约束生产环境我建议直接上物理机器或云主机构建双节点然后配合哨兵做自动切换。别图省事把生产Redis全部塞进容器里除非你的基础设施已经有很成熟的存储编排方案。3. redis.conf中与主从命运相关的配置项逐条拆解3.1 最核心的第一梯队replicaof与replica-read-onlyreplicaof是主从关系的起点语法是replicaof master-ip master-port注意在Redis 5.0之前这个配置项叫slaveof。网上大量老教程还在用slaveof新版本也兼容但配置规范里已经统一成replicaof了。如果你在旧系统上维护能用新的就尽量用新的命令。replica-read-only默认是yes即从节点只接受读请求。这个设计是为了防止从节点被误写后数据分叉。你真的需要临时写从节点吗几乎不需要。生产环境里从节点被误写入导致主从数据不一致的故障我见过不止一次保持只读是保护机制不是限制。这里要特别提醒replica-read-only只影响普通客户端写入。从节点如果装了旧版脚本或者有管理员权限绕过协议直接改数据文件的事也存在所以除了配置还要在权限上严格管控。3.2 认证体系requirepass与masterauth必须配合好密码是主从配置里最容易翻车的地方。很多人只设置了主节点的requirepass却忘了在从节点配置masterauth结果从节点日志里疯狂刷MASTER - REPLICA sync started # Error condition on socket for SYNC: Connection refused或者握手认证失败同步永远建立不起来。正确的做法分两块主节点配置requirepass用于客户端认证。从节点配置masterauth用于向主节点发起复制时认证。用Docker部署的时候命令行参数里--masterauth一定不能漏。如果你把主从节点的密码设成不一样从节点的masterauth要填主节点的密码这点不要搞反。生产环境的密码管理建议走配置中心或环境变量不要硬编码在配置文件里。3.3 进阶参数积压缓冲区、超时与最小从节点数这三个参数对同步的健壮度影响很大建议一个都不要省略。复制积压缓冲区repl-backlog-size。这个缓冲区是主节点维护的一块环形内存区域用来记录最近发送给从节点的命令流。从节点断线重连时如果断线期间的命令流还在缓冲区里主节点只需要把缺失部分补发给从节点这就是部分同步。缓冲区太小断线稍微久一点就触发全量同步代价是RDB全量传输网络和磁盘开销很大。默认值1MB生产环境建议调到32MB-128MB具体根据你写的QPS和断线容忍时长来算。公式很简单每秒写入量乘以期望容忍的断线秒数。例如每秒写入2MB希望容忍30秒断线缓冲区至少60MB。复制超时repl-timeout。默认60秒指主从节点之间N秒内没有有效数据交互就判定连接超时。网络抖动频繁的场景可以调大到120秒或180秒避免偶发抖动直接触发重连。最小从节点数min-replicas-to-write与min-replicas-max-lag。这组参数可以保证写可用性当健康的从节点数量低于阈值主节点直接拒绝写请求。比如设置min-replicas-to-write 1 min-replicas-max-lag 10意思是至少有1个从节点并且在10秒内有过心跳主节点才允许写入。设置后主节点就不会在没有任何副本可用时傻傻地接受写入丢失数据的窗口会小很多。4. 主从复制的底层握手流程与同步机制4.1 从节点启动之后发生了什么配置好replicaof后从节点启动时会做一连串动作很多人只知道自动同步没看过中间过程。我建议在生产环境用redis-cli -p 6380连上去实时观察日志完整链路是这样的从节点向主节点发起TCP连接。主节点开启一个后台进程执行BGSAVE生成RDB快照。主节点把RDB文件发给从节点。从节点清空自己的旧数据加载RDB文件。主节点把BGSAVE之后的增量命令持续推给从节点。从节点日志里的典型输出是这样的# Full resync requested by replica. # Starting BGSAVE in SYNC mode # Background RDB transfer terminated with success # Synchronization with master succeeded整个流程对主节点的影响主要是BGSAVE瞬间的CPU和磁盘IO。内存大的实例做全量同步时主节点可能短暂卡顿。因此一次性加很多从节点时要错峰别同一时间点全部挂上来。4.2 全量同步与部分同步的分界线在哪Redis复制协议的演进很有意思。老版本只能做全量同步新版本通过PSYNC实现了断线续传。全量同步发生在两种场景从节点第一次连接主节点或者从节点断线时间过长导致主节点的复制积压缓冲区里的命令流已经过期。全量同步要在网络上传输整个RDB文件如果数据集几十GB这个过程不仅慢还会占用大量带宽和内存。部分同步就是前文提到的积压缓冲区机制。从节点断线重连时会带上上次接收到的复制偏移量replication offset主节点对比自己的偏移量如果缺失的数据还在积压缓冲区内就只补发缺失部分。这里我想用一个生活类比帮助理解全量同步像是把整本书重新抄一遍寄给你部分同步只是把你没看的那几页复印给你。所以数据量越大越要保证缓冲区空间足够否则一次小抖动就让你重新抄一遍整本书代价很痛。4.3 复制偏移量与心跳机制复制的正确性靠两个东西维持复制IDreplid和复制偏移量offset。主节点有唯一的replid从节点会继承这个ID直到从节点被提升为主节点或者执行了replicaof no one才会生成自己新的replid。心跳机制上主节点默认每10秒向从节点发送PING从节点也定期上报自己的偏移量。判断主从是否健康关键看info replication里的lag字段它表示从节点多久没收到主节点的消息了。正常情况下lag应该在0或1如果持续变大说明网络或者主节点处理有问题。4.4 从节点如何处理过期键和AOF一个容易搞混的知识点主从架构下从节点不会主动删除过期键它只依赖主节点的DEL命令。主节点在键过期时会生成删除命令并发送给从节点。这样设计是为了确保主从数据的一致如果从节点自己按本地时间删数据就可能出现主从数据视角不一致的问题。从节点要不要开启AOF生产环境我建议开。开启AOF的从节点每次重启后先恢复自己的本地数据再执行复制同步网络中断时它能更快地补数据。不开启AOF的从节点如果重启且主节点缓冲区已过期就会被迫全量重同步。所以从节点开AOF不是加重负担是给恢复过程加保险。5. 验证主从状态与故障演练的完整操作5.1 用info replication判断健康状态配置完第一件事永远是看复制状态。在主节点上执行redis-cli -a masterpass info replication正常情况下你会看到类似这样的输出# Replication role:master connected_slaves:1 slave0:ip127.0.0.1,port6380,stateonline,offset1337,lag0 master_failover_state:no-failover master_replid:1a2b3c4d5e6f... master_repl_offset:1337在从节点上执行则是# Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 slave_read_repl_offset:1337 slave_repl_offset:1337这里重点看三个地方。第一个是role区分主从。第二个是master_link_status必须是up如果变成down说明同步链路断了。第三个是offset主从节点的偏移量应该一致如果从节点的偏移量一直落后并且不增长说明同步延迟或卡住了。5.2 数据一致性验证的土办法配置完成后我习惯做一次最朴素的数据验证简单但有效在主节点写入一条带特征的keyredis-cli -a masterpass set sync_test_value hello_redis_main然后在从节点读取redis-cli -a replicapass -p 6380 get sync_test_value能返回相同值说明同步基本正常。再删掉这个测试key保持线上数据干净。验证延迟还可以用DEBUG命令吗不推荐。DEBUG是故障诊断用的不能用它测数据一致性。应该观察master_last_io_seconds_ago和lag字段这两个字段能真实反映主从之间的交互时延。5.3 故障演练模拟主节点宕机这一步强烈建议做。我只在测试环境做验证生产环境请务必在业务低峰期申请变更窗口。演练步骤如下第一步停掉主节点redis-cli -a masterpass shutdown第二步观察从节点状态redis-cli -a replicapass -p 6380 info replication此时master_link_status会变成down但注意——从节点仍然可以正常处理读请求这是复制机制和主从高可用的重要区别。第三步在确认主节点真的不可恢复之后把从节点提升为主节点redis-cli -a replicapass -p 6380 replicaof no one提升后它会生成自己的replid接受写入。但这里要清楚这个操作是手工的。真实生产环境里应该由哨兵来干这件事。哨兵自动判断主节点客观下线然后从候选从节点中选一个执行replicaof no one并把其余从节点重新指向新的主节点。即便你打算用哨兵也建议手动演练一次。这样你对故障切换的时间窗口、服务中断时长、数据不丢失的判断都会有体感。6. 上线后的高频坑与排查链路6.1 我实际遇到过的三类主从问题第一类是密码不匹配之前已经讲过。第二类是网络抖动引发的全量重同步第三类是客户端连接超时。网络抖动导致全量重同步在公网环境下特别常见。从节点日志里会出现# MASTER - REPLICA sync started # Full resync requested by replica.即使你设置了repl-backlog如果抖动时间超过了积压缓冲区的覆盖范围照样触发全量。解决方向有两个一是调大repl-backlog-size二是优化主从节点之间的网络质量专线或同可用区部署会好很多。6.2 Lettuce客户端RedisCommandTimeout的排查思路这个热搜词频繁出现在Spring Boot项目的报错里打开日志一看是RedisCommandTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException很多刚用主从架构的人遇到这个报错第一反应是调大Lettuce的timeout参数其实这个方向经常是错的。从主从架构视角去拆解原因通常有两种。第一种是主节点负载过高命令排队时间超过了timeout。在主从架构下Lettuce默认会把所有读写请求都发给主节点从节点根本没被利用起来。你需要在Spring配置里显式开启读流量分配spring: data: redis: lettuce: pool: max-active: 16 max-idle: 8再配合LettuceClientConfigurationBuilderCustomizer设置readFrom(ReadFrom.REPLICA_PREFERRED)让读请求优先走从节点。这才叫真正用上了主从架构的读扩展能力。第二种是主节点在做全量RDB同步时产生短暂阻塞。排查时先看主节点日志有没有BGSAVE相关记录再看慢日志redis-cli -a masterpass slowlog get 10如果慢日志里全是BGSAVE触发的写命令排队说明同步过程影响到了主节点的服务能力这时候再回头优化复制的缓冲区配置和同步策略。6.3 从节点只读与自动切换的注意事项生产环境最忌讳两件事第一件是在从节点上执行写命令后业务看到数据成功写入但主从一同步这个数据分叉会被覆盖等于静默丢数据。第二件是把从节点当主节点用手工提升后客户端配置没改流量还是打到老的主节点地址上。这里我的个人习惯是主从节点的服务发现不要写死IP和端口而是通过VIP或者配置中心动态获取当前主节点地址。哨兵模式下客户端需要通过Sentinel去发现当前主节点而不是自己记住一个地址否则主从切换后客户端连的还是那个已经挂掉的机器。6.4 从节点延迟监控的正确姿势只搭不监控等于白搭。主从延迟问题的隐蔽之处在于它不会直接报错而是反映在业务上的数据不一致、过期数据读不到等奇怪现象。监控指标建议盯三个主从节点offset差值、master_last_io_seconds_ago、lag。这三个字段用Prometheus的redis_exporter都能直接采到。阈值上offset差值持续超过1000且不收敛就值得告警了。注意监控的是主从节点之间的同步延迟不是某个业务命令的响应时间这两个概念不要混在一起。7. 和主从纠缠最深的两个话题持久化与分布式锁7.1 持久化与复制的协作关系主从复制依赖RDB作为全量同步的载体所以主节点必须开启RDB或者AOF否则无法生成同步快照。生产最佳实践是主节点同时开启RDB和AOF从节点至少开启AOF。这样主节点能做增量恢复从节点在重启时也能快速恢复本地数据减少全量同步频率。很多老项目的误区在于把持久化文件都放在系统盘磁盘满了之后BGSAVE失败导致全量同步反复失败。这个坑看起来低级实际上我见过不止一次。持久化文件目录一定单独规划容量RDB和AOF的写盘频率要做评估别让日志把磁盘占满。7.2 数据类型语义在主从中的表现Redis的数据类型在主从复制下基本感受不到差异String、Hash、List的写命令都会正常同步到从节点。唯一的差异体现在过期时间上。之前提到过从节点不主动删除过期键所以从节点上可能会短暂读到主节点已经删掉的数据。如果你做了读写分离读到已过期但还没被DEL同步过来的数据是正常现象业务上需要对这种毫秒级的弱一致有容忍度。这也是我们要区分缓存和数据库语义的原因。缓存场景下主从弱一致通常无所谓但如果你把Redis当数据库存了强一致要求的数据主从架构天然就不合适。选型的时候要想明白这个边界。7.3 主从架构下分布式锁的局限性Redis分布式锁热火朝天的时候很多人没意识到主从架构和分布式锁之间存在一个经典矛盾主节点获取锁后还没来得及把锁的写命令同步到从节点主节点就挂了哨兵把从节点提升为新主节点此时新主节点根本没有这把锁的写入记录另一个客户端就能成功获得同一把锁。这就是分布式锁在主从模式下会失效的根因场景。解决思路不外乎两条一是锁的业务价值没那么高能接受极小概率的重复执行那主从Redisson这类方案够用二是锁失效代价极高比如扣库存、抢单就必须引入Redlock或者换用强一致存储实现分布式锁。我的建议是先评估业务容忍度再决定上不上Redlock不要为理论上的完美付出过高的运维复杂度。主从配置从来不是一句replicaof就能完事的。部署方式、认证体系、积压缓冲区大小、持久化策略、监控指标、故障切换机制每个环节都藏着一个为什么。我当时把每个配置项都亲手改一遍、推倒重来好几次才真正理解了复制机制。建议你照着这篇文章在自己环境里完整走一遍尤其故障演练那节踩过一遍和看一遍是完全两种体感。