数据复制的三种方法及其问题

前言

复制主要是指通过互联网络在多台机器上保存相同数据的副本。

通过数据复制方案,通常希望达到以下目的:

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

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

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

讨论背景

本章我们将假设数据规模比较小,集群的每一台都可以保存数据集的完整副本

讨论核心

如果复制的数据一成不变,那么复制就非常容易。然而所有的技术挑战都在于处理那些 持续更改的数据

我们将讨论三种流行的复制数据变化的方法

  • 主从复制

  • 多主节点复制

  • 无主节点复制

几乎所有的分布式数据库都使用上述方法中的某一种,而三种方法各有优缺点。

主节点和从节点

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

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

  1. 指定某一个副本为 主副本(主节点)。当用户写数据时,必须将写请求发送给主副本,主副本首先将新数据写入本地存储。

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

  3. 客户端从数据库读数据时,可以在主副本或者从副本上进行查询。再次强调,只有主副本可以写数据。

同步复制和异步复制

复制非常重要的一个设计选项是同步复制还是异步 复制。

如图,从节点1的复制是同步的,即主节点需等待直到从节点1确认完成了写入,然后才会向用户报告成功,并且将最新的写入对其他客户端可见。

而从节点2的复制是异步的:主节点发送完信息之后立即返回,不用等待从节点2的完成确认

同步复制

优点:

  • 一旦向用户确认,从节点可以明确保证完成了与主节点的更新同步,数据处于最新版本。

  • 一旦主节点发生故障,依然可以从从节点继续访问最新数据

缺点:

  • 如果同步的从节点无法完全确认(例如由于从节点发生崩溃,或者网络故障),写入就不能视为成功。主节点会阻塞其后所有的写操作,直到同步副本确认完成。

因此,把所有从节点配置为同步复制有些不切实际。实践中,如果数据库启用的同步复制,通常意味着其中某一个从节点是同步的,而其他节点是异步模式。这种方式有时也称为 半同步

全异步模式:

优点:

  • 不管从节点上数据多么滞后,主节点总是可以继续响应写请求,系统的吞吐性能更好

缺点:

  • 如果主节点发生失败且不可恢复,则所有尚未复制到从节点的写请求都会丢失。即使向客户端确认了写操作,却无法保证数据的持久化。

异步模式这种弱化的持久性听起来是一个非常不靠谱的折中设计,但是异步复制还是被广泛使用。

复制滞后问题

容忍节点故障只是使用复制其中的一个原因。而可扩展性(采用多节点来处理更多的请求)和低延迟(将副本部署在地理上距离用户更近的地方)同样也是至关重要的原因

主从复制要求所有写请求经过主节点,而副本只接受读请求。这种情况下,会出现数据库不一致的情况,如果同时对主节点和从节点发起相同的查询,可能会得到不同的结果。这种不一致只是一个暂时的状态,如果停止写数据库,经过一段时间后,从节点最终会赶上并与主节点保持一致。这种效应也被称为 最终一致性

“最终” 一词有些含糊不清,总的来说,副本落后的程度理论上没有上限。正常情况下可能不足1秒,但是,如果系统已接近设计上限,或者网络存在问题,则滞后可能轻松增加到 几秒甚至几分钟不等。

当滞后时间太长,导致的不一致性不仅仅是一个理论问题,而是会带来重大影响的现实问题。接下来,我们将重点介绍三个复制滞后可能出现的问题,并给出响应的解决思路

读自己的写

许多应用让用户提交一些数据,接下来查看他们所提交的内容,例如评论。对于异步复制存在这样一个问题,用户在写入不久就查看数据,而新数据可能未到底从节点。对用户来讲,看起来似乎是刚刚提交的数据丢失了,显然用户不会高兴。

对于这种情况,我们需要 实现“写后读一致性”,也称为 “读写一致性”。

一些可行的解决方案如下:

  1. 如果用户访问可能会被自己修改的内容,从主节点读取;否则,在从节点读取。这背后就要求有一些方法在实际执行查询之前,就已经知道内容是否可能会被修改。例如,社交网络上的用户首页信息通常只能由所有者编辑,而其他人无法编辑。因此,这就形成了一个简单的规则:总是从主节点读取用户自己的首页配置文件,而在从节点读取其他用户的配置文件。

    如果应用的大部分内容都可能被所有用户修改,那么方法1将不太有效。 它会导致大部分内容都必须经由主节点,这就丧失了读操作的扩展性。此时需要其他方案来判断是否应该从主节点读取。

  2. 跟踪最近更新的时间,如果更新后一分钟内,则总是在主节点读取。比如 修改了一个物品的信息,可以在redis/缓存中添加key,用物品id做唯一标识,设置过期时间,每次读的时候查看是否有这个key,有则从主库读,无则从从库读。

    缺点:如果是分布式每次读都要和redis进行交互,会影响系统吞吐量。

单调读

假定用户从不同副本进行了多次读取,如图所示,用户刷新一个网页,读请求可能被随机路由到某个从节点。

用户2345先后在两个从节点执行了两次完全相同的查询(先是少量滞后的节点,然后是滞后很大的节点),则会出现用户数据向后回滚的奇怪情况

单调读一致性可以确保不会发生这种异常。这是一个比强一致性弱,但比最终一致性强的保证。

