内容目录
Toggle序言
随着资料量的增加以及资料库读写流量的增加,传统资料库的常见的瓶颈也会开始出现。资料复制(Data Replication)是一种有效解决瓶颈的方法,可以通过在多个节点上复制资料来提高资料库的效能、可扩展性和可用性。本文将介绍资料复制的三种主要模型:主从复制(Single-leader replication)、多领导者复制(Multi-leader replication)和点对点复制(Leaderless replication),并分析它们的优缺点。
对于基础资料库知识还不熟悉的读者,可以参考此文章 资料库基础介绍– 系统设计08。对于可扩展性、可用性不熟悉的读者,也可以参考此文章 软体设计非功能性特性– 系统设计03。
资料复制(Data Replication)
资料复制是一种将资料的副本保留在多个节点上的技术,主要是为了实现以下目的:
- 提高效能:通过将资料分散在多个节点上,可以提高资料库的读取和写入效能。
- 提高可扩展性:随着资料量的增长,可以通过添加更多节点来扩展资料库。
- 提高可用性:如果一个节点发生故障,其他节点仍然可以提供资料服务。
资料复制在许多应用程式中都有应用,例如:
- 线上交易处理(OLTP):在OLTP 系统中,资料复写可以用来提高资料库的效能和可用性,用来满足高并发(High Concurrency)读写的需求。
- 灾害修复:在无预警的灾害中,资料复制可以用来将资料复制到异地备份,防止资料遗失。
克隆(Replication)
复制是指在各个节点上,保留多个资料备份,并且最好是地理上有差异的节点,例如:不同国家资料库的备份。透过这些资料复制,用来实现可用性、可扩展性和效能。
读者可以思考一个情境,如果今天在单一资料库的情况下,当资料库损毁,则整个系统都会受到影响。反之,如已经有多份资料复制在不同的资料库,则即便一个资料库损毁,也不会影响到整个系统。
不过以上都是资料复制的优点,但资料复制也带来了复杂性,以下是我简单举出的复杂性例子:
- 如何保持多个资料彼此是一致?
- 应该使用同步复制还是异步复制?
- 如何处理并发写入?
这篇文章会深入讲解资料复制的细节,同首先来解释同步和非同步复制。
同步复制与非同步复制(Synchronous versus asynchronous replication)
如果要实现复制,会分成以下两种,分别为:同步复制以及非同步复制。
这两者有何主要差异呢?
在同步复制中,主节点(Leader Node)会等待辅助节点(Follower Node)更新资料的确认请求。当主节点收到所有辅助节点的确认后,会像向客户端(Client Side)回报成功确认。而在非同步复制中,主节点不会等待辅助节点的确认,而是直接更新资料后,向客户端报告成功。
同步复制优缺点Synchronous Pros & Cons
同步复制的优点是所有辅助节点(Follower Node)都与主节点(Leader Node)完全同步。但是,优点往往伴随着缺点,如果辅助节点(Follower Node),因为故障或是其他原因而没有进行确认,则主节点就会无法回覆用户端,直到收到成功确认为止。因此这样的缺点,会导致从主节点到客户端的回应出现较高的延迟(High Latency)。
非同步复制优缺点Asynchronous Pros & Cons
非同步复制的优点是即使所有辅助节点(Follower Node)都当机了,主节点(Leader Node)也能继续运作。相反的,这样的缺点则是,如果主节点发生故障,未复制到辅助节点的写入将会遗失。
这边提供资料库圣经Designing Data-Intensive Applications 的图例,其中Leader 就是主节点,而Follower 则是辅助节点。

资料复制模型(Data Replication Models)
接下来我会分别针对以下资料库复制的模型,来比较其优缺点:
单主/主从复制(Single Leader / Primary-Secondary Replication)
在主从复制中,一个节点被指定为主节点。主节点负责处理资料写入,并且将所有写入发送到辅助节点并保持它们同步。
主从复制非常适合,读取负载量很大的时候,例如:Youtube 随时都有成千上万的人需要去观看影片,但是比起观看影片,上传影片的量不是很多,因此主从复制的模型很适合这样的情况。我们也可以使用此模型,随着使用者的增加而扩展资料库,提高系统的扩展性。当然,如果将资料复制给许多辅助节点,也会可能会有瓶颈。最后如果我们的写入负载量很大,则主从复制是不合适的。
主从复制的另一个优点是它具有读取弹性,例如:在主节点发生故障的情况下,辅助节点仍然可以处理读取请求,因此,对于读取量很大的系统来说,这是一种不错的解决资料库模型。
另外,如果我们使用非同步复制,则会带来资料复制不一致的问题。可以试想一种情况,如果主节点发生故障,无法将更新的资料传递到到辅助节点,则从不同的资料库读取的资料可能会看到不一致的资料。因此,如果主节点发生故障,任何资料复制的更新,在辅助节点尚未接收与回覆的情况下,都可能会遗失。

