老王经营着一家叫“Redis“的烘焙连锁店。总店(Master)负责研发新配方、掌握核心数据,分店(Slave)负责照方烤面包、服务更多顾客。为了让分店能做出和总店一模一样的产品,老王每天都要把配方同步过去。可问题来了:总店偶尔会停电、断网,如果没人盯着,顾客来了只能空手而归。于是老王雇了一支督导团队(Sentinel)——他们定时给各店发”在吗“的消息,一旦确认总店出了大事,就立刻从分店中选一家升格为新总店,让生意不打烊。这套”配方同步 + 督导巡查 + 紧急升格”的体系,就是 Redis 主从复制与哨兵高可用要讲的故事。

岗位关联

对后端和缓存架构工程师来说,主从复制与哨兵是 Redis 生产环境的“标配安全带”:既能横向扩展读能力,又能在主节点宕机时自动恢复服务,是搭建高可用缓存层的必备技能。

目录
  1. 可视化演示
  2. 主从架构:总店与分店的分工
  3. 全量同步:第一次大搬家
  4. 增量同步:对账补页
  5. 哨兵监控:督导的巡查
  6. 故障转移:紧急升格新总店
  7. 哨兵集群:督导团协作
  8. 脑裂与优化:失联总店的乌龙
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

通过主从复制数据同步流程、哨兵集群监控与故障检测、以及自动故障转移Leader选举三个维度,展示Redis高可用架构的完整机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Redis主从复制机制 全量同步通过RDB快照传输完整数据到从节点 增量同步通过命令传播实时复制主节点写入 Sync=Full(RDB)+Incr(Cmd) 全量+增量两阶段保证数据一致性

主从架构:总店与分店的分工

老王开了家烘焙店,生意好到顾客排队到街角。他决定开两家分店,但有个规矩:配方只有总店能改,分店只负责照着配方做面包。顾客想买新口味的面包,走几步路去分店就行,不用再挤总店。这就是主从复制的朴素版本:一个主节点(Master)负责接收写请求,多个从节点(Slave)负责复制数据并提供读服务。

在 Redis 里,主从复制就是让一个节点当“主”,其余节点当“从”。主节点接收客户端的所有写命令,从节点通过复制主节点的命令流让自己的数据和主节点保持一致。于是数据有了多份副本,一台机器坏了数据还在——这就是“数据冗余”;写走主、读走从——这就是“读写分离”。配置从节点很简单,执行 REPLICAOF 主节点IP 端口 或启动时加 --replicaof 即可。拓扑上最常见的是“一主多从”,还可以做“链式复制”——从节点下面再挂从节点,减轻主节点的分发压力。

从业务视角看,读写分离的收益可以量化:写请求只走主,读请求可以分流到所有从节点,系统的读吞吐量随从节点数量线性增长:

回到烘焙店:配方本只有一本,但每个分店都能按配方烤面包,分店越多,能同时招待的客人就越多。唯一要注意的是,面包口味始终由总店决定,分店绝不能自己研发新配方——在 Redis 中,从节点默认只读,写入会被拒绝。

QPS读=QPS主读+∑i=1nQPS从i\displaystyle QPS_{\text{读}} = QPS_{\text{主读}} + \sum_{i=1}^{n} QPS_{\text{从}_i}
每秒能处理的读请求总数,等于主节点自己读的量,加上 n 个从节点读的量之和。从节点越多,读能力越强。
  1. QPS 读整个主从集群每秒能处理的读请求数量,是衡量读能力的关键指标。
    QPS读QPS_{\text{读}}
  2. QPS 主读主节点自身承担的读请求量,通常是少量管理类查询或无法分流的关键读。
    QPS主读QPS_{\text{主读}}
  3. 求和符号把从 1 号到 n 号每个从节点的读 QPS 累加,n 越大读能力越强。
    ∑i=1nQPS从i\sum_{i=1}^{n} QPS_{\text{从}_i}

全量同步:第一次大搬家

