0%

数据复制

复制主要指通过互联网络在多台机器上保存相同数据的副本,通过数据复制方案,人们通常希望达到以下目的:

  • 使数据在地理位置上更接近用户,从而降低访问延迟

  • 当部分组件出现故障,系统依然可以继续工作,从而提高可用性

  • 扩展至多台机器以同时提供数据访问服务,从而提高吞吐量

本章讨论的内容都是在假设数据规模比较小,集群的每一台机器都可以保存数据集的完整副本。在接下来的第6章中,我们讨论单台机器无法容纳整个数据集的情况(即必须分区)。在后面的章节中,我们还将讨论复制过程中可能出现的各种故障,以及该如何处理这些故障。

如果复制的数据一成不变,那么复制就非常容易:只需将数据复制到每个节点,一次即可搞定。然而所有的技术挑战都在于处理哪些持续更改的数据,而这正是本章讨论的核心。我们将讨论是那种流行的复制变化数据的方法:主从复制、多节点复制和无主节点复制。几乎所有的分布式数据库都使用上述方法中的某一种,而三种方法各有优缺点。

主从复制

每个保存数据库完整数据集的节点称之为副本。当有了多个副本,不可避免地会引入一些问题:如何确保所有副本之间的数据是一致的?

对于每一笔数据写入,所有副本都需要随之更新,否则,某些副本将出现不一致。最常见的解决方案是基于主节点的复制,也即主从复制。主从复制的工作原理如下:

  1. 指定某一个副本为主副本(或主节点)。当客户写数据库时,必须将写请求发送给主副本

  2. 其他副本则全称为从副本(或从节点)。主副本把数据写入本地存储后,将数据更改为复制的日志或更改流发送给所有从副本。每个从副本获得更改日志后将其应用到本地,且严格保持与主副本相同的写入顺序。

  3. 客户端从数据库中读数据时,既可以在主副本也可以在从副本上执行查询。

//TODO: 贴图

许多关系型数据库都内置支持主从复制,例如PostgresSQL、Mysql、SQL Server。一些非关系型数据库如MongoDB、RethinkDB和Espresso也支持主从复制。另外,主从复制技术也不仅限于数据库,还广泛应用于分布式消息队列如Kafka和RabbitMQ,以及一些网络文件系统和复制块设备(如DRBD)

同步复制与异步复制

复制非常重要的一个设计选项是同步复制还是异步复制。对于关系数据库系统,同步或异步通常是一个可配置的选项;而其他系统则可能是硬性指定或者只能二选一。

结合一个例子,假设网站用户需要更新首页的头像图片。其基本流程是,客户将更新请求发送给主节点,主节点接收到请求,接下来将数据更新转发给从节点。最后,由主节点来通知客户端更新完成。

TODO://贴图

在上图中,从节点1的复制是同步的,即主节点需等待直到从节点1确认完成了写入,然后才会向用户报告完成,并且将最新的写入对其他客户端可见。而从节点2的复制是异步的:主节点发送完消息之后立即返回,不用等待从节点2完成确认。

从节点2在接收到复制日志并完成数据同步有一段延迟,通常情况下,复制速度会非常快,例如多数数据库系统可以在一秒之内完成所有从节点的更新,但是,系统其实并没有保证一定会在多长时间内完成复制。有些情况下,从节点可能落后主节点几分钟甚至更长时间,例如,由于从节点刚从故障中恢复,或者系统已经接近最大设计上限,或者节点之间的网络出现问题。

同步复制的优点是,一旦向用户确认,从节点可以明确保证完成了与主节点的更新同步,数据已经处于最新版本。万一主节点发生故障,总是可以在从节点继续访问最新数据。缺点则是,如果同步的从节点无法完成确认(例如由于从节点发生崩溃,或者网络故障,或任何其他原因),写入就不能视为成功。节点会阻塞所有的写操作,直到同步副本确认完成。

因此,把所有的节点都配置为同步复制有些不切实际。因为这样的话,任何一个同步节点的中断都会导致整个系统更新停滞不前。实践中,如果数据库启用了同步复制,通常意味着其中某一个从节点是同步的,而其他节点则是异步模式。万一同步的从节点变得不可用或性能下降,则将另一个异步的从节点提升为同步模型。这样可以保证至少有两个节点(即主节点和一个同步从节点)拥有最新的数据副本。这种配置有时也称为半同步。

主从复制还经常会被配置为全异步模式。此时如果主节点发送失败且不可恢复,则所有尚未复制到从节点的写请求都会丢失。这意味着即使向客户端确认了写操作,却无法保证数据一定会持久化存储到。但全异步配置的优点则是,不管从节点上数据多么滞后,主节点总是可以继续响应写请求,系统的吞吐性能更好。

全异步模式这种弱化的持久性听起来是一个非常不靠谱的折中设计,但是异步复制还是被广泛使用,特别是那些从节点数量巨大或者分布于广域地理环境。

配置新的从节点

如果出现一下情况时,如需要增加副本数以提高容错能力,或者替换失败的副本,就需要考虑增加新的从节点,但如何确保新的从节点和主节点保持数据一致呢?

简单地将数据文件从一个节点复制到另一个节点通常是不够的,主要是因为客户端仍在不断向数据库写入新数据,数据始终处于不断变化之中,因此常规的文件拷贝方式将会导致不同节点上呈现不同时间点的数据,这不是我们所期待的。

或许应该考虑锁定数据库(使其不可写)来使磁盘上的文件保持一致,但这会违反高可用的设计目标,好在我们可以做到不停机、数据服务不中断的前提下完成从节点的设置。逻辑上的主要操作步骤如下:

  1. 在某个时间点对主节点的数据副本产生一个一致性快照,这样避免长时间锁定整个数据库。
  2. 将此快照拷贝到新的从节点
  3. 从节点连接到主节点请求快照点所发生的数据更改日志。因为在第一步创建快照时,快照与系统复制日志的某个确定位置相关联。
  4. 获取日志之后,从节点来应用这些快照点之后所有数据变更,这个步骤称之为追赶。

建立新的从副本具体操作步骤可能因数据库系统而异,某些系统中,这个过程是全自动化的,而在某些系统中由于所设计的步骤、流程可能会比较复杂,甚至需要管理员手动介入。

处理节点失效