了解无服务器数据存储中数据一致性的挑战

Amazon DynamoDB、Azure Cosmos DB 和 Google Cloud Firestore 等服务器数据存储提供了自动缩放、按使用计价和减少运行费用。然而,其分布性质在数据一致性方面引入了基本的权衡。当一个应用程序在写完数据后立即读到数据时,用户期望看到最新值。在全球分布的系统中,实现这种保证成为非三进制。 CAP定理[提醒我们,分布式数据存储只能提供三个保障中的两个:一致性、可用性和分位容忍性。无服务器服务通常优先提供可用性和分区容忍性,默认提供 的绝对一致性。理解这种权衡是设计可靠应用程序的第一步。

数据一致性并不是一刀切的属性。 不同的工作量需要不同的保证。 比如,电子商务库存系统决不能过度出售项目,这要求股票更新要有强烈的一致性。 另一方面,社交媒体的反馈可以在新文章传播时容忍几秒钟的滞后。 选择正确的一致性模式和实施互补模式可以确保您的服务器应用程序在仍能从平台弹性中获益的同时,能预测到其行为。

无服务器存储器中的一致模式

强烈的连贯性

强烈的一致性保证每个读数返回最新的写法。在无服务器系统中,这常常是通过从主复制本读取或通过基于法定人数的协议来实现的。像DynamoDB支持[]这样的服务强烈一致地读取[(增加成本和耐久性),Azure Cosmos DB为使用多主复制的全球分布账户提供了强烈的一致性。当金融交易、用户认证或预订系统需要绝对准确性时,使用强烈的一致性。

最终一致性

意外一致性是大多数无服务器数据存储的默认。 这意味着如果没有给数据项写新字, 最终( 通常在毫秒或秒内) 所有复制件都会汇合到相同的值。 这个模型提供了最佳可用性和最低的延迟性。 对于读重工作量、 产品目录和日志系统来说, 短窗口读得 stale 的读数是可以接受的 。

因果关系

因果关系会保留因果关联操作的顺序。如果操作A(更新配置图片)发生在操作B(张贴注释引用该图片)之前,那么任何观察者都会在B之前看到A。这个模型会处于强烈一致性和最终一致性之间,并获得诸如[]Google Cloud Datastore[]等服务的支持。它对于协作编辑、社会信息以及事件命令时的聊天应用程序是有用的。

保持一致性的最佳做法

1. 为每项行动选择适当的一致性模式

而不是为您的整个应用程序选择一个单一的一致性级别,而是按照自己的一致性要求设计每个关键读写操作。在DynamomDB中,您可以指定个人的[ 或[ 呼叫,而将其他读写保留在最终一致。这种混合方法平衡了性能和正确性。记录您的决定,并测试是否在负载中,以确保在可接受的限度内保持耐性。

2. 使用与Sagas或两阶段交割的分散交易

当一个业务流程跨越多个数据存储或服务时,您需要一种机制来维护原子弹性。 分配交易 — 如两阶段承诺(2PC)协议—— 确保每个参与方共同承诺或中止交易。 然而, 2PC 可能缓慢并减少可用性。 一个替代方案是 SAG 模式[, 每一个操作都会发出一个事件, 如果失败, 触发了补偿行动。 许多服务器没有服务器的平台提供内置交易支持 : [[ 迪纳摩DB交易 覆盖多个项目之间的25项行动,而宇宙数据库则支持交易批次操作。

3. 执行解决冲突战略

同步写入多区域部署中的同一数据项会造成冲突。 无服务器存储通常使用 [[FLT: 0]] 最后一写- 赢 [LWW][[FLT: 1] , 保留了最近的时间戳。 虽然简单, LWW 可能会在时钟不同步时丢失数据。 对于更丰富的语义, 请使用 [[FLT: 2] 版本向量 [ 或 [ CRDTs (冲突-自由复制数据类型) [[FLT: 5] 。 DynamotB的有条件更新和版本字段允许您执行乐观的锁定自定义冲突解决。 Cosmos DB提供多种冲突解决政策,包括合并自定义存储程序。

4. 利用《同上》规定的能力开展行动和审查

网络失败或瞬间错误会导致客户端重试, 可能导致重复处理。 设计操作要为 [[ FLT: 0]] 偶数键 [[ [FLT: 1]] 消除了这种风险。 例如, 为每个写入请求指定一个独特的偶数键; 服务器可以复制共享同一密钥的请求。 许多没有服务器的 SDKs 支持偶数键的重试请求都以本地方式写。 将它与重试逻辑中的指数备份和抖动结合起来, 以减少争议, 并保持一致性而不压倒后端 。

5. 监测数据完整性,并进行变革流和审计

在没有服务器的环境中,您可以使用 更改数据捕获(CDC) 特性,如DynamotB流、Cosmos DB 更改种子或Firestore的实时听众来监视所有修改。设置一个羊肉或云函数来验证数据在每次修改后是否不变量。例如,银行应用程序可以订阅账户交易,并核实余额总是等于信用减去借项的总和。定期的审计查询——按时间表运行——可以发现漂移并触发纠正工作流程。

6. 优化数据复制,用于您的使用

全球复制可以改善世界各地用户的耐久性, 但可以增加不一致性。 配置复制时要使用适当的一致性级别, 并考虑使用 [[FLT: 0]] 活动式[[[FLT: 1] vs. [[FLT: 2] 活动式被动 地形。 主动式( 多主机) 提供了较低的写耐久性, 但需要有力的冲突解决。 主动式( 单主机和读的复制机) 提供了更强的写法一致性, 但仍服务于从最接近的复制机读取。 宇宙DB 等服务允许从五个定义明确的一致性级别中选择, 从强到最终, 来匹配您的复制耐久性目标 。

保持一致性的建筑模式

命令查询责任隔离(CQRS)

CQRS 将写模型与读模型分开, 允许每个模型独立优化 。 写到一个很一致的存储处; 读到来自最终一致的预测。 当结合 [[FLT: 0] 事件源 [[[FLT: 1] 方法时, 这个模式特别强大, 将所有状态变化都存储为不可改变的事件 。 如果出现一致性问题, 读模型可以从事件日志中重建 。 Martin Fowler 的 [[FLT: 2] CQRS [[[FLT: 3] 文章提供了很好的概述 。

事件确定和事件一致性

事件源代码存储一系列事件而非当前状态。 因为事件是附件和不可改变的, 它们自然是一致的。 诸如 DynamotB 或 Cosmos DB 之类的服务可以充当事件源代码。 消费者会同步处理事件, 最终构建读取模型。 在罕见的冲突情况下, 您可以从已知的检查点重放事件流。 这种模式可以确保 [ [FLT: 0] 的可持久性和可审计性 [[FLT: 1] , 同时可以直接说明一致性边界。

可靠信箱模式

当一个没有服务器的函数向数据库写到然后向队列发送消息时,这两个操作可能不是原子。 出箱模式[ 是通过在同一交易中存储同一数据库中的信息来解决的。 一个单独的进程(如流处理器)读出发箱并发布消息。 这保证了数据库写入和发送的信息要么承诺,要么同时滚动, 从而保持服务的一致性。 SaaS 供应商, 如 [] AWS Well-Architected 详细描述发箱模式

特殊案件处理:地理分配和离线写作

移动和IOT应用程序通常在下线和后期同步运行. 无服务器的供应商 SDK提供离线持续,通过自定义冲突解决器处理冲突. 例如,与 DynamomDB 的 AWS AppSync 可以根据时间戳或客户端定义的逻辑合并版本. 在使用此类库时,总是在真实的世界网络条件下测试冲突解决逻辑,并监视冲突的数量.

对于多区域的一致性,在可能的情况下使用一致性组-一个由宇宙数据库支持的概念,将相关项目分组,以便它们总是被复制。 这样就防止了用户的概况图在A区更新,但其生物更新(在同一组)尚未到达B区的情况。

测试和验证战略

一致性错误通常只在分布式负载下浮出水面。 写入针对真实的无服务器仿真器或云实例的集成测试, 模拟同时写和读。 诸如 [[FLT: 0]] Jepsen [[FLT: 1] 这样的工具可以验证您的数据存储在网络分区下的表现正确。 对于生产, 执行金丝雀部署, 并在监测一致性度量时将流量逐步转移到新的代码路径。 定义 SLA 的 Staleity( 最大可接受读数据年龄) , 用合成交易来测量它们 。

内 容 提 要

数据在无服务器数据存储中的一致性需要经过精心的建筑选择。 通过理解现有的一致性模型,使用分布式交易或saga模式,设计独家操作,以及利用冲突解决机制,您可以构建既可扩展又可靠的应用程序。 通过变化流和审计来监测您的系统的一致性保障,并采用CQRS、事件源源和发包模式等模式来保持跨服务边界的完整性。 通过这些最佳做法,您的无服务器后端将给用户提供一致、正确的体验 — — 即使其规模可以处理全球流量。