第一家分店开张时,总店已有三年积累的配方。老王把整套配方装订成一本厚厚的《配方全集》,派店员整本送过去。但问题来了:装订这本书花了两小时,这两小时里总店又卖出了十几个新品种,这些没写进书里怎么办?老王让助手拿一本“备忘本”,把新配方一条条记下来,等分店收到《配方全集》,再把备忘本里的内容补传过去。

这就是 Redis 全量同步(Full Resynchronization)的完整过程。从节点第一次连接主节点,或者断线太久已经无法增量续传时,主节点会 fork 出一个子进程生成 RDB 快照;与此同时主节点照常处理写命令,并把新命令写入复制缓冲区(repl_backlog)。快照传完后,从节点把 RDB 加载进内存;紧接着主节点把缓冲区里积压的命令继续发给从节点,从节点再执行一遍,最终追上主节点的进度。

全量同步的总耗时可以拆成三段:

全量同步就像分店开张的第一课:把压箱底的配方整本搬过去。虽然搬运重,但只此一遭,之后配方同步就不再这么大动干戈了。

T全量=TRDB生成+T传输+T加载\displaystyle T_{\text{全量}} = T_{\text{RDB生成}} + T_{\text{传输}} + T_{\text{加载}}
全量同步总时间 = 生成 RDB 快照的时间 + 快照文件网络传输的时间 + 从节点加载快照的时间。数据量越大,每一段都越长。
  1. T 生成主节点 fork 子进程扫描内存生成 RDB 文件所需时间,期间主节点仍可正常服务客户端。
    TRDB生成T_{\text{RDB生成}}
  2. T 传输RDB 文件从主节点通过网络送到从节点的时间,受带宽和文件大小影响。
    T传输T_{\text{传输}}
  3. T 加载从节点收到 RDB 后逐条解析并写回内存的时间,期间从节点还不能提供服务。
    T加载T_{\text{加载}}

增量同步:对账补页

分店运营进入正轨后,老王发现每天要同步的新配方其实就几页。如果每天都重新搬一整本配方全集,太浪费了。于是老王规定:总店和分店各自记一个“配方版本号”——在 Redis 中叫复制偏移量(offset)。每次同步前先对账,缺哪几页就补哪几页,这就是增量同步(Partial Resynchronization)。

Redis 的实现是:主节点维护一个环形的复制积压缓冲区(repl_backlog),最近执行的写命令都留在这里;主从节点各自维护自己的复制偏移量。从节点断线重连后,把自己的偏移量告诉主节点,主节点一算:你想追的位置还落在我的积压缓冲区里,好办,直接从缓冲区把后续命令发给你。可如果从节点落后太多,缓冲区早被新命令覆盖了,那就只能退回全量同步。

判断能否增量同步的条件可以写成:

增量同步像分店日常对账:总店把改动的那几页配方传真过去,分店誊抄一遍,两边版本号对齐,皆大欢喜。

slave_offset≥master_offset−backlog_size\text{slave\_offset} \ge \text{master\_offset} - \text{backlog\_size}
从节点的复制位置,必须仍然落在主节点积压缓冲区能覆盖的范围内。落在线内就增量补发,落在线外就只能全量重来。
  1. slave_offset从节点当前已复制的命令位置,相当于它已经誊抄到配方的第几页。
    slave_offset\text{slave\_offset}
  2. master_offset主节点当前最新的命令位置,相当于总店已经写到了第几页。
    master_offset\text{master\_offset}
  3. backlog_size复制积压缓冲区的容量,相当于总店愿意保留最近多少页的改稿。
    backlog_size\text{backlog\_size}
  4. 不等式含义只要 slave 的位置没有掉出缓冲区保留范围,就可以从缓冲区里补发后续命令;否则只能整本重搬。
    ≥\ge

哨兵监控:督导的巡查

老王事业越来越大,不可能天天盯着每家分店。于是他雇了几名督导——也就是哨兵(Sentinel)。每名督导每隔几秒给总店和分店发一条“在吗?”(PING),收到“在的”(PONG)就放心了。如果连发几条都没回应,督导会在值班日志上记一笔“疑似失联”——这就是主观下线(sdown,subjectively down)。注意,单个督导的判断不一定准,可能只是网络抖动。

