dot Redis 8 已发布——并且是开源的

了解更多

深入了解无冲突复制数据类型 (CRDTs)

主-主地理分布 让您能够将 Redis 数据库集群实例和数据中心放置在靠近用户的位置,无论他们身在何处。将读副本放置在离用户更近的位置是实现实时响应的正确方法。对于写密集型应用程序来说,这还不够。那么,您如何开发一个主-主地理分布式集群呢?

冲突复制数据类型 (CRDTs) 简介

无冲突复制数据类型 (CRDTs)(又称收敛复制数据类型可交换复制数据类型)是一系列复制数据类型,它们具有一组共同的属性,使得操作能够始终收敛到所有副本之间一致的最终状态。为了确保永远不会发生冲突(没有冲突解决的概念),从而避免在应用程序中引起问题,对 CRDT 数据类型执行的操作必须遵守一组特定的代数属性。

当您创建支持 CRDT 的数据库时,CRDTsRedis Enterprise 中工作,因为标准命令会被等效的 CRDT 实现所替换。让我们看看一个具有 CRDT 等效项的 Redis 数据结构,以及主-主地理分布式复制带来的细微之处。

Redis 中的 Set

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 数据库中运行相同的命令会显示相同的行为,但幕后发生的事情却完全不同。

CRDT 数据库中,所有副本节点可以独立地对“fruits”键应用更改。这使您能够开发真正的地理分布式应用程序。缺点是写入时也会遇到“复制延迟”。这种方法为地理分布式应用程序和实现数据一致性提供了显著优势。

CRDT Set 和 Redis Enterprise

在启用了 CRDT 的 Redis Enterprise 数据库中,Set 操作遵循一些附加规则,其中最重要的两条在合并来自不同节点的操作时应用:

  1. 添加操作优先于删除操作。
  2. 删除操作仅对执行该命令的副本已经看到过的元素有效。

第二条规则有时被称为“观察到的删除”规则,意思是您只能删除在发出命令时能够观察到的项目。

关于复制延迟和一致性模型的说明

虽然最终所有副本节点将收敛到相同的最终状态,但在短期内,发送到 ReplicaEU 的命令可能尚未传播到 ReplicaUS,例如。这种情况虽然通常很短暂,但却是 CRDT 数据结构必须硬编码冲突解决策略的原因。同一 CRDT 数据库中的所有副本将不断同步其状态,以尽可能提供数据集的一致视图,但请记住,CRDTs 对于在网络分区情况下确保高可用性也很有用。 

这意味着为了在您的系统中实现更好的弹性,您需要考虑到系统尚未完全同步可能存在的较长时间。这使得 CRDTs 成为最终一致性的一种形式。这通常被称为强最终一致性,因为它比基于法定配额的更常见类型的复制效率高得多。(有关更多信息,请参阅Redis 关于主-主地理分布的页面。) 

为什么要使用 CRDTs?

CRDTs 将复制作为可交换操作执行。这对于分布式系统具有理想的特性:复制的顺序无关紧要。任意顺序的复制从根本上重塑了许多分布式系统中的竞态条件,并且其效用随着异步性(例如,分布式)的增加而增加。在许多系统中,需要将某些数据的副本存储在副本上。这类系统包括:

  • 在本地设备上存储数据并需要将该数据同步到同一用户拥有的其他设备的移动应用程序(例如日历、笔记、联系人或提醒);
  • 分布式数据库,它维护数据的多个副本(在同一数据中心或不同位置),以便在某些副本离线时系统仍能正常工作;
  • 协作软件,如 Google Docs、Trello、Figma 或许多其他软件,允许多个用户同时修改同一文件或数据
  • 大规模数据存储和处理系统,它们复制数据以实现全局可伸缩性。
  • CRDTs 的用例包括:
    • 分布式缓存
    • 共享会话
    • 多区域物联网数据采集 

更多 CRDT 数据结构

