news 2026/10/11 10:51:48

Redis主从复制全解析:原理、配置与高可用排障实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis主从复制全解析:原理、配置与高可用排障实战

做 Redis 的人,几乎没有能绕过主从复制的。哪怕你暂时只用单机 Redis 扛缓存,只要流量稍微涨起来,或者你开始考虑“这台机器挂了怎么办”,主从复制就会从“加分项”变成“必选项”。这里不聊那些花哨的演进路线,直接拆开 Redis 主从复制这套方案:它到底怎么解决数据高可用,又是怎么把负载均衡落到读流量上的,以及你在配置、排障、扩容时最可能踩进去的坑。

这套机制表面上是“主库写、从库读”,但真正跑过生产环境的人都知道,它背后牵扯到全量同步、增量同步、断线续传、哨兵选主、客户端读写分离等一系列细节。任何一个环节没弄透,都会在某个深夜里变成告警短信。我尽量把原理和实操放在一起讲,配合我从实际环境里总结出来的排障经验,让你看完之后不仅能搭起来,还能在出问题的时候稳住阵脚。

1. 主从复制到底解决了什么问题

先把结论放在最前面:主从复制不是一个高可用方案本身,但它是一切高可用方案的基石。理解了这句话,你就不会对它产生不切实际的期待,也不会因为“主从明明配好了,主挂了业务还是断了”而大骂 Redis 坑爹。

1.1 单点故障与读压力:你迟早要面对的两堵墙

单个 Redis 实例跑得好好的,读写都能扛,但有两个问题是从一开始就埋着的。

第一是单点故障。一台机器只有一个 Redis 进程,操作系统崩溃、磁盘写满、内存颗粒故障、机房网络抖动,任何一种情况发生,这个 Redis 就不可用了。更尴尬的是,如果这台机器彻底起不来,你存的所有缓存数据都跟着没了。虽然不是持久化存储,但缓存一旦雪崩,后端数据库可能在几分钟内被打到喘不过气。

第二是读压力上行。单机 Redis 的 QPS 可以做得非常高,几万甚至十几万都不是问题,但业务增长是不讲道理的。热点活动一来,读流量可能翻十倍,你只能在“加机器”和“降体验”之间选。加机器怎么加?直接加一台 Redis,客户端连新的,每个客户端都要改配置,改完发现数据还是老的,缓存命中率急剧下降,这根本不算扩展,只能算拆东墙补西墙。

主从复制就是为这两堵墙设计的。主节点继续承担写请求和强一致性的压力,从节点通过复制获得相同的数据,承担读请求。一旦主节点宕机,管理员可以把从节点提升为新的主节点,流量继续运转。这就是数据高可用和负载均衡跑在同一条轨道上的底层原因。

1.2 主从复制不是银弹:必须明确它的边界

很多初学者容易把主从复制理解成“复制了数据就等于备份了数据”。这话只对了一半。Redis 的主从复制是异步的,注意“异步”这两个字。主库执行完写命令之后,并不会等着从库回复“我收到并且写好了”再去处理下一条命令。也就是说,在任意一个时间点,从库上的数据可能比主库落后一点点,遇到极端情况甚至可能落后很多。

所以它保护的是“高可用”,不是“强一致”。你从从库读数据,读到稍旧的数据是完全正常的。这跟 MySQL 的主从也有一定的相似性,但 Redis 的复制设计得更轻量,对命令执行性能的影响更小,代价就是一致性的保证也更弱。

另外,主从复制默认也没有自动故障转移。主库挂了,从库不会自己举手说“我来当主库”。你需要一个哨兵(Sentinel)在旁边盯着,或者干脆用 Redis Cluster 的托管故障转移。我在后面的章节单独讲哨兵这部分,因为如果你只配主从不配哨兵,生产环境基本等于裸奔。

2. 主从复制运行原理:全量同步、增量同步与心跳机制

有人觉得原理不重要,会用就行。但 Redis 主从复制的排障,十有八九要回到原理上。你不理解全量同步为什么可能阻塞主库,就没法解释“为什么加了一台从库之后主库延迟飙升”。你不理解增量同步依赖 backlog,就没法解释“为什么重启从库经常触发全量重同步而不是增量续传”。