所以老王定下规矩:一名督导说失联不算数,必须有多名督导同时说“这家店失联了”,才算“确认失联”——这就是客观下线(odown,objectively down)。这个“多名”的阈值叫 quorum。Redis 哨兵监控的核心就是这套“先怀疑、再确认”的多数派判定逻辑:先由单个哨兵判定 sdown,再由多个哨兵共同确认 odown,最终触发故障转移。

客观下线的判定公式是:

督导的巡查不是一次定生死,而是“一个人怀疑,一群人确认”——这套机制就是为了避免网络抖动造成的误判误切。

count(sdown)≥quorum\text{count}(\text{sdown}) \ge \text{quorum}
判定主节点疑似下线的哨兵人数,达到配置的 quorum 阈值时,才正式宣布主节点客观下线。
  1. count(sdown)统计所有哨兵中给主节点打了“疑似失联”标签的数量。
    count(sdown)\text{count}(\text{sdown})
  2. quorum配置文件设定的阈值,例如 2,表示至少 2 名哨兵都判失联才可信。
    quorum\text{quorum}
  3. 不等号判定人数达到或超过阈值时,哨兵集体认定主节点客观下线,准备切换。
    ≥\ge

故障转移:紧急升格新总店

总店被确认失联后,督导们要开会选一家分店来当新总店。选谁呢?老王给每家分店定了个“优先级”,数字小的优先升格;如果优先级相同,就看谁手里的配方最全,也就是复制偏移量最大;如果还相同,就比谁的编号靠前,即 RUNID 字典序小者优先。选定新总店后,督导团做三件事:通知其他分店改向新总店申请复制、把“新总店是谁”广播给所有客户端、更新自己的本地配置。这套动作就是自动故障转移(Failover)。

Redis 哨兵的选主规则可以概括为一条排序链:

故障转移让客户几乎无感:总店虽然倒了,督导团已经挂好新总店的门牌,食客们继续买面包,只有店员们知道刚刚经历了一场紧急交接。

候选排序:  (priority↑,  offset↓,  runid↑)\text{候选排序}: \; (\text{priority}\uparrow,\; \text{offset}\downarrow,\; \text{runid}\uparrow)
优先级数值小的优先;复制偏移量大的优先;RUNID 字典序小的优先。排在第一位的从节点就是新主节点。
  1. priority 升序从节点的 replica-priority 配置,值越小越有资格成为新主。
    priority↑\text{priority}\uparrow
  2. offset 降序复制偏移量越大,说明从节点数据越接近旧主,切换后丢失的数据越少。
    offset↓\text{offset}\downarrow
  3. runid 升序每个 Redis 实例都有随机 RUNID,优先级和偏移量相同时用它做“抽签”,保证排序唯一。
    runid↑\text{runid}\uparrow

哨兵集群:督导团协作

如果一个连锁集团只雇一名督导,这名督导自己休假或生病时,再赶上总店失联,就没人处理了。所以老王组建了督导团。督导团成员之间通过 Redis 的发布订阅(Pub/Sub)通道互相认识、交换信息。遇到重大决定——比如执行故障转移——不能由单个督导拍板,必须由督导团推选一位“团长”(Leader)来负责执行,其他人监督。

哨兵集群天然要求“多数派原则”:假如有 3 个哨兵,其中一个在分区里联系不上另外两个,它不能自作主张去切换主节点。只有在获得足够票数后,候选哨兵才能拿到故障转移的执行权。这个票数门槛既不能低于配置的 quorum,也不能低于哨兵总数的一半加一:

督导团的存在,让“监控者”自己也成为被监控对象。大家互相盯着、彼此制衡,整个系统就不会因为“某个人走神”而崩溃。

