主从复制 (Master-Slave Replication) 在系统设计与网络技术中的应用

在数据库复制中,我们创建相同数据库的副本,并将其分布在多个节点(副本)上。然而,在拥有多个副本的情况下,一个问题出现了:如何确保每次写操作后所有数据都传播到所有副本?最常见的解决方案是主从复制,也称为主动/被动单主复制

什么是主从复制?

主从复制中有两种类型的节点:主节点和从节点。单个主节点(Leader)作为主数据库,而一个或多个从节点(Follower)维护主节点数据的副本。

  • 主节点负责处理写查询,而从节点负责处理读查询。注意:如果需要,主节点也可以执行读查询。
  • 每当主节点上进行写操作时,它将复制所有数据更改到所有从节点,以保持整个系统中数据的一致性。

整个主从复制的思想如下:

  • 当客户端要执行写查询时,它们将请求发送到主节点,主节点首先将新数据写入其本地存储。
  • 当主节点将新数据写入其本地存储时,它还会将数据更改作为复制日志发送给所有从节点。每个从节点通过从主节点接收日志并按照与主节点上处理它们相同的顺序更新其本地副本。
  • 如果只有一个从数据库可用且它处于脱机状态,则读操作将暂时定向到主数据库,并且一个新的从数据库将取代旧的从数据库。
  • 如果有多个从数据库可用,则读操作将重定向到其他健康的从数据库,并且新的数据库服务器将取代旧的从数据库。
  • 如果主数据库处于脱机状态,一个从数据库将被提升为新的主数据库。现在,所有写操作将在新的主数据库上执行,并且一个新的从数据库将立即取代旧的从数据库进行数据复制。注意:提升新的主数据库更加复杂,因为从数据库中的数据可能不是最新的。如何更新缺失的数据?我们将在本文后面的部分讨论这个想法。

主从复制的应用场景

主从复制适用于读负载较重的情况下,并且需要将读请求分布在多个节点以提高系统性能。由于从节点可以处理读请求,因此它们可以从主节点卸载读流量,并允许主节点专注于处理写请求。

  • 此体系结构提供容错性,并且即使主节点失败,系统也可以继续运行。
  • 主从复制在关系型数据库(如MySQL、PostgreSQL和Oracle)以及NoSQL数据库(如MongoDB、Cassandra、RethinkDB、Espresso等)中使用。
  • 基于领导者的复制不仅局限于数据库。分布式消息代理(如Kafka和RabbitMQ)也使用它来提供高可用的队列。

同步复制与异步复制配置

在主从复制中,一个重要的方面是复制是否同步进行或异步进行。为了理解这一点,让我们考虑一个用户在社交媒体网站上更新个人图片的情况:客户端向Leader发送更新请求。一旦Leader收到请求,它会将数据更改转发给Follower。现在,关键问题是:从节点如何更新其数据?

在同步复制中,客户端在从节点确认更新在所有从节点都已经应用之前会等待Leader的确认。相反,在异步复制中,客户端在所有从节点都已经更新之前就会收到响应。

同步复制和异步复制的优缺点

同步复制的缺点: 如果从节点没有响应(由于崩溃、网络故障或任何其他原因),则写操作无法被处理。

同步复制的优点: 从节点保证具有与Leader一致的最新数据副本。如果Leader突然失败,我们可以确保从节点上仍然可用的数据。

WeChat225d69a6b8c95b19af86f3cc6489a927.png

异步复制的优点和缺点

异步复制的缺点: 如果主节点失败且无法恢复,则尚未复制到从节点的所有写操作都将丢失。这意味着尽管已经向客户端确认,但写操作不保证持久。

异步复制的优点: 即使所有从节点都已滞后,Leader仍可以继续处理写入。弱化持久性可能听起来像是一个坏的权衡,但异步复制仍然广泛使用,特别是如果有许多从节点或者它们分布在地理位置上。

WeChat009de4a825bb455eafce982231561b58.png

总体而言,选择同步复制或异步复制取决于一致性和性能之间的权衡。同步复制提供更强的一致性保证,但也可能导致较长的响应时间。另一方面,异步复制提供更快的响应时间

,但可能会牺牲一致性。

异步复制中的关键问题

  1. 在异步复制中,如果Leader在失败之前尚未收到所有来自旧Leader的写入,可能会出现问题。当前Leader在新Leader产生后重新加入集群时,可能会出现冲突的写入。关键问题是:这些写

入应该怎么处理?思考和探索!

  1. 当用户进行写入时,新数据可能不会立即传达到所有从节点。如果用户在进行写入后立即尝试读取相同数据,从节点可能无法获得该数据,从而导致用户认为他们的数据丢失了。

为了处理上述情况,一种解决方案是在读取用户可能已修改的某些内容时从Leader读取。否则,从Follower读取。例如,在社交媒体平台上,通常只有用户自己的配置文件是可编辑的。因此,最好总是从Leader读取用户自己的配置文件,从Follower读取其他用户的配置文件。

一个共同点:半同步复制

在大多数情况下,复制是非常快速的,对Leader数据库所做的更改会快速传播到Follower。但在某些情况下,复制可能会延迟。例如,如果Follower正在从故障中恢复、系统正在以最大容量运行或节点之间存在网络问题。

另一方面,同步复制要求Leader数据库在Follower确认接收和存储数据之前阻止所有写操作。如果所有的副本都是同步的,这可能导致显著的延迟和性能问题。如果一个副本脱机,整个系统将受到影响。

一个很好的解决方案是使用半同步复制。在这种设置中,一个Follower被指定为同步,而其他Follower是异步的。这样,同步Follower将实时更新所有数据更改,而所有异步Follower将在后台逐渐更新数据。如果同步Follower出现问题或减慢,可以将异步Follower之一提升为替代。