这里我尽量用大白话把整套机制讲明白。

2.1 复制连接的建立:从一条命令开始

当你在从库上执行replicaof <主库IP> <主库端口>的时候,从库做的事情是:向主库发起一条握手请求,主库收到请求后会返回自己的运行 ID(run_id)和复制偏移量(replication offset)。从库把这两个信息记录下来,然后就可以开始同步数据了。

这里的 run_id 一定要记住,它是判断是否需要全量同步的关键依据。主库每次启动都会生成一个新的 run_id,从库保存的是它认领过的那个主库 run_id。如果主库重启了,run_id 变了,从库拿着旧 run_id 去请求增量同步,主库一看对不上,只能回一句“兄弟,来不及解释了,全量来一遍吧”。很多线上“莫名其妙触发全量同步”的案例,根源就是主库重启导致的 run_id 换新。

2.2 全量同步:RDB 快照加复制缓冲区的接力赛

全量同步发生在从库第一次连接主库,或者主从之间的复制链路断开了太久的情况下。流程可以拆成四步:

第一步,主库 fork 出一个子进程,生成一份 RDB 快照文件。注意是 fork 子进程,不是主进程亲自写磁盘。Redis 利用操作系统的写时复制(Copy-on-Write)机制,让子进程在后台持久化当前内存数据,主进程同时继续服务读写请求。

第二步,从库收到 RDB 文件后,会先清空自己当前的所有数据,然后把 RDB 文件装载进内存。这个清空和装载的过程,从库是阻塞的。如果从库上已有不少数据,装载时间会非常长,期间从库对外不可用。

第三步的坑就在这里:主库在生成 RDB 和传输 RDB 的过程中,可没有停下来。源源不断的写命令仍然在执行,这些新数据不会出现在 RDB 文件里。为了保证从库最终数据和主库一致,主库会把这段时间收到的写命令写进一个复制缓冲区(client output buffer,更准确说是 replication backlog 的一部分),等 RDB 传完,再把缓冲区里的命令补发给从库。

第四步,从库收完增量命令,终于跟主库追平,此时主从状态变成 online。

这个过程听着顺畅,但实际运行时有两个风险点。一是 fork 这个动作在内存特别大的实例上会卡一下,甚至造成主库短时间内延迟升高;二是传输 RDB 期间产生的新写命令如果超出了缓冲区大小,从库就只能重新再来一次全量同步。这就形成了一个恶性循环:主库写入压力越大,缓冲区越容易爆,从库越可能反复被全量同步。

所以我们在规划从库数量时,不要动不动就挂三四个甚至更多从库。每增加一个从库,主库就要多生成一份 RDB 并全量传一次,RDB 传输是走网络带宽的,这对主库的性能、磁盘 I/O、网卡带宽都是实打实的消耗。

提示:使用 Redis 6.0 以上版本,可以考虑开启repl-diskless-sync yes,让主库不落盘而直接把 RDB 数据通过 socket 流式传输给从库。但这个方案要求主库和从库网络质量足够好,否则容易卡在传输阶段。

2.3 增量同步与 repl_backlog:断线续传的续命机制

全量同步成本太高,所以 Redis 设计了一种更轻量的机制来处理主从短暂断开后的数据补齐,这就是增量同步,也叫部分重同步。

主库维护着一个环形的内存缓冲区 repl_backlog,默认大小是 1MB。主库执行每一条写命令后,都会在 backlog 里追加一条记录,同时更新自己的复制偏移量(master_repl_offset)。从库每接收并应用一条命令,也会更新自己的偏移量(slave_repl_offset)。两个偏移量之差,就是从库落后主库的距离。

当主从连接断开重连后,从库会带着自己最后记录的偏移量和 run_id 去找主库。主库查一下 backlog,发现从库请求的偏移量数据还在缓冲区里,于是直接从那个偏移量开始,把后续的所有命令打包发给从库。这就避免了全量同步的巨大开销。

但如果断线时间太长,从库落后的偏移量已经被 backlog 环形缓冲区冲刷掉了,主库就无能为力了,只能退回全量同步。这就是为什么你在生产环境里经常看到“从库断连几分钟,重连后直接全量同步”——因为 backlog 默认 1MB 实在太容易不够用了。