授权票数≥max⁡(quorum,  ⌊nsentinel2⌋+1)\text{授权票数} \ge \max(\text{quorum},\; \lfloor \frac{n_{\text{sentinel}}}{2} \rfloor + 1)
想执行故障转移的哨兵必须拿到足够多的“同意票”,这个数字要同时压过 quorum 和哨兵多数派两条线。
  1. max(quorum, 多数)在配置阈值和多数派阈值之间取大者,防止极少数哨兵在分区中擅自切换。
    max⁡(quorum,  ⌊nsentinel2⌋+1)\max(\text{quorum},\; \lfloor \frac{n_{\text{sentinel}}}{2} \rfloor + 1)
  2. n_sentinel哨兵集群中参与投票的哨兵总数。
    nsentineln_{\text{sentinel}}
  3. 多数派阈值3 个哨兵的多数派是 2,5 个哨兵是 3,保证切换决定代表大多数。
    ⌊nsentinel2⌋+1\lfloor \frac{n_{\text{sentinel}}}{2} \rfloor + 1

脑裂与优化:失联总店的乌龙

最让人哭笑不得的事故是:总店并没有真着火,只是门前的电话线被施工队挖断了。督导团联系不上总店,按流程选了新总店。可老总店并不知道这一切,还在正常接单、正常烤面包——顾客下订单它照收,配方改动它照记。等电话线修好,老总店发现自己已经被“革职”,这段时间独自记下的改动全部作废。这个局面就是“脑裂”(Split-Brain):网络分区把原本的一个系统撕成了两个各自主张的部分。

Redis 用两个参数来扎紧篱笆:min-replicas-to-write 和 min-replicas-max-lag。前者要求主节点只有在至少还有 N 个从节点在线的情况下才允许写入;后者要求这些从节点的最大同步延迟不超过 M 秒。一旦网络分区导致老主节点和所有从节点断开,它就会触发“停止写入”的保护,从而大幅减少脑裂期间产生的孤儿数据:

回到烘焙店:总店一旦发现自己和所有分店失联,就要主动挂出“暂停接单”的牌子,而不是闷头烤面包。虽然会损失一点生意,但至少不会在恢复通信后面对一屋子卖不出去的面包。

可写条件:  #replicas≥min_replicas_to_write  ∧  max⁡(lag)≤min_replicas_max_lag\text{可写条件}: \; \#\text{replicas} \ge \text{min\_replicas\_to\_write} \;\wedge\; \max(\text{lag}) \le \text{min\_replicas\_max\_lag}
主节点只有在“至少还有 N 个从节点在线,并且最大同步延迟不超过 M 秒”时才允许继续接单。两个条件同时满足,写入才放行。
  1. #replicas主节点视角中仍然保持连接和通信的从节点数量。
    #replicas\#\text{replicas}
  2. min_replicas_to_write允许写入所需的最小从节点数,例如 1,达不到就拒绝写入。
    min_replicas_to_write\text{min\_replicas\_to\_write}
  3. max(lag)所有在线从节点中最大的同步延迟秒数。
    max⁡(lag)\max(\text{lag})
  4. min_replicas_max_lag允许的最大延迟阈值,例如 10 秒,延迟太高的集群宁可拒写。
    min_replicas_max_lag\text{min\_replicas\_max\_lag}

AI 应用场景

AI 推荐系统的特征缓存高可用

阶段:模型在线推理前的特征数据存取阶段

解决的问题:推荐模型每秒要读取数百万个用户特征和物品特征,特征全部缓存在 Redis 中。传统单机 Redis 一旦宕机,整个推荐链路直接熔断,用户刷不出内容。采用 Redis 主从 + 哨兵后,从节点分摊读流量,哨兵在主节点故障时自动切换,特征层可用率从 99% 提升到 99.99% 以上。

具体案例:某短视频推荐系统将用户画像与物品特征写入 Redis,采用一主两从三哨兵架构。主节点承接特征更新写入,两个从节点承接每秒约 8 万次的读请求。某天凌晨主节点所在物理机硬件故障,哨兵在约 10 秒内完成客观下线判定、选主与切换,推荐服务无感知恢复。