这种配置确保至少两个节点(Leader和一个同步Follower)始终拥有最新的数据副本。让我们通过一个示例来理解:假设用户在网站上更新了他们的个人图片,并且有一个Leader和两个Follower。这里同步复制到Follower 1,异步复制到Follower 2。

WeChatd715d5ec452cfe29fc87d77cc27ba872.png

  • 对于Follower 1: Leader等待直到Follower 1确认收到写入,然后向客户端报告成功,并在其他客户端上使写入可见。
  • 对于Follower 2: Leader发送消息但不等待来自Follower 2的响应。图示显示Follower 2处理消息之前有显着的延迟。

在主从复制中设置新的Follower

假设我们希望增加从节点的数量或替换故障的从节点。我们该如何做呢?如何确保新的从节点拥有主节点准确的数据副本?简单地将数据从主节点复制到新的从节点是不够的,因为客户端正在不断写入数据库。换句话说,标准的数据复制将在不同时间点看到数据库的不同部分。

一个解决方案是锁定Leader或主数据库以确保在复制过程中的一致性。然而,这种方法将不支持高可用性的目标,因为在复制过程中将使Leader数据库不可用于写入。

幸运的是,有一种方法可以在没有任何停机的情况下设置新的从节点。以下是步骤:

  1. 在特定时间点对Leader数据库进行一致性快照。大多数数据库都有此功能,它允许在不锁定整个数据库的情况下进行一致性快照。
  2. 将快照复制到新的从节点。这样确保新的从节点在快照被拍摄时具有完整且准确的主节点数据副本。
  3. 将从节点连接到Leader,并请求从快照拍摄时起发生的所有数据更改。新的从节点必须将快照与主节点的复制日志中的特定位置相关联,以请求从那个点以后的所有数据更改。这个位置在不同的数据库中有不同的名称,例如PostgreSQL中的日志序列号(log sequence number)和MySQL中的binlog coordinates。
  4. 最后,新的从节点将处理自快照以来发生的更改。此过程在新的从节点赶上Leader并能够继续实时处理数据更改时完成。

设置从节点的实际步骤可能因数据库管理系统(DBMS)的不同而大不相同。在某些系统中,该过程是完全自动化的,而在其他系统中,它可能需要管理员手动执行的多步工作流。

处理节点故障和宕机

由于故障或错误,系统中的任何节点都可能宕机。因此,我们的目标是保持系统在个别节点故障时继续运行,并尽量减少节点故障的影响。以下是处理基于Leader的复制中的节点故障的情况的讨论。

处理从节点故障

每个从节点都维护其从Leader接收到的数据更改的日志。这个日志帮

助从节点在故障发生之前识别最后一个处理的事务。

因此,如果从节点发生故障(如崩溃、重新启动或暂时的网络中断),它可以连接到Leader并请求在它断开连接时发生的所有数据更改。一旦它应用这些更改,它将赶上Leader,并可以像以

前一样继续接收数据更改流。

处理Leader故障

处理Leader故障有点复杂,并需要三个关键步骤:1)检测Leader节点故障 2)将一个从节点提升为新Leader 3)配置客户端将其写入发送给新Leader,并将其他从节点开始消费新Leader的数据更改。这个过程也被称为故障切换(failover)

步骤1:检测Leader故障: Leader故障可能由各种原因(崩溃、停电、网络问题等)引起。由于没有绝对可靠的方法来检测故障的原因,因此通常使用超时来假设Leader节点在一段时间内未响应时宕机,通常不超过30秒或1分钟。

步骤2:选择新Leader: 这可以通过选举过程来实现,新Leader由大多数剩余副本选择。为了最小化数据丢失,通常选择具有最新数据更改的副本作为新Leader。但要使所有节点都同意一个新的Leader是一个共识问题。注意:我们将在单独的博客中讨论共识问题的想法。

步骤3:重新配置系统使用新Leader: 客户端需要将其写入请求发送给新Leader。如果旧Leader恢复上线,它可能仍然认为自己是Leader,并不知道已被新Leader替换。因此,系统需要确保旧Leader成为从节点并识别新Leader。

注意: 在半同步复制的情况下,我们将同步的从节点设为新的主节点,因为我们知道它是最新的,并且不会丢失数据。

处理Leader故障时的一些关键挑战!

  • 在异步复制中,可能出现新Leader在故障之前尚未收到所有来自旧Leader的写入的情况。当前Leader重新加入集群后,可能会出现写入冲突的可能性。关键问题是:对这些写入应该采取什么措施?思考和探索!
  • 在某些情况下,分布式系统中的两个节点可能认为自己是Leader,这被称为脑裂(split-brain)情况。这种情况可能非常棘手,因为两个Leader可能都会接受写入而没有解决冲突的过程,这可能导致数据丢失或损坏。如何预防或处理这种脑裂情况?
  • 在声明Leader故障之前,什么是正确的超时时间?超时时间越长,在Leader故障时的恢复时间就越长。然而,如果超时时间太短,可能会出现不必要的故障切换。例如,临时增加负载可能会使节点响应时间超过超时时间,或者网络故障可能导致延迟的数据包。如果系统已经在处理高负载或网络问题,则不必要的故障切换可能会使情况变得更糟。

这篇文章讨论了主从复制(Master-Slave Replication)的概念、应用场景以及相关的同步和异步复制策略,以及处理节点故障和故障切换的方法。主从复制是一种常用的数据库复制技术,用于提高系统性能、容错性和高可用性。了解这些复制策略和处理故障的方法对于设计和维护分布式系统非常重要。

请我吃🍗