实践建议:如果网络环境不算稳定,把repl-backlog-size调大一些,比如 64MB 或 128MB。这个参数占用的是主库内存,但它能在极端情况下省掉一次灾难性的全量同步。代价是主库内存增加,你可以根据业务写入速率和可容忍的断线时间自行折算:大致等于“每秒写入量 × 可容忍断线秒数”。

2.4 心跳机制与命令传播的细节

主从之间不是建立连接之后就不管了。从库默认每秒钟向主库发送一次REPLCONF ACK <offset>,一方面汇报自己的复制偏移量,让主库知道从库落后多少;另一方面充当心跳,告诉主库“我还活着”。主库也能通过这种心跳感知到从库是否在线,如果超过repl-timeout时间(默认 60 秒)没收到心跳,主库就会判定这个从库已经失联。

主库向从库传播命令是持续进行的。主库每执行一条写命令,除了更新内存数据,还会把命令写入复制缓冲区和 backlog,然后异步发送给所有已连接的从库。这个过程是单线程主循环里的一部分,所以正常情况下主库不会因为从库数量太少而明显变慢,但从库数量非常多时,网络发送会成为瓶颈。

还有一个容易忽视的点:从库默认replica-read-only yes,也就是说从库只能读,不能写。这不是强制的,但生产环境千万别改成 no。一旦从库能被写入,数据分叉(divergence)就发生了,到时候你根本搞不清哪个数据才是对的。如果你确实需要在从库上临时写入,比如做某个特殊标记,那也不要让它进入业务路径,后续还得小心清理。

3. 实操:从零搭建一套可用的 Redis 主从复制

讲完原理,我们来动手。这里我不只贴命令,还把每一步背后的选择和注意点都交代清楚。选用最常见的方式:一台机器上跑多个 Redis 实例,模拟一主一从,全部配置用文件方式完成,这样最贴近生产环境下的管理方式。

3.1 环境准备:Redis 安装与基础配置

生产环境里我推荐用 Redis 6.2 以上版本,最好直接用 7.x。老版本的反斜杠玩法有不少坑,而且 7.x 在复制、持久化、ACL 这些方面都完善了很多。安装方式不多说,Linux 上一般就是apt install redis-server或者去官网下载源码编译。如果不开源包管理器安装,我就是直接源码编译的,两步代码解决:

wget https://download.redis.io/releases/redis-7.2.4.tar.gz tar xzf redis-7.2.4.tar.gz && cd redis-7.2.4 && make && make install

源码编译的好处是不会被发行版阉割掉一些模块,坏处是需要自己管理 systemd 服务文件和目录结构。个人做实验无所谓,生产建议还是用发行版的包,维护成本低很多。

接下来规划实例目录。一台机器上跑两个实例的话,建议目录完全分离开,日志、数据文件、配置文件都各管各的。我一般这样建:

mkdir -p /data/redis/6379 mkdir -p /data/redis/6380 mkdir -p /etc/redis

为什么特意强调目录分离?因为 Redis 的数据文件、日志文件如果混在一起,排障时严重影响效率。尤其是线上事故时,你连哪个日志对应哪个实例都分不清,那叫一个酸爽。

3.2 配置主从:三种方式与各自的使用场景

主从复制的配置方式实际上有三种,很多人只知道其中一两种。

第一种,通过命令行动态设置,适合临时调试和快速验证:

redis-cli -p 6380 replicaof 127.0.0.1 6379

执行之后立刻生效,无需重启。但注意这只是运行时配置,重启 Redis 会丢失。它适合你在测试环境快速验证主从效果,但不适合写入任何启动脚本。

第二种,写进从库的配置文件,这也是生产环境的标准做法。在 6380 实例的 redis.conf 里加上:

replicaof 127.0.0.1 6379 replica-read-only yes

然后启动或者重启该实例。配置文件的好处是持久化,实例重启后主从关系自动恢复。我强烈建议所有生产 Redis 实例都用这种方式管理主从关系,不要依赖命令行动态设置,因为一旦机器重启而你忘了重新设置,整个集群就变成了散沙。