大模型推理结果缓存

阶段:大模型推理结果复用与缓存阶段

解决的问题:企业私有化部署大模型时,相似问题反复调用推理会带来高昂的 GPU 成本和响应延迟,需要把高频问答结果缓存到 Redis。缓存层自身必须高可用,否则缓存一挂,流量全部回源打穿 GPU。主从复制提供读扩展,哨兵保障缓存层故障自愈。

具体案例:某企业知识库助手的“如何申请发票”等高频率问题答案缓存在 Redis。主节点负责写入新答案,从节点承担查询流量;当主节点所在容器异常重启时,哨兵快速切换,缓存命中率维持在 90% 以上,GPU 推理调用量不因缓存故障而暴涨。

Python 演示

python82 行
# -*- coding: utf-8 -*-"""用 Python 模拟 Redis 主从复制同步与哨兵故障转移的核心流程"""import hashlib  class RedisNode:    """模拟 Redis 节点:维护数据、复制偏移量和写命令日志"""     def __init__(self, name, priority=1):        self.name = name        self.priority = priority        self.runid = hashlib.md5(name.encode()).hexdigest()[:6]        self.data = {}        self.backlog = []        self.offset = 0        self.alive = True     def write(self, key, value):        if not self.alive:            raise RuntimeError(self.name + " is down")        self.data[key] = value        self.backlog.append((key, value))        self.offset += 1     def ping(self):        return self.alive  def full_sync(master, slave):    """全量同步:把主节点数据整体拷贝给从节点"""    slave.data = dict(master.data)    slave.offset = master.offset    print("全量同步完成: %s -> %s, 数据 %d 条"          % (master.name, slave.name, len(slave.data)))  def incremental_sync(master, slave):    """增量同步:从 backlog 中补发从节点落后部分的写命令"""    missed = master.backlog[slave.offset:]    for key, value in missed:        slave.data[key] = value    slave.offset = master.offset    print("增量同步: %s 补发 %d 条命令, offset -> %d"          % (slave.name, len(missed), slave.offset))  def elect_new_master(candidates):    """哨兵选主:priority 小优先, offset 大优先, runid 小优先"""    return min(candidates, key=lambda n: (n.priority, -n.offset, n.runid))  def demo():    master = RedisNode("master", priority=1)    slave_a = RedisNode("slave-a", priority=1)    slave_b = RedisNode("slave-b", priority=2)     master.write("user:1", "alice")    master.write("user:2", "bob")     full_sync(master, slave_a)    full_sync(master, slave_b)     master.write("order:100", "item-42")    master.write("order:101", "item-99")     incremental_sync(master, slave_a)    incremental_sync(master, slave_b)    print("主从数据一致:", master.data == slave_a.data == slave_b.data)     master.alive = False    sentinel_names = ["sentinel-1", "sentinel-2", "sentinel-3"]    sdown = sum(1 for _ in sentinel_names if not master.ping())    quorum = 2    print("哨兵判定: sdown=%d, quorum=%d -> 客观下线=%s"          % (sdown, quorum, sdown >= quorum))     new_master = elect_new_master([slave_a, slave_b])    print("选出新主节点:", new_master.name)  if __name__ == "__main__":    demo()
目的:用纯 Python 模拟 Redis 主从复制的全量/增量同步以及哨兵客观下线判定与选主过程,不依赖真实 Redis 环境。
  1. slave.data = dict(master.data)模拟主节点把 RDB 快照整体拷贝给从节点,是“全量同步”的抽象表达。
  2. self.backlog.append((key, value))每写一条命令都追加到日志中,等价于 Redis 的复制积压缓冲区 repl_backlog。
  3. missed = master.backlog[slave.offset:]根据从节点偏移量切出缺失命令,模拟增量同步只补发落后部分。
  4. key=lambda n: (n.priority, -n.offset, n.runid)用元组排序实现哨兵选主三规则:优先级小、偏移量大、RUNID 小。
  5. sdown = sum(1 for _ in sentinel_names if not master.ping())模拟多个哨兵分别探测主节点,统计主观下线的人数。

