跳到主要内容
约 5 分钟2 张卡

主备复制

主备复制由主节点确定写入顺序,再把变化复制到备节点。备节点可以承担读取,也可以在主节点故障后接管。能否安全接管,取决于写入成功时数据已经到哪里,以及备节点是否真正应用了这些变化。

1. 面试核心​

先记住这几条,再读正文
  • 主节点确定写入顺序,备节点按相同日志顺序应用确定的变化,才能得到相同状态。
  • 异步复制只在本地确认时,未复制的写入可能随主节点永久故障而丢失。
  • 副本收到日志、持久化日志、应用日志是三个不同阶段,确认落盘不代表查询已经能看到结果。卡 · 日志接收与回放
  • 新副本先加载一致快照,再追赶快照位置之后的日志,两者必须衔接。
  • 安全切换必须保留已确认写入,并隔离旧主的写入能力,确认规则和新主选择规则要配套。卡 · 综合题

2. 写入顺序​

主备复制先由一个节点确定顺序,避免副本各自决定更新先后。客户端把写请求交给主节点,主节点分配日志位置或版本,备节点再按顺序应用这些变化。

状态机是按输入更新当前状态的处理逻辑。副本从相同状态出发,按相同顺序处理输入,而且处理结果是确定的,才能得到相同状态。具体系统还要规定谁有写入权、何时返回成功、如何追赶和接管。MySQL、Redis 与共识系统的保证不同,不能仅凭“主备”两个角色判断数据安全。

3. 写入确认时机​

返回成功之前等待哪些节点,决定了延迟和数据风险。本地完成就返回,省去了复制等待,但尚未复制的写入会随主节点永久故障而丢失;等待备节点确认可以缩小风险窗口,不过还要问清它确认的是收到、落盘还是已经应用。

多数派共识进一步把确认规则与安全选举连接起来,保证接管者保留已提交数据。等待所有副本则会让最慢或故障副本影响每次写入的完成。

3.1 日志接收与回放​

备节点持久化日志后,查询仍可能读到旧值,因为日志还没有应用到可查询的状态。回放就是按日志更新本地状态的过程,它与接收、持久化是不同阶段。

以 PostgreSQL 18 为例,配置同步备库后,synchronous_commit 的取值决定等待到哪一步。这里的 WAL 是数据库用于恢复和复制的预写日志:

配置远端确认条件
remote_write备库已写入操作系统,未要求刷新到持久存储。
on同步备库已把 WAL 刷到持久存储。
remote_apply同步备库已回放事务,查询可见其结果。

这些远端等待以 synchronous_standby_names 指定了同步备库为前提。remote_write 确认的数据能应对备库进程退出,但操作系统崩溃时仍可能丢失。remote_apply 等得更久,换来的是所等待备库已应用该事务,后续查询可以看到结果。

读取路由若指向其他异步副本,仍需检查它的回放位置。

4. 日志复制​

日志复制把每次状态变化按顺序传给备节点,备节点据此更新自己的状态:

通过有序日志复制状态变化

如果一次更新依赖当前时间、随机数或外部调用结果,就要把这些值作为明确输入传递。让各副本各自重新取值,即使执行同一段逻辑,也可能得到不同结果。

日志位置用于发现缺口和重复;发现冲突分支后,要按具体协议修复。已经提交的日志前缀,则由提交与切换规则保证不会丢失。

5. 快照​

快照保存某个日志位置对应的完整状态。新副本先加载这份状态,就不必从最早的日志重新执行:

通过快照传输完整状态

快照必须与后续日志衔接。例如,快照包含到某个位置的全部变化,安装后就从该位置之后继续追赶;传输快照期间产生的新日志也必须保留,否则中间会缺一段。

快照解决历史状态传输,日志传播后续变化。采用哪种复制形式,并不能单独决定读取一致性,仍要看确认、读取和切换协议。

6. 故障切换​

检测到主节点失联,不代表它已经停止写入。新主接管前,既要确认候选节点包含必须保留的写入,也要通过任期检查或写入隔离(fencing)使旧主失去修改权限。否则,即使数据追平了,仍可能出现两个主节点同时写入。

异步复制无法凭空恢复尚未传播的数据。若目标副本缺失这部分内容,应明确数据损失边界。执行流程见故障转移。

7. 复制延迟​

复制延迟可能来自网络传输、磁盘写入或回放速度不足。普通展示如果允许旧值,可以直接读备节点;用户刚写完就要看到结果时,可以读取有效主节点,或等待目标副本应用到这次写入的提交位置。

权限、余额等判断要明确需要多新的数据。监控时同时看日志位置差、时间滞后、积压和追平速度;复制已经停止时,不能继续用上一次采样的低延迟值判断健康。

8. 恢复验证​

恢复完成要以数据和业务结果为准。切换后核对新主是否保留已确认请求,客户端缓存和长连接是否仍指向旧主。旧主重新加入前,隔离可能冲突的分支,并按产品恢复流程处理。

消息、搜索和缓存等派生结果通过重放或对账恢复。故障演练需同时验证数据目标和业务恢复时间。

9. 常见问题​

9.1 副本越多,就越不会丢数据吗?​

不一定。数据安全取决于成功响应前数据保存到了哪里、是否持久化,以及接管时选中了哪个副本。即使副本很多,只要全部落后,最近确认的写入仍可能只存在于主节点。

9.2 等备节点追平自己的写入,就能保证线性一致读吗?​

10 · 面试题卡片​

本页题目与参考回答

10.1 主节点故障后,怎样保证新主不丢失已提交数据并避免双主​

题型:综合题

考察重点

  • 写入确认、日志提交与副本追赶。
  • 多数派选举、任期和 fencing。
  • 快照、故障恢复和数据验证。

相关内容:写入顺序至恢复验证。

参考回答

新主必须保留已确认写入,并隔离旧主的写入能力,才能同时避免数据丢失和双主修改。

写入确认条件必须与新主选择规则配套。只在旧主本地确认的异步复制存在丢失窗口;共识复制则通过安全提交和选举保留已提交前缀。

副本通过快照与日志追平,新主接管前隔离旧写入权。切换后核对已确认请求、旧连接和业务状态,实际保证以所用复制协议为准。

10.2 同步复制已经确认成功,为什么读取备库仍可能得到旧值?​

考察重点:接收、持久化、回放与读取路由。

相关内容:日志接收与回放。

参考回答

同步确认可只等待日志持久化,备库尚未回放时仍会读到旧值。

PostgreSQL 18 配置同步备库后,synchronous_commit=on 等待远端 WAL 持久化。synchronous_commit=remote_apply 还等待事务回放。读取其他异步副本时,仍需等待其追平。

11. 参考资料​

来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明