第三种,通过 docker-compose 拉起整个主从环境,适合快速搭一套开发环境。下面是一份可以直接跑的配置,我用的是 Redis 7.x 镜像,网络用自定义 bridge 网络保证容器之间可以互通:

version: '3' services: redis-master: image: redis:7.2 container_name: redis-master command: ["redis-server", "--appendonly", "yes", "--requirepass", "masterpass"] ports: - "6379:6379" networks: - redisnet redis-slaver: image: redis:7.2 container_name: redis-slaver command: ["redis-server", "--replicaof", "redis-master", "6379", "--masterauth", "masterpass", "--appendonly", "yes"] ports: - "6380:6379" networks: - redisnet depends_on: - redis-master networks: redisnet: driver: bridge

注意到我没给从库设置 requirepass,生产环境里从库和主库密码建议保持一致,这里为了演示方便做了简化。还有一点,主库开了密码认证,从库必须用--masterauth指定主库密码,否则从库连接主库会被拒绝认证,这是新手最容易踩的坑。

3.3 验证状态:把 info replication 逐行读透

配置好之后,怎么确认复制真的在工作?别急着写读写测试,先用redis-cli连上从库,执行:

redis-cli -p 6380 info replication

你会看到类似这样的输出:

# Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_read_repl_offset:1234567 slave_repl_offset:1234567 slave_priority:100 connected_slaves:0

这里每个字段都有它的意思,我挑几个重点讲。

master_link_status:up表示从库和主库的连接是正常的,如果显示down,说明连接中断了,优先查网络和认证问题。master_last_io_seconds_ago表示距离上一次跟主库通信过去了多久,如果在不断增长,说明连接虽然没断开,但数据流可能已经卡死。slave_repl_offset和slave_read_repl_offset是从库已经处理到的偏移量,理论上这两个值应该一致;如果slave_read_repl_offset落后太多,说明从库已经读取到了最新数据但还在排队应用。

在主库上执行同样的命令,你会看到connected_slaves:1,后面跟着一行slave0:ip=127.0.0.1,port=6380,state=online,offset=1234567,lag=1。lag=1就是从库上一次心跳到现在经过的秒数,这个值如果持续大于 5,网络基本有抖动。

验证读写效果很简单:在主库写一个 key,在从库读,然后换过来,看看从库能不能写。从库会返回READONLY You can't write against a read only replica,看到这个报错说明从库配置生效了。

注意:如果使用 docker-compose 且主库设了 requirepass,但你忘了在从库的 command 里加 masterauth,从库会一直处于尝试重连的状态。日志里会不断出现-NOAUTH Authentication required,这时候优先检查 masterauth 配置,别去检查网络。

4. 从库参与读流量:负载均衡落地的关键细节

主从复制搭好了,从库也同步了数据,接下来就要让从库真正扛起读流量。这一步看着简单,实际上细节问题非常多。很多团队栽在“客户端根本不走从库”或者“走了从库但数据不一致被投诉”上。

4.1 读写分离的正确姿势:客户端路由是关键

Redis 单机版的主从复制本身不提供任何自动读写分离,也不提供智能 DNS 解析。从库到底承担多少读流量,完全取决于客户端怎么路由请求。换句话说,主从复制只是把数据复制好了,路由策略必须你自己在应用层实现。

这里有几条路可以走。最简单的做法是在业务代码里维护两个连接池,一个是主库连接池专门处理写操作,一个是从库连接池批量处理读操作。优点是不需要引入额外组件,缺点是比较死板,从库列表变化时业务代码要跟着改。稍微好一点的做法是用客户端库自带的读写分离能力,比如 Lettuce 可以配置readFrom策略,配好之后,写命令固定走 master,读命令可以自动分摊到 replica 节点。

但注意,Java 原生 Jedis 官方非常不建议“读写分离自动读从库”,因为它无法感知从库数据落后程度。有一个折中方案:在业务层对一致性要求高的读也强制走主库,比如用户下单前的库存查询,这类数据延迟一秒钟就是事故;而对一致性要求低的读,比如文章列表、热门排行榜,就可以放心走从库。这是我在生产中用下来最稳妥的思路。

下面是一段以 Spring Boot + Lettuce 为例的配置思路,通过两个连接工厂分开管理读写连接:

