在上一期中,我们开启了一个两部分的系列,探讨常见的数据复制策略。我们了解了主从复制模型——它的同步和异步变体、一致性考虑、故障处理等等。
在本期中,我们将检查两种替代方法——多主复制和无主复制。我们将对比它们的设计,深入了解它们如何工作,并看看它们擅长的用例类型。
到最后,你将理解核心复制模型以及如何根据你的系统需求和约束选择正确的策略。让我们回到上周结束的地方。
多主复制
多主复制(有时称为 leader-leader 复制)涉及使用多个主节点(也称为 leader),每个节点都能够接收和处理写入请求。这些 leader 相互复制数据以保持最新。每个 leader 也可能有 follower 副本用于读取扩展。

这种模型的主要优势是提高了写入可用性。有了多个活动的 leader,一个节点的故障不会中断写入——其他 leader 继续处理写入请求。这改进了主从设计,在主从设计中,leader 故障会停止写入,直到新 leader 可用。

然而,多主复制也带来了一系列挑战。例如,当多个 leader 处理写入请求时,如果 leader 同时修改相同的数据,可能会发生冲突变更。
冲突是多主复制模型中的自然结果,因为多个 leader 可以同时执行写入操作。有效的冲突管理是一项复杂的任务,但这对确保数据一致性和完整性至关重要。

以下是一些常用的冲突解决策略:

最后写入获胜:这是一种简单的方法,最新的变更优先。虽然易于实现,但有可能丢失重要更新。
CRDT(无冲突复制数据类型):CRDT 通过合并冲突变更来实现无缝协调。CRDT 有多种类型,适用于不同类型的数据(如计数器、集合和列表),并自动解决冲突,无需单独的冲突解决过程。
操作转换:通常用于实时协作应用。它考虑操作本身,而不仅仅是数据状态。这种方法实现复杂,但提供细粒度控制。
应用层解决:在某些情况下,冲突解决逻辑可以推送到应用层。应用可以使用领域特定规则,甚至涉及人工干预来解决冲突。
数据分区:另一种选择是在多个 leader 之间分区数据,以最小化冲突变更。然而,实现跨分区事务需要仔细协调,并且需要有效管理繁忙数据分区的潜在热点。值得注意的是,这种策略可以降低集群的整体写入吞吐量。
与主从复制一样,多主系统也容易受到复制延迟和不一致读取的影响。它们会导致 leader 之间的临时不一致,直到更新完全传播。应用必须考虑到这一点进行设计。
多主复制的用例
- 全球用户应用:对于拥有全球用户的应用,多主复制可以通过允许用户与附近的 leader 节点交互来减少终端用户的延迟
- 不能停机的系统:如金融交易平台,可以从拥有多个 leader 中受益。即使一个宕机,操作也能继续
- 重写入负载:对于具有重写入负载的应用,在多个 leader 之间分配写入操作可以防止任何单个节点成为瓶颈
本质上,多主复制对优先考虑高写入可用性、容错性和全球分布数据可访问性的应用特别有用。许多现代数据库可以利用这种复制策略,无论是原生还是通过扩展,成功率各不相同。
多主复制提供高可用性,但需要在共识、冲突检测和解决机制方面进行仔细设计。当实施良好时,它可能是一种最大化写入吞吐量和可用性的强大方法。
在下一节中,我们将探索采用不同方法的无主复制模型。
无主复制
无主复制采用基于法定人数(quorum-based)的方法。这个概念听起来可能有点奇怪,特别是当我们刚刚花了一些时间讨论在清晰层级下运作的模型时。在无主系统中,网络中的任何节点都有权接受写入操作。没有单一 leader 从根本上改变了我们系统的动态。

现在,让我们从一个支撑无主复制的关键概念开始:“法定人数写入和读取”。在没有 leader 的系统中,我们不依赖任何单个节点来验证读取或写入操作。相反,我们追求一定数量节点之间的共识。这个数字称为”法定人数”。使用法定人数方法在高可用性和数据准确性之间取得平衡,因为我们不再需要所有节点之间的完全共识。
在这个系统中,我们使用三个重要值:
- n:系统中节点的总数
- w(写入法定人数):写入被视为成功所需的最小同意节点数
- r(读取法定人数):读取有效所需的最小同意节点数
对于强一致性,一般指导原则是 w + r > n。这确保任何读取与任何写入重叠并返回最新值。
例如,想象一个有 3 个节点的系统(n=3)。如果我们将 w 配置为 2,这意味着我们需要三个节点中的两个确认写入请求,然后才能被视为成功。如果其中一个节点宕机,写入操作仍然可以继续。这个想法对读取也类似。如果 r 设置为 2,读取操作将查询 2 个节点并返回两者之间最新的数据。

本文为学习目的的个人翻译,译文仅供参考。
原文链接:How to Choose a Replication Strategy。
版权归原作者或原刊登方所有。本文为非官方译本;如有不妥,请联系删除。