主从复制方式(Primary-secondary replication methods)
主从复制可以有许多不同的实作方式:
基于语句的复制(Statement-based replication)
基于语句的复制(Statement-based replication)以下会简称为(SBR),因为我实在找不太到针对繁体中文的翻译,SBR 是MySQL 资料库中使用的方法。在这种实作方式下,主节点可以执行INSERT、UPDATE、DELETE…等等的SQL语法,然后将这些语法写入日志档案。接下来,日志档案就会被传送到辅助节点执行。
虽然SBR,可以解决从主节点复制资料到辅助节点的问题,但其实也有缺点。例如:使用不确定(nondeterministic)的函式,可能会导致主节点和辅助节点上的写入是不相同的。
何谓不确定(nondeterministic)函式?例如:NOW()获得当前时间、RAND()获得一个随机数,都是不确定函式,每次执行函式都会获得不同的结果。
预写日志 (Write-Ahead Log)
预写日志(Write-Ahead Log)以下会简称为(WAL),WAL 是PostgreSQL 和Oracle 中,使用的资料复制技术。在WAL中,当交易(transaction)发生时,它最初被记录在交易日志档案(transactional log file)中,然后该日志档案被写入资料库。接下来,在主资料库上执行纪录操作,然后传送到辅助节点执行。
与SBR 不同,WAL 将交易日志去做处理,而不是SQL 语法,这样的好处是确保遇到非确定性(nondeterministic)函数时的一致性。另外,WAL 将资料直接写入磁碟也有助于在发生故障时进行复原。
例如:PostgreSQL 中执行UPDATE 等操作时,它会先写入交易日志档案和磁碟,然后才处理资料库。交易日志中包含交易ID、资料型别、有被影响的tabla,接下来将变更复制到辅助节点。
当然有优点就有缺点,WAL 的缺点是与资料库内部结构的紧密耦合,主节点与辅助节点如果要进行软体升级版本的时候,就会变得复杂。
逻辑复制(Logical Replication)
逻辑复制(Logical Replication) 也有些人会称为基于行(Row-Based)复制,此方法用在各种关联式资料库,包括PostgreSQL 和MySQL。在这种方法中,对资料库所做的操作与修改都会被纪录,然后复制到辅助节点。
例如,当执行INSERT 或UPDATE 等操作时,会在主节点上撷取整个受影响的Row,其中包含指定Row 的所有列值。然后,撷取下来的变更就会在辅助节点上执行,以确保资料与主节点上的资料保持一致。
多领导者复制(Multi-leader replication)
前面介绍完了主从复制,各位应该也会发现,使用非同步复制的主从复制有一个很致命的缺点。当只有一个主节点,所有的写入操作都必须经过它,这会大幅阻碍其效能。如果主节点发生故障,辅助节点可能就不会更新的资料库。
多领导者复制则是另一种模型,可以用来解决这种高并发系统的问题。多领导者复制顾名思义,有多个主节点处理写入并将其发送到其他主节点和辅助节点进行复制。
这种复制模型,对于离线状态也可以继续运作的系统来说,是很有优势的。我们也可以在维运多的资料中心时,使用这个模型,可以使每一个资料中心都有一个主节点。

冲突
多领导者复制比单一领导者复制提供了更好的效能和可扩展性,但此模型也有一个缺点。因为所有主节点都可能同时处理写入请求,因此它们有可能会修改相同的资料,这样的情境就称之为冲突。
例如:假设两个使用者同时编辑相同的资料栏位。在这种情况下,如果不另外处理这种情境的话,我们就无法得知最终资料的正确性。以下也提供几种常见处理冲突的方法:
避免冲突
一个很简单的想法,如果我们要处理冲突,就应该先防止冲突发生。如果系统可以确保特定记录的所有写入,都是通过同一个主节点,那就不会有冲突的问题。我们可以将客户端的请求,导到相同资料中心,这样就不会有不同资料中心的两个使用者修改同一份文档
但是,如果使用者移动到不同的位置,并且现在位于不同的资料中心附近,则一样会发生冲突。如果发生这种情况,我们需要重新处理请求的流量。在这种情况下,冲突避免方法会失败并导致同时写入。
最后写入获胜
所有节点使用节点本身的本地端时间,来为每次更新分配一个时间戳记(Timestamp)。当发生冲突时,选择最新时间戳记去进行更新。不过这种方法也会有盲点,因为在分散式系统中,节点之间的时间是有可能不同的,如果希望做到时间同步,是会有难度的。也因为时间可能不同,时间偏差就会导致资料遗失。
多领导者复制拓扑(Topology)
以下是多领导者复制的拓扑,包含:环形拓扑、星型拓扑、全对全拓扑等。最常见的是全对全拓朴。在星形和圆形拓朴中,也存在类似的缺点,如果其中一个节点发生故障,可能会影响整个系统。这就是为什么全对全是最常用的拓朴。

点对点/无领导者复制(Peer-to-peer/leaderless replication)
在主从复制中,主节点如果发生问题,就会造成资料库故障。除了多领导者复制以外,也有另一个模型,点对点(Peer-to-peer Replication) 也可以帮助系统与资料库实现读取的可扩展性,但无法提供写入可扩展性。换言之,可以提供高流量读取的扩展性。
点对点复制模型透过非主节点来解决这些问题。所有节点权重相等,可以接受读写请求。 Cassandra 就是使用这样的资料库复制模型。
与主从复制一样,这种复制也会产生不一致,因为当多个节点接受写入请求时,可能会导致并发写入。

结论
资料库复制是一种有效的解决资料库瓶颈的方法,可以提高资料库的效能、可扩展性和可用性。但是,不同的复制模型具有不同的优缺点,因此在选择复制模型时,需要根据具体需求进行权衡。如果喜欢系统设计内容的读者,可以参考其他相关文章。
相关文章
系统设计元件介绍Building Block – 系统设计05
Back-of-the-envelope 封底计算– 系统设计04
引用
Designing Data-Intensive Applications