metadata:
要使用 Cosmos DB 状态存储,您的数据必须以 JSON 序列化格式发送到 Dapr。仅仅是 JSON 可序列化 是不够的。
如果您使用 Dapr SDK(例如 .NET SDK),SDK 会自动将您的数据序列化为 JSON。
如果您想直接调用 Dapr 的 HTTP 端点,请查看下面分区键部分中的示例(使用 curl)。
对于非 actor 状态操作,Azure Cosmos DB 状态存储将使用请求中提供给 Dapr API 的 key 属性来确定 Cosmos DB 分区键。可以通过在请求中指定一个元数据字段,键为 partitionKey,值为所需的分区来覆盖此设置。
以下操作使用 nihilus 作为发送到 Cosmos DB 的分区键值:
curl -X POST http://localhost:3500/v1.0/state/<store_name> \
-H "Content-Type: application/json"
-d '[
"key": "nihilus",
"value": "darth"
对于非 actor状态操作,如果您想控制 Cosmos DB 分区,可以在元数据中指定它。重用上面的示例,以下是如何将其放在 mypartition 分区下:
curl -X POST http://localhost:3500/v1.0/state/<store_name> \
-H "Content-Type: application/json"
-d '[
"key": "nihilus",
"value": "darth",
"metadata": {
"partitionKey": "mypartition"
对于actor状态操作,分区键由 Dapr 使用 appId、actor 类型和 actor id 生成,以便同一 actor 的数据始终位于同一分区下(您无需指定它)。这是因为 actor 状态操作必须使用事务,而在 Cosmos DB 中,事务中的项目必须位于同一分区。
使用 Microsoft Entra ID 认证设置 Cosmos DB
当使用 Dapr Cosmos DB 状态存储并使用 Microsoft Entra ID 进行认证时,您需要执行一些额外步骤来设置您的环境。
前提条件:
您需要根据Azure 认证页面中的说明创建一个服务主体。您需要服务主体的 ID 以用于下面的命令(请注意,这与您的应用程序的客户端 ID 不同,或您在元数据中用于 azureClientId 的值)。
Azure CLI
以下脚本针对 bash 或 zsh shell 进行了优化
授予您的 Microsoft Entra ID 应用程序访问 Cosmos DB 的权限
您可以在官方文档中找到更多信息,包括分配更细粒度权限的说明。
为了授予您的应用程序访问 Cosmos DB 中存储数据的权限,您需要为 Cosmos DB 数据平面分配一个自定义角色。在此示例中,您将使用内置角色“Cosmos DB 内置数据贡献者”,该角色授予您的应用程序对数据的完全读写访问权限;您可以选择按照官方文档中的说明创建自定义的、精细调整的角色。
# 包含您的 Cosmos DB 的资源组名称
RESOURCE_GROUP="..."
# 您的 Cosmos DB 帐户名称
ACCOUNT_NAME="..."
# 您的服务主体对象的 ID
PRINCIPAL_ID="..."
# "Cosmos DB 内置数据贡献者" 角色的 ID
# 您也可以使用自定义角色的 ID
ROLE_ID="00000000-0000-0000-0000-000000000002"
az cosmosdb sql role assignment create \
--account-name "$ACCOUNT_NAME" \
--resource-group "$RESOURCE_GROUP" \
--scope "/" \
--principal-id "$PRINCIPAL_ID" \
--role-definition-id "$ROLE_ID"
优化 Cosmos DB 以提高批量操作写入性能
如果您正在构建一个仅通过键(id)从 Cosmos DB 读取数据的系统,这是使用状态管理 API 或 actor 时 Dapr 的默认行为,您可以通过排除所有路径的索引来优化 Cosmos DB 以提高写入速度。默认情况下,Cosmos DB 会索引文档内的所有字段。在写入密集型且对文档内的值运行很少或没有查询的系统中,此索引策略会减慢在 Cosmos DB 中写入或更新文档的时间。这在高容量系统中尤为严重。
例如,Cosmos SQL 容器索引的默认 Terraform 定义如下所示:
indexing_policy {
indexing_mode = "consistent"
included_path {
path = "/*"
可以通过排除所有其他字段的索引来强制 Cosmos DB 仅索引 id 和 partitionKey 字段。这可以通过将上述内容更新为如下所示来实现:
indexing_policy {
# 如果您纯粹将容器用作键值存储,也可以将其设置为 "none"。如果您的容器仅用作分布式缓存,这可能适用。
indexing_mode = "consistent"
# 请注意,included_path 已被 excluded_path 替换
excluded_path {
path = "/*"
此优化以状态存储中文档内字段的查询为代价。这可能会影响任何存储过程或 SQL 查询的定义和执行。仅当您使用 Dapr 状态管理 API 或 Dapr actor 与 Cosmos DB 交互时,才建议应用此优化。
优化 Cosmos DB 以节省成本
如果您打算仅将 Cosmos DB 用作键值对,您可能会考虑在将状态对象持久化到状态之前将其转换为 JSON 并压缩,然后在从状态读取时解压缩。这是因为 Cosmos DB 根据给定时间段内(通常为每小时)使用的最大 RU/s 数量来计费。此外,RU 使用量是根据您读取或写入的每 1 KB 数据计算为 1 RU。压缩有助于减少存储在 Cosmos DB 中的数据大小,从而减少 RU 使用量。
这种节省对于 Dapr actor 尤为显著。虽然 Dapr 状态管理 API 在保存之前对您的对象进行 base64 编码,但 Dapr actor 状态以原始格式化 JSON 保存。这意味着多行带有缩进的格式。压缩可以显著减少 actor 状态对象的大小。例如,如果您的 actor 状态对象在 actor 被加载时为 75KB,您将使用 75 RU/s 从状态中读取该对象。如果您随后修改状态对象并使其增长到 100KB,您将使用 100 RU/s 将该对象写入 Cosmos DB,总计 175 RU/s 的 I/O 操作。假设您的 actor 同时处理 1000 个请求每秒,您将需要至少 175,000 RU/s 来满足该负载。通过有效的压缩,大小减少可以达到 90% 的范围,这意味着您只需要大约 17,500 RU/s 来满足负载。
此特定优化仅在您保存大型对象到状态时才有意义。执行压缩和解压缩的性能和内存权衡需要对您的用例有意义。此外,一旦数据保存到状态,它就不可读,也不可查询。仅当您将大型状态对象保存为键值对时,才应采用此优化。
Dapr 组件的基本架构
阅读本指南以获取有关配置状态存储组件的说明
状态管理构建块