要获取 Redis Enterprise 支持的 CRDT 数据结构完整列表,请查阅官方文档

为 CRDTs 开发

开发一个主-主应用程序的实际要求是什么?

让我们看看可能引起疑问的主要开发方面。

用于 CRDT 数据库的客户端库

一个问题是,是否需要特殊的 Redis 客户端来与 CRDT 数据库交互。答案是否定的——任何普通的 Redis 客户端都可以连接到 CRDT 数据库并直接执行命令。如前所述,命令没有改变,改变的是底层机制。客户端开箱即用不提供的唯一功能是,当距离服务实例最近的地理分布式副本不可用时,能够连接到其他副本的能力。我们正在解决这个问题,但在此期间,如果发生网络分割,您需要在应用程序层面决定何时适合连接到其他区域的副本。

CRDT 应用程序架构

主-主地理分布的优势在于能够跨全球分布的服务实例共享一些状态,同时在操作该状态时体验本地延迟。为了充分利用这一能力,您的服务需要尽可能地依赖 CRDTs 的语义,因此要避免保留在发生故障时会丢失(或变得无法合并)的内部状态。基于 CRDT 的数据库即使在分布式数据库副本无法交换数据时也可用。 

CRDTs 无法解决所有问题,因为它们硬编码了特定的合并规则,这些规则可能不适合您的特定问题。计数器是一个典型的例子CRDT 计数器非常有用,但它们不能用于建模银行账户余额,因为合并可能导致计数器变为负数——而且在应用程序层面无法阻止这种情况发生。换句话说,CRDTs 是一种高效但有细微差别的最终一致性形式,并不适用于本质上是事务性的问题。

测试主-主地理分布式 CRDT 应用程序

测试主-主地理分布式应用程序似乎比测试普通的单主应用程序复杂得多。虽然 CRDTs 确实是您的数据模型的一个复杂组件,但它们的行为在结果方面是完全确定性的。您必须考虑集群分区时的主要情况。如上所述,即使副本已与集群的其余部分断开连接,继续向其发送更新也是可以的,因为连接重新建立后,更新最终会成功合并。您需要确保您的服务在与整个主-主地理分布式CRDT数据库集群断开连接时仍能正常运行。

换句话说,您需要进行的唯一不明显的额外测试应该是关于应用程序在网络分区事件中的行为。

针对全球用户的本地延迟

CRDTs 允许您创建地理分布式应用程序,为您的全部用户提供本地延迟,同时提高整个应用程序的故障恢复能力。虽然并非所有问题都可以通过 CRDTs 解决,但大多数公司可以从中受益的空间非常广阔。举个例子,请参阅 Kyle Davis 的这篇最新博客文章,他在其中展示了如何使用 Sorted Set 实现排行榜——并暗示了 CRDT 版本的优势。

要了解更多关于使用 Redis Enterprise 编写主-主应用程序的信息,请参阅我们的白皮书《CRDTs 幕后揭秘》和官方文档

最终一致性强一致性相比如何? 

强一致性是将任何更新传播到所有数据副本。在最简单的情况下,一系列数据更新来自单个来源,而所有持有数据副本的其他实体都被保证以相同的顺序接收这些更新。

当需要同时更新多个数据副本时,需要一种方法来就数据的正确版本达成一致。强一致性下,一旦某个实体进行任何更新,所有其他副本都会被锁定,以消除冲突解决的需要,直到它们更新到相同的新版本。真相来源将更新以相同的顺序推送到所有实体,以使它们“同步”。 

强一致性中使用的锁定机制与对实时性能的需求不符。这就是最终一致性和 CRDTs 发挥作用的地方。每个集群或节点都可以进行并接收更新,因此无法确保每个副本都获得相同的更新序列。当数据的状态最终得到协调时,不管每个副本接收到更新事件的顺序如何,这就是最终一致性的属性。CRDTs 可以解决去中心化环境中存在的副本上并发更新并发插入引起的复制冲突。