Redis主从复制配置实战:从原理到故障切换
1. 为什么需要Redis主从配置1.1 单机Redis的痛点我在生产环境里第一次碰到Redis单点故障时正在处理一个凌晨的线上告警。业务侧反馈部分接口响应突然从几十毫秒涨到好几秒排查后发现是缓存服务不可用导致请求直接穿透到数据库。那一刻起我就意识到Redis主从配置不是可选优化而是线上部署的必备项。单机Redis最直接的几个问题很简单一是进程崩溃或者服务器宕机时内存里的数据全部丢失即使开了RDB和AOF持久化重启恢复也需要时间这个窗口期内所有热数据的访问都会打到下游存储二是读写都压在一个节点上随着业务增长QPS到了单机上限主线程处理能力受限瓶颈很快出现三是一旦要重启Redis做版本升级、配置调整或内核补丁会直接影响线上读写。主从配置的核心思路就是把一份数据复制到多个节点上让读写请求分散到不同实例同时当主节点出现异常时从节点可以顶上来继续服务。它不解决数据丢失问题但能显著提高可用性和读扩展能力。对于大多数中小团队来说这是性价比最高、最实用的高可用手段。1.2 主从复制解决了什么问题主从复制的价值可以拆成三层来讲。第一层的价值是读写分离。主节点负责写操作从节点负责读操作把集中在一个实例上的读流量分散出去。我在一个日活过百万的信息流项目里把缓存层的读QPS从单机1.6万分散到一主两从三台机器上每台负载明显下降Redis主线程的CPU使用率从接近90%降到了40%左右效果立竿见影。第二层价值是数据冗余。从节点实时同步主节点的数据相当于有了一份热备份。当主节点机器损坏或者要做维护时从节点可以快速提升为新的主节点业务影响控制在秒级别。这点在数据库层面的意义非常大虽然Redis定位是缓存但很多团队实际上把一些用户维度的会话数据、登录状态、限流计数都放在Redis里丢了非常麻烦。第三层价值是故障切换的基础。单纯的一主一从还谈不上完整的高可用因为从节点不会自动上位需要配合哨兵Sentinel做监控和自动故障转移。但是所有高级形态都是建立在主从复制之上的先把复制跑通后续加哨兵、加集群才走得顺。1.3 复制原理的直观理解用生活化的类比来理解主从复制主节点像一个作家从节点是抄写员。作家写完一页纸抄写员完整誊抄一遍以后凡是作家改动的地方抄写员也同步修改。第一次抄写的时候整本书都要重写一遍这就是全量同步之后作家每写一行新内容就告诉抄写员补上这是增量同步。具体到Redis内部全量同步发生在从节点刚接入或者复制连接断开太久时主节点生成一份RDB快照发给从节点从节点清空旧数据再加载这份快照。增量同步则发生在全量同步完成之后主节点把写命令实时发给从节点重放。后面我会把整个流程的细节逐步拆开讲。2. 环境准备与配置文件梳理2.1 部署规划与Redis安装动手之前先把环境规格定清楚。我一般建议主从节点使用相同大版本的Redis比如都是6.x或7.x跨大版本复制虽然在多数情况下能工作但部分命令的编码格式和同步协议有差异容易在细节上出问题。生产环境中我基本采用同一版本测试环境随意一些。我用习惯的Linux环境示例来演示CentOS 7.9和Ubuntu 20.04都适用。Redis 6.x之后的新版本建议直接编译安装虽然也可以apt或yum安装但软件源里的版本往往偏旧。# 下载稳定版Redis以6.2.14为例 wget https://download.redis.io/releases/redis-6.2.14.tar.gz tar xzf redis-6.2.14.tar.gz cd redis-6.2.14 make -j4 make install PREFIX/usr/local/redis编译完成后redis-server、redis-cli会在 /usr/local/redis/bin 下。一个容易忽略的细节是编译依赖gcc和makeCentOS上如果没装要先执行 yum install gcc make。我之前在一台新机器上直接make报了一堆不理解集错误后来装上gcc就顺利通过了。Windows环境也有玩法。Redis官方虽然不直接支持Windows但微软的移植版和目前社区维护的版本都能跑。下载zip包解压后直接运行 redis-server.exe 和 redis-cli.exe配置文件里同样支持主从参数。Windows上做实验验证原理很快我记得下载包里默认带的 redis.windows.conf 就是可用的配置模板。2.2 主从相关核心参数速查主从配置涉及的参数不算多但每个都很关键。我整理了一份对照表方便你规划时快速核对。参数作用说明配置位置replicaof指定主节点IP和端口从节点专用从节点配置文件masterauth主节点开启密码时从节点需配置从节点配置文件requirepass设置访问密码可同时设定复制密码主节点配置文件bind监听地址建议设内网IP或0.0.0.0主从节点配置文件protected-mode保护模式限制无密码访问生产必须开启主从节点配置文件repl-backlog-size增量同步缓冲队列大小影响断线续传能力主节点配置文件repl-diskless-sync是否无盘同步从节点网络传输RDB主节点配置文件repl-read-only从节点是否只读默认yes从节点配置文件老版本的Redis用 slaveof 参数5.0版本之后官方把命名改成了 replicaof语义更准确。虽然slaveof命令仍然兼容但新配置里建议直接用 replicaof。2.3 复制前网络与权限检查主从复制对网络要求很直接从节点必须能访问主节点的Redis端口默认6379。我遇到过不少次主从配置半天没生效的情况最后查下来都是防火墙挡了端口或者是云服务的安全组只放行了本机访问。配置之前做两件事第一用telnet或nc测试端口连通性比如telnet 10.0.1.10 6379能连上说明网络通第二确认主节点的bind配置没有限制死127.0.0.1否则从节点作为外部IP访问会被拒绝。如果主节点开启了requirepass从节点的masterauth必须配置成一致的密码否则复制握手阶段就会一直报NOAUTH错误。密码配置我习惯用一个专门的复制账号而不是用默认的default用户这样后续做权限收敛和审计都方便。3. 主从配置实操全过程3.1 主节点配置与启动假设我有两台机器主节点内网IP是10.0.1.10从节点是10.0.1.11。配置文件按上面的表格整理主节点最核心的是开启监听和持久化。# 主节点redis.conf 关键配置 daemonize yes port 6379 bind 0.0.0.0 protected-mode yes requirepass redispass123 dir /data/redis dbfilename dump.rdb appendonly yes appendfilename appendonly.aofbind 0.0.0.0表示监听所有网卡意味着从节点可以通过内网IP访问本地也能访问。如果只bind内网IP就需要写具体地址。dir参数指定持久化文件的目录这个目录必须存在否则Redis启动时报错且无法保存数据。启动主节点后用redis-cli验证一下状态。redis-cli -a redispass123 ping # 输出 PONG 表示正常 redis-cli -a redispass123 info replication # 关注 role:master 和 connected_slaves:0这里有个体验小技巧redis-cli用-a传密码会在终端历史里留下明文可以改成执行后交互式输入或者用环境变量方式传递。在脚本里可以用redis-cli --user default --pass redispass123的方式写清楚。3.2 从节点配置与主从拉起从节点的配置相对更简单核心是加上replicaof和masterauth。# 从节点redis.conf 关键配置 daemonize yes port 6379 bind 0.0.0.0 protected-mode yes replicaof 10.0.1.10 6379 masterauth redispass123 dir /data/redis appendonly yes配置完成后启动从节点然后用info replication命令观察复制状态。这一步我最喜欢用INFO命令实时观察因为它直接展示了复制的全过程。redis-cli -p 6379 info replication输出的关键信息如下# Replication role:slave master_host:10.0.1.10 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 slave_repl_offset:815master_link_status为up表示主从连接成功slave_repl_offset会持续增长说明增量同步进行中。如果看到down或者SYNC_ERR就需要按后面问题排查章节的方法来处理。从节点默认是只读的执行写命令会报错(error) READONLY You cant write against a read only replica.这是正常现象repl-read-only参数默认值为yes生产环境建议保持默认避免误写入从节点导致数据分叉。3.3 同步状态验证与数据一致性检查主从拉起来之后验证同步效果最直接的办法是写入数据再读出来。# 在主节点写入 redis-cli -a redispass123 set user:1001 zhangsan # 在从节点读取 redis-cli -p 6379 -a redispass123 get user:1001 # 应当返回 zhangsan这只是最基本的验证。更严谨的做法是打开AOF或RDB做数据比对但日常工作里只要info replication里slave_repl_offset在追平主节点的master_repl_offset就说明数据在持续同步。Offset一致说明积压的命令都已经重放完成。实际业务里我见过一个常见误解认为主从同步是实时的、零延迟的。实际上主节点发命令到从节点重放走的是一条异步链路从节点通过网络接收并执行必然有毫秒级甚至几十毫秒级的延迟。在强一致要求的场景下只靠标准主从复制是不够的需要引入RedLock或者客户端侧的同步确认机制。3.4 三种常用的部署形态主从配置不是只能做一主一从实际业务里我建议按需求选形态。一主一从是最小架构适合读多写少但数据量不大的业务。比如中小型网站的会话缓存、配置缓存一台扛读一台做热备成本低部署快。一主多从更常见适合读流量有明显放大效应的场景。比如某活动页的缓存内容被大量用户读取一台机器撑不住就在主节点后面挂两台、三台从节点所有读都走从库。需要注意从节点越多主节点推送数据占用的带宽越高所以也不是从节点越多越好。主从加哨兵是目前最推荐的生产形态。哨兵是独立的进程监控主从节点的健康状态当主节点故障时自动选一个从节点提升为主并将新主节点地址通知给客户端。如果没有哨兵主节点宕机后业务只会一直连旧地址直到人工干预。加上哨兵才能把故障切换时间缩短到十几秒级别。4. 复制原理深入从命令到数据流4.1 全量同步是怎么发生的从节点第一次连上主节点或者长时间断线导致缓冲区中的数据被覆盖时会触发全量同步。全量同步的过程大致分四步第一步从节点发送PSYNC命令给主节点携带自己的runid和offset。如果主节点判断无法提供增量同步就返回FULLRESYNC同时带上自己的runid和当前offset。第二步主节点执行BGSAVE生成RDB快照。这里有个细节生成RDB期间主节点照常处理写命令新写入的命令会暂时缓存在复制缓冲区里。第三步主节点把RDB文件通过网络发给从节点。从节点收到后在本地清空旧数据再把快照加载进内存。加载期间从节点不对外提供读服务所以大数据的全量同步会造成短暂的服务抖动。第四步主节点把复制缓冲区中积压的写命令发给从节点从节点依次重放追上最新的数据状态。全量同步代价不低传输整个数据集、从节点加载时阻塞服务、网络带宽被占用。所以在生产环境里我会尽量避免频繁的全量同步方法就是合理设置repl-backlog-size并保证从节点网络稳定。4.2 增量同步与backlog缓冲区全量同步完成后正常状态下的复制走增量模式。主节点每处理一个写命令除了执行和持久化还会把命令写入一个叫repl_backlog的循环缓冲区同时发给所有已连接的从节点。repl-backlog-size默认是1MB这个值直接影响断线续传的能力。场景是这样的从节点网络闪断了几十秒恢复后从节点重新连上主节点会带上自己最后的offset。主节点检查这个offset是否还在backlog缓冲区内如果在就只发送缺失部分的命令这就是增量续传如果不在比如断线太久或缓冲区太小就只能做全量同步。数据量大的业务里1MB缓冲区非常容易撑满。我做活动缓存时高峰期每秒写入命令就有几千条flash断网两分钟backlog早就滚动覆盖了。后来把repl-backlog-size调到256MB闪断恢复后都是走增量续传零全量同步。参数调整的方法很简单redis-cli -a redispass123 config set repl-backlog-size 256mb # 持久化到配置文件 redis-cli -a redispass123 config rewriteconfig rewrite可以把你用命令修改的参数写回配置文件但前提是Redis对配置文件有写权限。如果启动时没有设置dir权限这一步会失败注意看返回值。4.3 过期键与写入冲突的处理细节Redis主从复制里有个容易被忽略的机制过期键的删除策略在主从之间不是完全一致的。主节点删除一个过期键时会同步给从节点发一条DEL命令而不是依赖从节点自己判断过期时间。这种设计是为了避免时钟不同步导致的数据不一致。如果从节点服务器时钟比主节点慢从节点可能认为一个键还没过期继续对外提供服务而主节点已经删除。由于主节点会主动广播DEL命令从节点以此为准所以最终结果还是收敛一致的。另一个坑是从节点的过期键淘汰策略。如果从节点长时间没有收到主节点的DEL命令比如网络分区了从节点也不能自己主动淘汰过期键因为它是只读的。由此带来的结果是分区恢复后主从数据能正常收敛但分区期间从节点读到的数据有可能是已过期的旧值。对一致性敏感的业务读从库时要容忍这种短暂差异。4.4 无盘复制与断点续传优化Redis支持两种全量同步模式有盘复制disk-backed和无盘复制diskless。默认是有盘复制主节点先落盘生成RDB文件再传输。当RDB文件很大时磁盘I/O会成为瓶颈从节点等待时间长。无盘复制则跳过落盘主节点直接在内存中生成快照流并发送给从节点。配置项是repl-diskless-sync yes。这个模式对主节点内存和带宽要求更高但能显著降低从节点等待时间。我实测过一个900MB数据集的主节点有盘复制从BGSAVE到传输完成耗时28秒无盘复制在同样条件下耗时11秒快了一倍多。代价是主节点内存占用峰值高了一些因为生成快照需要额外的内存开销。无盘复制还有一个参数repl-diskless-sync-delay表示等待更多从节点接入的延迟时间默认5秒。这个延迟能让多个从节点共用一个快照流减少主节点的重复生成开销。如果你要挂多个从节点这个参数值得调大一些比如10秒。5. 常见问题与排查实录5.1 从节点一直SYNC_FAIL怎么办从节点状态一直卡在master_link_status:down或者日志里反复出现SYNC_FAIL最常见的几个原因依次排查。首要确认网络。用telnet测端口通不通在主从节点互相ping一下。我遇到过一个奇葩案例从节点能ping通主节点但telnet 6379失败最后发现是主节点云安全组只放行了80和443端口。这类问题在云环境里尤其常见。其次排查主节点是否开启了protected-mode且没有配置bind。如果主节点保护模式开启同时又设置了requirepass从节点的masterauth必须一致。换一句话说从节点访问主节点时如果主节点要求密码验证从节点没配或者配错密码握手会一直失败。如果网络和密码都没问题再看日志。Redis日志在从节点启动时有类似MASTER - REPLICA sync started、Full resync requested by replica这样的信息通过日志能定位到具体卡在哪一步。这里我直接推荐一套排查口诀一ping二telnet三看密码四读日志。5.2 主从数据不一致的分析思路如果发现主从数据不一致先确认不是自己的预期问题。Redis主从复制是异步的所以主从之间存在短暂的不一致窗口数据差异在offset追赶阶段是正常的。等slave_repl_offset追上master_repl_offset后数据应该完全一致。如果offset已经追平数据仍然不一致那就需要怀疑人为写入。从节点默认只读但如果有人手动执行了replicaof no one又把repl-read-only改为no从节点就能写入导致数据分叉。我排查过一个典型案例运维同学为了让从节点承担一些临时计算任务把只读关掉了结果业务往从节点写了数据主从瞬间不一致且Redis本身不会自动合并这种差异。解决思路只有一个找到原因后清空从节点数据重新执行全量同步。操作方式是在从节点上执行redis-cli -a redispass123 replicaof no one redis-cli -a redispass123 flushall redis-cli -a redispass123 replicaof 10.0.1.10 6379先断开复制清空数据再重新建立主从关系。这样会触发一次全量同步从节点数据会完整覆盖为当前主节点的数据。注意这操作会清空从节点数据动手前确认从节点上没有额外业务数据。5.3 复制延迟较大的排查套路复制延迟在INFO replication里通过master_last_io_seconds_ago体现也可以对比master_repl_offset和slave_repl_offset之间的差距来判断。如果差距持续扩大说明从节点来不及处理主节点发送的命令。常见原因有三个第一从节点的网络带宽不足命令积压在传输层第二从节点开启了AOF持久化且是always策略每次写命令都要落盘处理速度受限第三从节点本身还承担了大量读请求主线程在处理写命令重放和读请求之间需要排队。我的处理手段是先把AOF策略从always改成everysec降低刷盘频率。然后用redis-cli --latency工具直接测量主从之间的网络延迟。最后考虑给从节点扩容或者减少挂在主节点下的从节点数量。对于业务上无法容忍延迟的场景可以引入客户端侧的可控策略比如强制要求写后立即读走主节点而不是从节点。在Spring Redis之类的客户端里RedisTemplate支持路由策略配置把强一致请求路由到master。5.4 故障切换与从节点提升主节点宕机时从节点不会自动上位除非配置了哨兵。没有哨兵的情况下手动提升的步骤很直接在从节点上执行以下命令让它断开复制并成为新的主节点。redis-cli -a redispass123 replicaof no one执行后从节点变为master角色不再接收旧主节点的数据。此时业务客户端需要切换连接地址到新主节点。如果客户端之前连接的是旧主IP那么需要在负载均衡层或者客户端配置层面切换。因为有这个手动操作成本我强烈建议生产环境一定要部署哨兵。三个哨兵实例能提供真正的自动故障转移哨兵之间通过投票选主当主节点失联超过down-after-milliseconds设置的时间就会发起选举挑一个数据最新的从节点提升为新的主节点。6. 生产环境主从配置建议与调优6.1 核心参数推荐值根据我在多个项目的实测整理一套主从配置的推荐参数可以作为业务的起点配置。参数推荐配置说明repl-backlog-size128MB~512MB越大越能容忍断线续传内存充足就用256MBrepl-diskless-syncyes大数据集效率高repl-diskless-sync-delay10等待更多从节点接入repl-timeout60网络异常时避免长时间阻塞repl-read-onlyyes从节点只读禁止写入min-replicas-to-write1主节点写可用性需要至少有1个健康从节点min-replicas-max-lag10主从延迟超过10秒时限制写入min-replicas-to-write是一个很实用的数据安全参数主节点会检查健康从节点数量如果小于设定值就拒绝写请求。这个机制在极端情况下能避免主节点和所有从节点同时写入导致的数据分叉。6.2 监控与日常运维命令主从复制状态的监控不需要额外安装工具用redis-cli的几个命令就能覆盖。# 查看复制状态 redis-cli -a redispass123 info replication # 查看主节点所有客户端连接 redis-cli -a redispass123 client list # 持续监控延迟指标 redis-cli -a redispass123 --stat--stat命令会持续输出Redis的运行状态包括内存、连接数、命令处理数等是我排查性能问题时的首选工具。输出里有一栏是repl表示当前连接的从节点数量和复制offset。更完整的监控建议接上云监控或者开源方案。如果公司没有现成的监控最简单的办法是写一个定时任务每30秒采集一次info replication解析master_link_status字段发现不是up就告警。这个脚本用Python或Shell都可以实现十几行代码就能搞定。6.3 我在实际踩过的坑与建议操作了这么多年Redis主从配置有几个坑反复出现。今天一并写出来希望你能绕开。第一个坑是版本不一致。线上环境里有人顺手给从节点升级了Redis版本主节点还是旧版结果某些数据类型如List、Hash的编码格式在新版本里发生了变化复制时出现解析异常。后来我定了一条规矩主从节点版本必须严格一致涉及Redis升级时先升级从节点再升级主节点分批操作。第二个坑是忽略了maxmemory的配置。Redis在内存满了之后有淘汰策略如果主节点配置了maxmemory但从节点没有主节点触发了内存淘汰删除键从节点内存使用率会不一致。更严重的是从节点内存不足时加载RDB或重放命令直接失败复制中断。所以主从节点的内存上限要设成一致的值。第三个坑是备份策略的依赖关系。很多人以为有了从节点就不需要备份了实际上从节点的数据也是基于主节点的异步复制不能替代离线备份。如果主从节点同时宕机且没有离线备份数据照样全丢。专业的做法是在从节点上定期执行BGSAVE并把dump.rdb同步到独立的备份服务器或对象存储。最后一个建议是别把主从复制当成高可用的全部。主从解决了数据复制和读扩展但故障转移依赖哨兵或集群。我的生产架构标配是一主两从三哨兵哨兵用独立的最小规格机器部署避免哨兵所在的机器和Redis节点同时宕机。Redis主从配置看起来是很小的一个知识点但真正把它用好需要理解复制流程、参数语义和运维套路。希望这篇文章能帮你少走一些弯路尤其是在踩坑排查的时候回头看看这些细节会有帮助。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →