主-主地理分布 让您能够将 Redis 数据库集群实例和 中心放置在靠近用户的位置,无论他们身在何处。将读副本放置在离用户更近的位置是实现实时响应的正确方法。对于写密集型应用程序来说,这还不够。那么,您如何开发一个主-主地理分布式集群呢?
(又称 或 )是一系列复制 类型,它们具有一组共同的属性,使得操作能够始终收敛到所有副本之间一致的最终状态。为了确保永远不会发生冲突(没有 的概念),从而避免在应用程序中引起问题,对 类型执行的操作必须遵守一组特定的代数属性。
当您创建支持 的数据库时, 在 中工作,因为标准命令会被等效的 所替换。让我们看看一个具有 等效项的 Redis ,以及主-主地理分布式 带来的细微之处。
Redis Set 类似于您最喜欢的编程语言标准库中提供的 Set,它提供了添加和删除元素、检查元素是否属于 Set 以及执行集合交集、并集和差集的专门操作。以下是调用实际 Redis 命令的样子:
// 创建一个 Set
> SADD fruits apple pear banana
3
// 测试是否包含 apple
> SISMEMBER fruits apple
1
// 移除一个水果
> SREM fruits banana
1
// 测试它是否仍然存在:
> SISMEMBER fruits banana
0
在启用 CRDT 的 Redis Enterprise 数据库中运行相同的命令会显示相同的行为,但幕后发生的事情却完全不同。
在 数据库中,所有 节点可以独立地对“fruits”键应用更改。这使您能够开发真正的地理分布式应用程序。缺点是写入 时也会遇到“ 延迟”。这种方法为地理分布式应用程序和实现 提供了显著优势。
Set 和
在启用了 CRDT 的 Redis Enterprise 数据库中,Set 操作遵循一些附加规则,其中最重要的两条在合并来自不同节点的操作时应用:
第二条规则有时被称为“观察到的删除”规则,意思是您只能删除在发出命令时能够观察到的项目。
关于复制延迟和一致性模型的说明
虽然最终所有副本节点将收敛到相同的最终状态,但在短期内,发送到 ReplicaEU 的命令可能尚未传播到 ReplicaUS,例如。这种情况虽然通常很短暂,但却是 CRDT 数据结构必须硬编码冲突解决策略的原因。同一 CRDT 数据库中的所有副本将不断同步其状态,以尽可能提供数据集的一致视图,但请记住,CRDTs 对于在网络分区情况下确保高可用性也很有用。
这意味着为了在您的系统中实现更好的弹性,您需要考虑到系统尚未完全同步可能存在的较长时间。这使得 CRDTs 成为最终一致性的一种形式。这通常被称为强最终一致性,因为它比基于法定配额的更常见类型的复制效率高得多。(有关更多信息,请参阅Redis 关于主-主地理分布的页面。)
CRDTs 将 作为可交换操作执行。这对于 具有理想的特性: 的顺序无关紧要。任意顺序的 从根本上重塑了许多 中的竞态条件,并且其效用随着异步性(例如,分布式)的增加而增加。在许多系统中,需要将某些 的副本存储在副本上。这类系统包括:
更多 CRDT 数据结构
要获取 Redis Enterprise 支持的 CRDT 数据结构完整列表,请查阅官方文档。
开发一个主-主应用程序的实际要求是什么?
让我们看看可能引起疑问的主要开发方面。
用于 数据库的客户端库
一个问题是,是否需要特殊的 Redis 客户端来与 CRDT 数据库交互。答案是否定的——任何普通的 Redis 客户端都可以连接到 CRDT 数据库并直接执行命令。如前所述,命令没有改变,改变的是底层机制。客户端开箱即用不提供的唯一功能是,当距离服务实例最近的地理分布式副本不可用时,能够连接到其他副本的能力。我们正在解决这个问题,但在此期间,如果发生网络分割,您需要在应用程序层面决定何时适合连接到其他区域的副本。
应用程序架构
主-主地理分布的优势在于能够跨全球分布的服务实例共享一些状态,同时在操作该状态时体验本地延迟。为了充分利用这一能力,您的服务需要尽可能地依赖 CRDTs 的语义,因此要避免保留在发生故障时会丢失(或变得无法合并)的内部状态。 的数据库即使在分布式数据库副本无法交换 时也可用。
CRDTs 无法解决所有问题,因为它们硬编码了特定的合并规则,这些规则可能不适合您的特定问题。计数器是一个典型的 : 非常有用,但它们不能用于建模银行账户余额,因为合并可能导致 变为负数——而且在应用程序层面无法阻止这种情况发生。换句话说,CRDTs 是一种高效但有细微差别的 形式,并不适用于本质上是事务性的问题。
测试主-主地理分布式 应用程序
测试主-主地理分布式应用程序似乎比测试普通的单主应用程序复杂得多。虽然 CRDTs 确实是您的 模型的一个复杂组件,但它们的行为在结果方面是完全确定性的。您必须考虑集群分区时的主要情况。如上所述,即使 已与集群的其余部分断开连接,继续向其发送更新也是可以的,因为连接重新建立后,更新最终会成功合并。您需要确保您的服务在与整个主-主地理分布式 数据库集群断开连接时仍能正常运行。
换句话说,您需要进行的唯一不明显的额外测试应该是关于应用程序在网络分区事件中的行为。
CRDTs 允许您创建地理分布式应用程序,为您的全部用户提供本地延迟,同时提高整个应用程序的故障恢复能力。虽然并非所有问题都可以通过 CRDTs 解决,但大多数公司可以从中受益的空间非常广阔。举个例子,请参阅 Kyle Davis 的这篇最新博客文章,他在其中展示了如何使用 Sorted Set 实现排行榜——并暗示了 CRDT 版本的优势。
要了解更多关于使用 Redis Enterprise 编写主-主应用程序的信息,请参阅我们的白皮书《CRDTs 幕后揭秘》和官方文档。
是将任何 传播到所有 副本。在最简单的情况下,一系列 更新来自单个来源,而所有持有 的其他实体都被保证以相同的顺序接收这些更新。
当需要同时更新多个 副本时,需要一种方法来就 的正确版本达成一致。 下,一旦某个实体进行任何更新,所有其他副本都会被锁定,以消除 的需要,直到它们更新到相同的新版本。真相来源将更新以相同的顺序推送到所有实体,以使它们“同步”。
中使用的锁定机制与对实时性能的需求不符。这就是 和 CRDTs 发挥作用的地方。每个集群或节点都可以进行并接收更新,因此无法确保每个 都获得相同的更新序列。当 的状态最终得到协调时,不管每个 接收到 事件的顺序如何,这就是 的属性。CRDTs 可以解决去中心化环境中存在的副本上 或 引起的 冲突。