Dapr 状态管理
Dapr 状态管理构建基块简化了状态跟踪,并跨各种数据存储提供高级功能。
分布式应用程序由独立服务组成。 虽然每个服务都应是无状态的,但某些服务必须跟踪状态才能完成业务操作。 请考虑电子商务网站的购物篮服务。
使用 Dapr 状态管理的好处显而易见:
- 它还消除了使用第三方 SDK(例如
StackExchange.Redis
)的复杂性。 - 将基础 Redis 缓存替换为不同类型的数据存储只需要更改组件配置文件。
工作原理
应用程序与 Dapr sidecar 进行交互,以存储和检索键/值数据。 在后台,sidecar API 使用可配置的状态存储组件来持久保存数据。 开发人员可以从不断增长的受支持状态存储集合中选择,这些存储包括 Azure Cosmos DB、SQL Server 和 Cassandra。
图 5-1 显示已启用 Dapr 的购物篮服务如何使用名为 statestore
的 Dapr 状态存储组件存储键/值对
curl http://localhost:3500/v1.0/state/statestore/basket1
该命令返回响应正文中的存储状态:
{ "items": [ { "itemId": "DaprHoodie", "quantity": 1 } ], "customerId": 1 }
一致性
CAP 定理是一组适用于存储状态的分布式系统的原则。 图 5-2 显示了 CAP 定理的三个属性
图 5-2。 CAP 定理。
该定理指出,分布式数据系统将在一致性、可用性和分区容错之间做出权衡。 而且,任何数据存储只能保证三个属性中的两个:
-
一致性 (C)。 群集中的每个节点都会使用最新数据进行响应(即使系统必须阻止请求),直到所有副本都更新。 如果你向“一致性系统”查询当前正在更新的项,直到所有副本都成功更新,才会获得响应。 不过,你将始终收到最新的数据。
-
可用性 (A)。 每个节点都会返回即时响应,即使该响应不是最新数据。 如果你向“可用系统”查询正在更新的项,将获得服务此时可以提供的最佳答案。
-
分区容错 (P)。 保证系统继续运行,即使复制的数据节点发生故障或者与其他复制的数据节点断开连接。
分布式应用程序必须处理 P 属性。 当服务与网络调用相互通信时,会发生网络中断 (P)。 因此,分布式应用程序必须是 AP 或 CP。
AP 应用程序选择可用性,而不选择一致性。 Dapr 通过最终一致性策略支持此选择。 请考虑基础数据存储(例如 Azure CosmosDB),它在多个副本上存储冗余数据。 借助最终一致性,状态存储会将更新写入副本,并完成客户端的写入请求。 之后,存储将异步更新其副本。 读取请求可以从任何副本返回数据(包括尚未收到最新更新的副本)。
CP 应用程序选择一致性,而不选择可用性。 Dapr 通过其强一致性策略支持此选择。 在此方案中,状态存储将在完成写入请求前同步更新所有必需副本(或者,在某些情况下,达到仲裁)。 读取操作将跨副本一致地返回最新数据。
并发
在多用户应用程序中,多个用户可能(同时)更新同一数据。 Dapr 支持使用乐观并发控制 (OCC) 来管理冲突。 OCC 基于以下假设:更新冲突不常见,因为用户处理数据的不同部分。 更有效的做法是假设更新会成功,如果失败则重试。 实现悲观锁定的替代方法可能会影响性能,长时间运行的锁定会导致数据争用。
Dapr 支持使用 ETag 进行乐观并发控制 (OCC)。 ETag 是一个与存储的键/值对的特定版本关联的值。 每次键/值对更新时,ETag 值也会更新。 当客户端检索键/值对时,响应包括当前的 ETag 值。 客户端更新或删除键/值对时,必须将该 ETag 值发送回请求正文中。 如果另一个客户端同时更新了数据,则 ETag 不匹配,请求将失败。 此时,客户端必须检索已更新的数据,再次进行更改,然后重新提交更新。 此策略称为“先写入优先”。
Dapr 还支持“后写入优先”策略。 通过此方法,客户端不会将 ETag 附加到写入请求。 状态存储组件将始终允许更新(即使基础值在会话期间已更改)。 后写入优先非常适用于低数据争用的高吞吐量写入方案。 也可以容忍覆盖偶尔的用户更新。
事务
Dapr 可以将多项更改写入数据存储,作为事务实现的单个操作。 此功能仅适用于支持 ACID 事务的数据存储。 撰写本文时,这些存储包括 Redis、MongoDB、PostgreSQL、SQL Server 和 Azure CosmosDB。
在以下示例中,多项操作将发送到单个事务中的状态存储。 所有操作都必须成功,事务才能提交。 如果一个或多个操作失败,则回退整个事务。
使用 Dapr .NET SDK
Dapr .NET SDK 为 .NET 平台提供特定于语言的支持。 开发人员可以使用DaprClient
中引入的 DaprClient
类来读取和写入数据。
ASP.NET Core 集成
在Nuget添加 Dapr.AspNetCore
在 Program.cs
文件中,在 WebApplication
生成器上调用以下扩展方法:
services.AddDaprClient();