常见误区

误区“我往从节点写数据,再从从节点同步回主节点,不就能分担主节点的写压力了吗?”

正解从节点默认是只读的(replica-read-only yes)。往从节点写入会被拒绝,即使侥幸写进去,也只会留在那台节点上,永远不会同步给主节点,反而造成主从数据不一致。就像分店厨师私自改了配方,总店和其他分店完全不知情,做出来的面包味道千奇百怪。

为何常见:习惯了 MySQL 主从双写或半同步的开发者,容易把 Redis 的复制模型等同于通用数据库,忽略了 Redis 从节点是“只读副本”的设计。

误区“哨兵就是帮我看门的人,一个就够了,多配几个浪费资源。”

正解如果只有一个哨兵,它本身就是新的单点。它宕机或所处网络被隔离,就没人监控主节点了。而且客观下线依赖多个哨兵投票,只有一名哨兵时,它的判断就是最终判断,一旦误判就会错误切换。生产环境至少部署 3 个哨兵(奇数个),像督导团一样互相看护。

为何常见:只看到哨兵在监控主从节点,忽略了“监控者自身也需要高可用”这一层。

误区“从节点第一次连主节点,主节点发一个 RDB 快照文件给从节点,加载完就完事了。”

正解RDB 生成需要时间,这期间主节点仍在正常服务,新写命令源源不断进来。只传 RDB 会让从节点缺了生成期间的数据。所以主节点会把生成 RDB 期间的写命令缓存到复制缓冲区,传完快照后再补发。就像先给分店整本老配方,再把印刷期间的新配方手工补上。

为何常见:把“快照”想象成静态拷贝,忽略了 Redis 是持续对外服务、数据时刻在变化的事实。

误区“主节点坏了不是一瞬间就能换吗?我看文档里写着哨兵能自动故障转移。”

正解一次完整故障转移要经历超时等待、主观下线、多个哨兵确认客观下线、Leader 选举、选新主、通知其他从节点、广播给客户端等多个环节,整体耗时通常在几秒到十几秒。如果业务对中断零容忍,还需要客户端配合做本地降级或写缓冲。

为何常见:把“自动”理解为“瞬间”,没有把故障检测的完整链路放进心里,对故障转移的耗时没有预期。

误区“数据都多副本了,还有哨兵看着,不可能丢数据吧?”

正解主从复制是异步的,主节点在自己最新的写命令尚未同步给从节点时宕机,这条命令就丢了。脑裂场景更危险:老主在网络分区期间写入的数据,在新主上任后全部无法同步,等同于丢失。min-replicas-to-write、AOF 持久化可以减少丢失窗口,但无法做到零丢失,这是以可用性换一致性的权衡。

为何常见:混淆了“高可用”与“数据零丢失”,把复制冗余等同于持久化保证。

面试题

Q1. Redis 主从复制中,从节点默认处于什么状态?

单选题 · easy

  • A.可读可写
  • B.只读不可写← 正确答案
  • C.只写不可读
  • D.读写都不可

答案:B。从节点默认 replica-read-only yes,只可读不可写。分店只能照着配方烤面包,不能自己改配方。A 错在从节点不可写,C 错在从节点可读,D 错在从节点具备读能力。

Q2. 关于 Redis 主从复制的作用,下列说法错误的是?

单选题 · easy

  • A.实现数据冗余备份
  • B.实现读写分离扩展
  • C.可以自动故障转移
  • D.提升写请求并发量← 正确答案

答案:D。主从复制让从节点分担读流量,写请求仍集中在主节点,因此不能提升写并发量,D 错误。数据冗余、读写分离是主从复制的基本收益;“自动故障转移”是配合哨兵后获得的能力。

Q3. 从节点第一次连接主节点时,Redis 会执行哪种同步?

单选题 · mid

  • A.增量同步
  • B.全量同步← 正确答案
  • C.命令传播
  • D.哨兵选举

