掘金 后端 ( ) • 2024-05-09 09:52

引言

对《数据密集型应用系统设计》第五章数据复制中的主从复制的摘要和补充。

复制指将同一份数据冗余存储在多个节点上,节点之间通过网络来同步数据,使之保持一致。通过数据复制方案,有如下好处:

  • 提高可用性:当部分组件出现故障,系统仍然可以继续工作
  • 降低访问延迟:将数据存储在地理位置不同的数据中心,使数据在地理位置更接近用户
  • 增加吞吐量:多台服务器同时处理请求

在复制技术带来高可用性、高性能的同时,也给系统带来了复杂性和更多的可能故障。如果数据一成不变,复制会简单很多,但实际的技术挑战正是处理持续更改的数据。书中介绍了三种流行的方法:主从复制、多主复制、无主复制,并分别讨论了它们的优缺点和技术挑战。本文主要关注于主从复制

基本原理

主从复制的基本原理是:

  1. 指定一个副本为主节点,当处理写请求时,首先发送给主节点,主节点将数据写入本地存储
  2. 主节点写入本地存储后,将数据更改作为复制的日志发送给所有从节点,每个从节点将其应用于本地。因为写入顺序相同,基于状态机理论,最终数据的状态一定是一致的
  3. 在处理读请求时,可以从任意节点读取,但只有主节点才能接受写请求

复制方式

基于系统以何种方式同步数据,可以分为三类:

  • 同步复制:主节点在执行完一个写请求后,必须确认所有从节点都执行完毕,才能回复客户端写入成功
  • 异步复制:主节点执行完写请求后,立即将结果返回客户端,无需等待其他副本是否写入完成
  • 半同步复制:主节点确认至少一个从节点执行完毕即可恢复客户端

同步复制可以明确保证所有数据都处于最新版本,如果主节点发生故障,总是可以在从节点访问到最新的数据。但是如果同步的从节点无法确认,写入就不能视为成功,主节点会阻塞其后的请求。

异步复制的从节点无论数据多么滞后,主节点总是可以继续响应写请求,系统的吞吐性能更好。但是如果主节点发生失败且不可恢复,那么所有尚未同步到从节点的数据都会丢失。

半同步复制是一种折中的设计,保证至少有两个节点拥有最新的数据副本,从节点可以随时接替主节点工作,同时也提高了吞吐性能。

配置新的从节点

配置新的从节点的主要操作步骤如下:

  1. 对主节点的数据副本生成一个一致性快照
  2. 将快照拷贝到新的从节点
  3. 从节点连接到主节点并请求快照点后的数据更改日志
  4. 从节点基于日志应用数据变更

通过一致性快照加追加式日志的好处是不需要锁定数据库来保证一致性,可以实现高可用的目标。

处理节点失效

从节点失效:追赶式恢复

当从节点发生崩溃或主从节点之间的网络发生中断时,从节点可以根据故障前最后一笔事务,在重新上线连接到主节点后,可以请求自这笔日志后所有的数据变更,并将其应用到本地来追赶主节点。

主节点失效:节点切换

主节点发生故障时可以由管理员手动切换,也可以使用共识算法进行自动切换,自动切换的步骤如下:

  1. 确认主节点失效。主节点之间通过定期发送心跳包维系领导者地位,如果一段时间没有收到来自领导者的心跳包,从节点的选举工作流会判定超时而开启新一轮选举。
  2. 选举新的主节点。各节点通过数据差异选择投票。
  3. 重新配置系统使新主节点生效。

在这个过程中,如果两个节点都认为自身是主节点,有发生脑裂的风险。在新主节点并未收到原主节点的所有数据,原主节点又快速上线时,会丢失原主节点上尚未完成复制的写请求。当数据与其他系统协同使用时(如缓存),会导致缓存不一致,引发更多问题。这些问题会在第八章分布式系统的挑战中进一步讨论。

复制日志的实现

基于语句的复制

主节点记录执行的每个操作语句作为日志发送给从节点,从节点会分析并执行这些语句。这是最简单的日志的实现,但是这个方案不适用调用非确定性函数的语句(如NOW获取时间)、自增列和副作用(触发器、存储过程),因此目前首选其他复制实现方案。

基于预写日志传输

在存储引擎中通常每个写操作都是以追加写的方式写入日志,所有对数据库写入的字节序列都会被写入日志,可以使用完全相同的日志在另一个节点上构建副本。

PostgreSQL和Oracle支持这种复制方式。但因为WAL描述的数据结果过于底层,使得复制方案和存储引擎紧密耦合,系统无法支持主从节点上运行不同版本的软件。

基于行的逻辑日志复制

复制和存储引擎可以采用不同的日志格式,将复制与存储逻辑剥离,这种日志被称为逻辑日志。

关系数据库的逻辑日志包括一系列记录来描述数据表行级别的写请求:

  • 行插入:日志包含所有相关列的新值
  • 行删除:唯一标识已删除的行或记录所有列的旧值
  • 行更新:唯一标识更新的行以及所有列的新值

如果一条事务涉及多行的更改,则会产生多个这样的日志记录,并跟随一条标识事务已提交的记录。MySQL的binlog使用这种方式。

复制滞后问题

复制滞后指的是在一个分布式系统中,数据从主节点复制到从节点所经历的延迟。在复制过程中,从节点上的数据可能会落后于主节点,导致数据在各个节点上不一致。

复制滞后会导致一些反常识的问题,在处理复制滞后问题时,可以根据对可用性要求的不同,选择不同的一致性模型解决,在对一致性模型的补充中有详细解释 DDIA | 个人补充:一致性模型

实例:Redis主从复制

启动过程

步骤 主节点操作 从节点操作 1 (等待命令进入) 连接主节点,发送 SYNC 命令 2 开始执行 BGSAVE,并使用缓冲区记录快照点后的写命令 (等待主节点) 3 BGSAVE 执行完毕,向从节点发送快照文件,发送期间继续使用缓冲区记录 载入主节点发送的快照文件 4 向从节点发送缓冲区中的写命令 开始接受外部的读请求 5 缓冲区的命令发送完毕,异步地发送接下来收到的写命令 执行主节点发送的写命令

Redis主从复制的模式可以概括为全量复制、长连接命令传播、增量复制三种。第一次同步时使用全量复制,之后建立长连接进行基于命令的日志传播。当发生故障下线又重新上线后,使用增量复制追赶式恢复。