@Bean public LettuceConnectionFactory masterFactory() { return new LettuceConnectionFactory(hostRedisMaster, portRedisMaster); } @Bean public LettuceConnectionFactory slaveFactory() { return new LettuceConnectionFactory(hostRedisSlave, portRedisSlave); }

然后在 Service 层注入两个 RedisTemplate,约定好哪个方法用哪个 template。别想着在 Repository 层做一刀切,那样过渡阶段容易出大乱子。

4.2 从库的延迟、淘汰策略和一致性补偿

配置好了路由,你还需要监控从库的数据延迟。Redis 的复制命令传播在理想情况下非常快,延迟通常在毫秒级,但一旦主库有大事务或者网络拥塞,从库的延迟会迅速拉大。

这里有两个参数可以帮你判断问题:一个是从库自身计算的slave_repl_offset与主库master_repl_offset的差值,差值越大数据越陈旧;另一个是master_last_io_seconds_ago,它反映的是最近一次 I/O 的时间,如果持续扩大,从库已经读不到主库的新数据了。我见过比较夸张的情况是主库执行了一次FLUSHALL,从库积压了一堆命令还没处理完,读写分离的读请求直接从从库读到了旧数据,业务方把这种问题归结于 Redis 主从坏了。其实核心原因就是读写分离前没有评估延迟阈值。

还有一个容易被忽略的细节:从库也可能会进行键淘汰。Redis 的过期键驱逐策略在主从之间是独立执行的。主库主动淘汰一个过期 key 之后,会向从库发送 DEL 命令,从库才真正删除这个 key。所以在主库和从库的缓存淘汰瞬时窗口里,从库上可能还存着主库已经不存在的 key。如果读请求走了从库而恰好命中这种 key,就会拿到“死数据”。对于缓存场景还好,对于需要精确判断“这个 key 是否存在”的业务,这可能就是 bug。

实践经验:我一般会在从库读路径上添加一层“短时间容忍”的补偿策略,比如允许从库读到最多 2 秒前的数据,超过这个时间阈值就重定向到主库读。实现方式是记录客户端请求时间和写操作时间戳,在 key 的 value 里存一个last_updated_ts,读的时候做时间戳校验。这不是 Redis 官方功能,但确实是很多大厂内部的通用玩法。

5. 高可用进阶:主从复制必须配合 Sentinel

终于要说到哨兵了。前文反复强调主从复制本身不能自动切换,这一节把 Sentinel 的功能、配置和常见套路讲透。

5.1 主从复制单独撑不住高可用

如果只是主从复制,主库宕机的恢复流程是这样的:你需要人工找一台业务影响最小的从库,手动用replicaof no one把它提升为主库,然后通知所有客户端修改主库的 IP 和端口,再重新建立其他从库的复制关系。这个过程从发现故障到恢复,少则五分钟,多则半小时以上。业务方等得起五分钟吗?大概率等不起。

Sentinel 存在的意义就是把这套人工流程自动化。它会持续监控主从节点的健康状态,一旦发现主库不可用,会通过内部投票选出一个新的主库,把其他从库重定向到新主库,最后通过发布订阅机制通知客户端主库地址已经改变。

5.2 最小但完整的哨兵配置实战

假设前面的一主一从已经运行,IP 是 127.0.0.1,端口分别是 6379 和 6380,哨兵我们再起一个 26379 端口。哨兵配置文件长这样:

sentinel monitor mymaster 127.0.0.1 6379 1 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 10000 sentinel parallel-syncs mymaster 1

逐行解释。sentinel monitor定义了监控对象的名字叫 mymaster,监控地址是 127.0.0.1:6379,最后的数字 1 表示至少需要几个哨兵对主库下线达成一致才判定为客观下线。测试环境只有一个哨兵,所以填 1,生产环境至少部署 3 个哨兵,这个数字建议填 2。

down-after-milliseconds表示主库多久没有响应就认为它主观下线。这里设 5000ms,生产环境可以按网络状况调大,比如 10000 到 30000 毫秒,太短容易误判,太长又拉长了故障恢复时间。failover-timeout是故障转移超时时间,如果超过这个时间没完成,哨兵会重新安排。parallel-syncs表示在完成主从切换后,同时允许几个从库对新主库发起全量同步,设置为 1 是为了避免新主库一上来被多个从库的全量同步请求压垮。