实现方式:确保每个用户总是从固定的同一副本执行读取(不同用户可以从不同副本读取)。

例如:基于用户 ID 的 哈希的方法而不是随机选择副本。但如果该副本失效,则用户的查询必须路由到另一个副本。

前缀一致读

第三个由于复制滞后导致因果反常的例子。例如 Poons先生 与 Cake夫人之间的以下对话。

Poons先生:

Cake夫人,你能看到多远的未来

Cake夫人:

通常约 10s

这两句话具有因果关系。现在,假如 第三个人正在通过从节点收听上述对话,(例如群聊),可能会出现顺序相反的异常。

防止这种异常需要引入另一种保证:前缀一致读。该保证是说,对于一系列按照某个顺序发生的写请求,那么读取这些内容时也会按照当时写入的顺序。

这是分区(分片)数据库出现的一个特殊问题。不同分区独立运行,因此不存在全局写入顺序。

一个解决方案是确认任何具有因果关系的写入都交由一个分区来完成,但该方案真实实现效率会大打折扣。

多主节点复制

单主节点复制有一个明显的缺点:

系统只有一个主节点,而所有写入都必须经由主节点。如果由于某种原因,例如与主节点之间的网络中断而导致主节点无法连接,主从复制方案就会影响所有的写入。

对主从复制模型进行自然的扩展,则可以配置多个主节点,每个主节点都可以接受写操作,后面复制的流程类似:处理写的每个主节点都必须将所有更改转发到其他节点。

适用场景

在一个数据中心内别使用多主节点基本没有太大意义,其复杂性已经超过所能带来的好处。但是,在以下场景这种配置则是合理的。

  • 多数据中心

  • 离线客户端操作

  • 协作编辑

处理写冲突

多主复制最大问题是可能发生写冲突,这意味着必须有方案来解决冲突。

例如,两个用户同时编辑 Wiki页面。

  1. 用户1将页面标题 从 A更改成为 B

  2. 用户2将 标题 从 A更改为 C

  3. 每个用户的更改都顺利提交到本地主节点,但是,当更改被异步复制到对方时,却发现存在冲突。注意,正常情况下的单主节点主从复制则不会出现这种情况

避免冲突

处理冲突最理想的策略是避免发生冲突,即如果应用层可以保证对特定记录的写请求总是通过同一个主节点,这样就不会发生写冲突。

但是,有时需要改变事先指定的主节点,例如由于数据中心发生故障,不得不将流量重新路由到其他数据中心,

此时,冲突避免方式不再有效,必须有措施来处理同时写入冲突的可能性。

收敛于一致状态

实现收敛的冲突解决有以下可能的方式

  • 给每个写入分配唯一的 ID,例如,一个时间戳,一个足够长的随机数,一个 UUID或者一个基于键-值的哈希,挑选最高的 ID的 写入作为胜利者,并将其他写入丢弃。如果基于时间戳,这种技术被称为 最后写入者获胜。虽然这种方法很流行,单很容易造成数据丢失。

  • 为一个副本分配一个唯一的 ID,并制定规则,例如序号高的副本写入始终优先于序号低的副本。这种方法也可能数据丢失

  • 以某种方式将这些值合并在一起。例如,按字母顺序排序,然后拼接在一起。

  • 利用预定义好的格式来记录和保留冲突相关的所有信息,然后依靠应用层的逻辑,事后解决冲突(可能会提示用户)

自定义冲突解决逻辑

解决冲突最合适的方式可能还是依靠应用层,所有大多数多主节点复制模型都有工具来让用户编写应用代码来解决冲突。

注意,冲突解决通常用户 单个行或者文档,而不是整个事务。因此,如果有一个原子事务包含不同写请求,每个写请求依然是分开考虑来解决冲突。

拓扑结构

复制的拓扑结构描述了 写请求 从一个节点的传播到其他节点的通信路径。

  • 两个主节点,只存在一个合理的拓扑结构:主节点1必须把所有的写同步到2,反之亦然。

  • 两个以上主节点,则会有多个可能的拓扑结构,如图所示

环形和星形拓扑

写请求需要通过多个节点才能到达所有的副本,即中间节点需要转发从其他节点收到的数据变更。为防止无限循环,每个节点需要赋予一个唯一的标识符,在复制日志中的每个写请求都标记了已通过的节点标识符。如果某个节点收到了包含自身标识符的数据更改,表面该请求已经被处理过,因此会忽略此变更请求,避免重复转发。

问题:如果某一个节点出现故障,在修复之前,会影响其他节点之间复制日志的转发

全部-全部拓扑

优点: 对于链接更密集的拓扑,消息可以沿着不同的路径传播,避免了单点故障,因而有更好的容错性。

缺点:存在某些网络链路比其他链路更快的情况,从而导致复制日志之间的覆盖。

无主节点复制

小结

复制或者多副本技术主要服务于以下目的:

  • 高可用性: 即使某台机器出现故障,系统也能保持正常运行

  • 连接断开与容错:允许应用程序在出现网络中断时继续工作

  • 低延迟:将数据放在在距离用户较近的地方,从而实现更快地交互

  • 可扩展性:采用多副本读取,大幅提高系统读操作的吞吐量

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值