答案:B。新从节点没有复制偏移量,无法和主节点的积压缓冲区对齐,必须先做一次全量同步拿到基线数据。就像新分店没有配方底子,只能整本搬配方,不能只补几页。

Q4. 主节点上的复制积压缓冲区(repl_backlog)最主要的作用是?

单选题 · mid

  • A.持久化全部写入数据
  • B.记录快照生成的时刻
  • C.缓存最近的写命令← 正确答案
  • D.暂存来自从库请求

答案:C。repl_backlog 是一个环形缓冲区,保存最近执行的写命令,供断线重连的从节点增量补发。它不负责持久化所有数据,也不处理从库的读请求。它更像是总店保留的最近几页改稿,够从节点对账补页就行。

Q5. 关于哨兵的“主观下线”和“客观下线”,下列说法正确的是?

多选题 · mid

  • A.单个哨兵判定即为主观下线← 正确答案
  • B.多个哨兵判定才为客观下线← 正确答案
  • C.客观下线需要达到 quorum← 正确答案
  • D.主观下线就立刻切换主节点

答案:ABC。主观下线是单个哨兵自己的判断,客观下线需要多个哨兵投票达到 quorum 后才成立。只有客观下线才会触发故障转移,所以 D 错误。整个流程就像督导先记“疑似失联”,等多人确认后才宣布“彻底失联”。

Q6. 哨兵选出新主节点时,以下哪一项不是其参考依据?

单选题 · mid

  • A.从节点的优先级
  • B.从节点的复制偏移量
  • C.从节点的内存大小← 正确答案
  • D.从节点的运行 ID

答案:C。选主依据依次是 replica-priority 数值小者优先、复制偏移量大者优先、RUNID 字典序小者优先。内存大小不属于选主标准。督导选新总店看的是配方全不全、优先级高低,而不是店面规模。

Q7. 为降低脑裂导致的数据丢失,可以采取的措施包括?

多选题 · hard

  • A.设置从节点数下限← 正确答案
  • B.设置从节点延迟上限← 正确答案
  • C.开启 AOF 持久写盘← 正确答案
  • D.升级更大的内存条

答案:ABC。min-replicas-to-write(从节点数下限)和 min-replicas-max-lag(延迟上限)让老主在失去多数从节点时拒绝写入,是防脑裂的核心配置;开启 AOF 能减少故障恢复时的数据丢失。内存大小与脑裂无关。

Q8. 哨兵执行故障转移前,需要获得的授权票数条件是?

单选题 · hard

  • A.一票即可执行
  • B.达到 quorum 值
  • C.全体哨兵同意
  • D.达到多数与 quorum 的较大值← 正确答案

答案:D。Redis 要求授权票数同时满足“不少于 quorum”和“不少于哨兵总数一半加一”,两者取较大值。防止在分区情况下少量哨兵擅自切换,也防止 quorum 配置过低导致误切。督导团要选团长,既要有内定门槛,也得过半数。

Q9. 从节点断线后重新连接主节点,主节点会怎么处理?

单选题 · easy

  • A.总是发全量 RDB
  • B.判断后再定同步方式← 正确答案
  • C.要求从节点重启
  • D.忽略并断开连接

答案:B。主节点会比较从节点上报的偏移量与积压缓冲区范围,如果落后部分仍在 backlog 内就增量补发,否则退回全量同步。所以不是每次都全量,也不是忽略,而是“先对账,再决定怎么补”。

Q10. 关于哨兵集群部署,以下说法正确的有?

多选题 · hard

  • A.哨兵节点数量通常为奇数← 正确答案
  • B.三个哨兵可组建最小集群← 正确答案
  • C.哨兵之间可互相通信← 正确答案
  • D.哨兵与主从共用端口

答案:ABC。哨兵集群通常部署 3 个或 5 个奇数节点,保证多数派容易达成;3 个哨兵就足以组成最小的高可用监控集群;哨兵之间通过 Pub/Sub 通道通信。哨兵默认端口 26379,与 Redis 数据节点端口 6379 不同,所以 D 错误。