运行哨兵:

redis-server /path/to/sentinel.conf --sentinel

然后你可以测试故障转移:直接杀掉主库进程,观察日志,等一会儿连接哨兵,执行sentinel get-master-addr-by-name mymaster,应该返回新主库的地址和端口,也就是原来的从库 6380。

注意:Sentinel 集群 3 个节点中的任意 2 个以上存活才能完成故障转移判定,所以哨兵不能只在一台机器上,否则那台机器挂了,哨兵间无法形成有效投票,故障转移就永远不会发生。

5.3 客户端如何感知主库切换

主库地址变了,客户端怎么知道?有两个方案。老派的方案是客户端直连哨兵,先通过sentinel get-master-addr-by-name mymaster拿到当前主库地址,再订阅哨兵频道+switch-master监听主库切换事件,切换发生时主动刷新连接池。这套机制已经被很多语言的客户端封装好了,比如 Java 的 Lettuce 和 JedisSentinelPool,你不用自己实现。

新派的方案是直接上 Redis Cluster,它在协议层面解决了主从切换的问题,客户端只需要连接任意一个节点,节点会返回 MOVED 错误并告诉客户端应该访问哪个节点。但 Redis Cluster 是一套更重的架构,一般的小系统前期不需要上它。

如果你在开发阶段想快速验证 Sentinel 切换后客户端是否正常工作,最简单的办法是启动 Redis 自带的 redis-cli 直接用-h 哨兵ip -p 哨兵端口连接,不过这个玩法在生产上没什么价值。生产环境还是老老实实用客户端库内置的 Sentinel 支持。

6. 常见问题与故障排查实录

无论原理讲得多通透,排障总归是一场实战。这里把我这几年来遇到的典型问题做个整理,每一个都是踩过坑之后的实话。

6.1 全量同步反复发生

现象:从库日志里频繁出现全量同步,数据同步速度很快但过一会儿又断掉再来一遍。

排查方向按优先级来。先看从库的日志,如果有MASTER <-> REPLICA sync started和Full resync交替出现,重点检查 repl_backlog 是否太小。主库上执行info replication,查看master_repl_offset和slave0的 offset 差值,如果差值经常超过 repl_backlog 大小,那就是 backlog 不够了。调大repl-backlog-size后重启主库,绝大多数情况都能解决。

再来看有没有大 key 引发同步风暴。主库执行redis-cli --bigkeys扫描一次,如果有单个 key 超过几百 MB,复制命令体量也会异常大,容易让从库长期处于忙不过来状态。这种没法靠调整 backlog 解决,只能拆分 key 设计。

6.2 主库延迟抖动、阻塞与 fork 时间过长

现象:主库在某个时间点突然出现读写延迟飙升,持续几十秒后恢复,从库这个时候开始全量同步。

这种问题十有八九是 RDB fork 导致的。主库内存越大,fork 耗时越长,Linux 上 fork 耗时超过几百毫秒的话,主库会有肉眼可见的停顿。排查方法是在主库上执行info stats查看latest_fork_usec字段,这个值是最近一次 fork 消耗的微秒数,如果超过 100000 微秒(100ms),就是很大了。

缓解方案有三个:尽量减少主库内存总量,给系统留足空闲内存;开启repl-diskless-sync yes让从站模式的 RDB 传输不落盘;或者把持久化策略从 AOF + RDB 改成单纯 AOF 或降低 RDB 生成频率。注意,改持久化策略会影响数据安全性,需要结合备份方案一起考虑。

6.3 从库数据与主库不一致

现象:业务反馈从库读出来的数据跟主库不一致,多数是少了新写入的数据,偶尔是多了已经删除的数据。

先看是不是复制链路延迟。执行redis-cli -p 从库端口 info replication,看slave_read_repl_offset与主库master_repl_offset的差距。如果差值为零但数据仍不一致,那问题多半出在客户端路由错了,比如某些写操作也走了从库,或者从库被设置了replica-read-only no之后有人手动写过数据。

再检查是不是本地重启导致的复制错乱。Redis 在从库本地如果开启了 AOF,重启后会优先加载 AOF 文件。如果 AOF 文件不完整或者损坏,从库装载的数据就会跟主库产生差异。这种情况下只能触发一次全量同步:在从库执行replicaof no one再重新replicaof 主库IP 主库端口。

6.4 哨兵误判触发不必要的故障转移

现象:主库没挂,但哨兵把主库切换了,业务连接闪断。

这通常是把down-after-milliseconds配置得太小造成的。主库在做 RDB fork 或者处理复杂命令时,会短暂地停止响应心跳,哨兵等不到响应就判断它主观下线了。解决方法是把这个阈值调大,同时排查主库是否有长时间阻塞的命令,比如慢查询里出现keys *这种。别以为生产没人会用keys *,真的会有人用它做数据盘点,跑一次就是一场灾难。

还有一个策略是给哨兵单独配置主库信息检查,而不是仅仅依赖心跳。比如哨兵可以通过周期性的INFO命令主动询问主库状态,即使心跳没有回应,只要 INFO 还能返回内容,就可以暂时不做客观下线判定。这个功能在不同版本里支持程度不一,旧版本比较弱,升级到新版本会更稳。

最后分享一段个人实操体会

我记得第一次把 Redis 主从从“教程里”搬到“生产上”时,最惨痛的教训是只配了主从没有配哨兵,结果凌晨四点半主库所在机器宕机,而我从三个候选从库里挑了一个数据最全的,手动提升又花了二十分钟。那之后我养成了一个习惯:凡是上了主从复制的环境,哪怕是预发环境,也一定把 Sentinel 一起部署进去。不需要一开始就搞很复杂的架构,一个小集群加三个哨兵,总共也就几台机器的事,但它能让你在最不想醒来的时间里少接一个电话。

另一个小建议是,从库的replica-read-only一定要确认是 yes,而且在业务设计里,从库数据只能作为“参考数据”而不是“事实数据”。你把它当缓存扛压,没问题;你把它当权威源,迟早要出事。主从复制解决的是可用性和扩展性问题,数据一致性的答案在 Redis 里永远是“最终一致”,谁违背这个前提,谁就要在线上付学费。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 10:51:35

Python+Pygame实战:从零构建新年烟花粒子动画系统

简介&#xff1a;面向Python初学者的Pygame图形编程实践资源&#xff0c;以新年烟花动画为项目载体&#xff0c;系统讲解从环境准备、pip安装Pygame到完整代码编写的过程。内容覆盖粒子系统构建、烟花发射与爆炸逻辑、颜色随机设置、背景音乐无限循环播放等关键知识点&#xff…

作者头像 李华
网站建设 2026/10/11 10:50:35

DeepSeek实操指南:从注册到高级功能的完整提效路径

简介&#xff1a;面向广大科技爱好者、学生、研究人员及相关从业者的《DeepSeek新手宝典&#xff1a;从入门到精通的超详细指南》&#xff0c;以PDF文档形式系统讲解DeepSeek的注册登录、网页与移动端安装、界面要素及功能菜单&#xff0c;并重点演示智能问答、编程辅助、创意生…

作者头像 李华
网站建设 2026/10/11 10:49:31

全开源本地去水印系统源码:基于OpenCV与FFmpeg的实现

简介&#xff1a;这套去水印系统源码为全开源交付&#xff0c;所有解析与处理逻辑均在本地实现&#xff0c;不依赖第三方接口&#xff0c;适合个人站长、PHP开发者以及关注隐私的用户快速部署或二次开发。压缩包共21.36MB&#xff0c;内含165个文件&#xff0c;其中76个PHP文件…

作者头像 李华
网站建设 2026/10/11 10:46:46

AI芯片软硬件协同设计的第六环:破解语义坍塌

1. 为什么“AI芯片的软硬件设计”这个编号6特别值得深挖“AI芯片的软硬件设计 6”——看到这个标题&#xff0c;第一反应不是“又一篇泛泛而谈的科普”&#xff0c;而是&#xff1a;前5篇讲了什么&#xff1f;为什么这一篇要单独标号&#xff1f;它到底在序列中承担什么不可替代…

作者头像 李华