在 Azure Cosmos DB 中跨分区重新分配吞吐量(预览版)

默认情况下,Azure Cosmos DB 跨所有物理分区均匀分布预配的吞吐量。 但是,如果工作负荷偏斜(例如,某些分区由于热键或流量不均衡而持续需要更多吞吐量),则可以重新分发吞吐量以优化性能。 还可以将分区上的 RU/秒增加到最大 10,000 RU/秒。 在热分区达到最大 RU/秒限制的情况下,还可以拆分分区。 此功能适用于使用预配吞吐量(手动或自动缩放)的数据库和容器,可以使用 Azure Cosmos DB PowerShell 或 Azure CLI 命令进行管理。

例如,如果在零售应用程序中对 StoreId 数据进行分区,则某些商店的活动可能高于其他商店。 如果注意到这些繁忙的存储频繁地遭遇速率限制(即429错误),那么重新分配吞吐量使您能够将更多资源分配给热分区,从而提高性能。 可以使用或不增加整体吞吐量来执行此作。

注释

拆分具有单个热分区键的热分区不会提高性能。 即使在拆分后,具有相同分区键的所有数据也会位于同一物理分区上。 因此,可以为其配置的最大 RU/秒仍为 10,000 RU/秒。 请参阅此查询以确定物理分区中是否存在单个热分区键。

注释

目前,默认情况下,吞吐量策略设置为“等于”。使用此功能重新分发吞吐量或将自定义吞吐量分配给物理分区后,策略现在将设置为“自定义”。这意味着只能使用此 API 更改吞吐量(RU/s)设置。 阻止在容器或共享吞吐量数据库级别更改吞吐量。 此限制是经过精心设计,以确保保留每个分区的自定义每秒请求单位 (RU/s)。 若要重新启用更改容器或共享吞吐量数据库级别的功能,请将吞吐量策略更改回“等于”。

先决条件

  • 现有的 Azure Cosmos DB 帐户
  • 最新版本的 Azure CLI

    • cosmosdb-preview 已安装扩展

      az extension add --name cosmosdb-preview
      
  • 最新版本的 Azure PowerShell

    • Az.CosmosDB 启用了预发行版功能的模块

      $parameters = @{
          Name = "Az.CosmosDB"
          AllowPrerelease = $true
          Force = $true
      }
      Install-Module @parameters
      

使用 Azure Monitor 指标识别热分区

若要使用 Azure Monitor 指标识别 Azure Cosmos DB 中的热分区,请检查每个物理分区的规范化 RU 消耗,以查找使用率不成比例的分区。

  1. 登录到 Azure 门户 (https://portal.azure.cn)。

  2. 在 Azure 门户中导航到 Azure Cosmos DB 帐户的 “见解 ”部分。

  3. 选择 “吞吐量”。

  4. 打开按 PartitionKeyRangeID 划分的规范化 RU 消耗量 (%)

  5. 筛选到特定数据库和容器。

  6. 查看每个 PartitionKeyRangeId映射到物理分区的图表。

  7. 确定任何 PartitionKeyRangeId 一直显示规范化 RU 消耗量比其他高的情况。 例如,如果一个值始终为 100%,而其他值则为 30% 或更少,则此模式表示热分区。

    显示按 PartitionKeyRangeId 标准化 RU 消耗的图表的截图,其中展示了一个使用率较高的热点分区。

使用诊断日志识别热分区

了解哪些逻辑分区键和物理分区在二级粒度上使用最多的RU/秒,并使用帐户诊断日志中的信息CDBPartitionKeyRUConsumption。 若要使用此功能,请确保已启用PartitionKeyRUConsumption

  1. 导航到 Azure Cosmos DB 帐户的 “诊断日志 ”部分。

  2. 查找随着时间推移使用此查询消耗最多 RU/秒的物理分区(PartitionKeyRangeId)。

    let databaseName = "MyDB" // Replace with database name
    let collectionName = "MyCollection" // Replace with collection name
    CDBPartitionKeyRUConsumption 
    | where TimeGenerated >= ago(24hr)
    | where DatabaseName == databaseName and CollectionName == collectionName
    | where isnotempty(PartitionKey) and isnotempty(PartitionKeyRangeId)
    | summarize sum(RequestCharge) by bin(TimeGenerated, 1s), PartitionKeyRangeId
    | render timechart
    
  3. 对于物理分区,请查找使用此查询每小时消耗最多 RU/秒的顶级逻辑分区键。

    let databaseName = "MyDB"; // Replace with database name
    let collectionName = "MyCollection"; // Replace with collection name
    let partitionKeyRangeId = 0; // Replace with your PartitionKeyRangeId
    CDBPartitionKeyRUConsumption 
    | where TimeGenerated >= ago(24hour)
    | where DatabaseName == databaseName and CollectionName == collectionName
    | where isnotempty(PartitionKey) and isnotempty(PartitionKeyRangeId)
    | where PartitionKeyRangeId == partitionKeyRangeId
    | summarize RU_Usage = sum(RequestCharge) by bin(TimeGenerated, 1h), PartitionKey
    | join kind=inner (
        CDBPartitionKeyRUConsumption
        | where TimeGenerated >= ago(24hour)
        | where DatabaseName == databaseName and CollectionName == collectionName
        | where isnotempty(PartitionKey) and isnotempty(PartitionKeyRangeId)
        | where PartitionKeyRangeId == partitionKeyRangeId
        | summarize TotalRU_PerHour = sum(RequestCharge) by bin(TimeGenerated, 1h)
    ) on TimeGenerated
    | extend RU_Percentage = round(RU_Usage * 100.00 / TotalRU_PerHour, 2)
    | project Hour = TimeGenerated, PartitionKey, RU_Usage, TotalRU_PerHour, RU_Percentage
    | order by Hour asc, RU_Percentage desc
    

    分区键每小时最多 RU/秒的数据行的屏幕截图。

    分区键图表的屏幕截图,其中每小时的 RU/秒数最多。

这些示例查询使用 24 小时进行说明,但最好使用至少七天的历史记录来查看使用模式。

确定每个物理分区的当前吞吐量

若要检查每个物理分区的当前 RU/s,请使用 Azure Monitor 指标 PhysicalPartitionThroughput 并按 PhysicalPartitionId 拆分。 如果每个分区的吞吐量从未更改,则通过将总 RU/秒除以物理分区数来估计每个分区的 RU/秒。

使用 az cosmosdb sql container retrieve-partition-throughput 读取每个物理分区上的当前 RU/s。 此 CLI 命令没有等效的共享吞吐量。

// Container with dedicated RU/s - some partitions
az cosmosdb sql container retrieve-partition-throughput \
    --resource-group "<resource-group-name>" \
    --account-name "<cosmos-account-name>" \
    --database-name "<cosmos-database-name>" \
    --name "<cosmos-container-name>" \
    --physical-partition-ids "<space-separated-list-of-physical-partition-ids>"

// Container with dedicated RU/s - all partitions
az cosmosdb sql container retrieve-partition-throughput \
    --resource-group "<resource-group-name>" \
    --account-name "<cosmos-account-name>" \
    --database-name "<cosmos-database-name>" \
    --name "<cosmos-container-name>"
    --all-partitions

请使用Get-AzCosmosDBSqlContainerPerPartitionThroughputGet-AzCosmosDBSqlDatabasePerPartitionThroughput命令,读取每个物理分区上的当前 RU/秒。

# Container with dedicated RU/s - some partitions
$containerParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    Name = "<cosmos-container-name>"
    PhysicalPartitionIds = @("<PartitionId>", "<PartitionId>")
}
$somePartitionsDedicatedRUContainer = Get-AzCosmosDBSqlContainerPerPartitionThroughput @containerParams

# Container with dedicated RU/s - all partitions
$containerAllParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    Name = "<cosmos-container-name>"
    AllPartitions = $true
}
$allPartitionsDedicatedRUContainer = Get-AzCosmosDBSqlContainerPerPartitionThroughput @containerAllParams

# Database with shared RU/s - some partitions
$databaseParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    PhysicalPartitionIds = @("<PartitionId>", "<PartitionId>")
}
$somePartitionsSharedThroughputDatabase = Get-AzCosmosDBSqlDatabasePerPartitionThroughput @databaseParams

# Database with shared RU/s - all partitions
$databaseAllParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    AllPartitions = $true
}
$allPartitionsSharedThroughputDatabase = Get-AzCosmosDBSqlDatabasePerPartitionThroughput @databaseAllParams

注释

有关查找分区数的详细信息,请参阅 缩放预配吞吐量(RU/s)的最佳做法

计算目标分区的吞吐量

接下来,让我们确定要为最热的物理分区分配多少 RU/s(请求单位每秒)。 调用此设置目标分区。

在设置目标分区的吞吐量之前,请记住以下几点:

  • 可以减少或增加分区上的吞吐量。

  • 物理分区最多只能包含 10,000RU/秒

  • 用户可以将目标分区的吞吐量设置为最大值 20,000RU/秒

    • 将分区设置为大于 10,000 RU/秒的吞吐量值会导致分区拆分,这可能需要一些时间。
  • 如果将分区的 RU/秒设置高于 10,000,它会先获得 10,000 RU/秒。 然后,Azure Cosmos DB 会自动拆分分区,并在新分区之间均匀分配指定的吞吐量。

    • 如果物理分区使用 5,000 RU/秒,并且将其吞吐量设置为 15,000 RU/秒,则 Azure Cosmos DB 首先将 10,000 RU/秒分配给原始分区。 然后它会自动将分区拆分为两个分区,每个分区的吞吐量为每秒 7,500 RU。
  • 如果所有分区的总吞吐量不等于所有分区的当前吞吐量总和,则此作会相应地更新总吞吐量设置。

    • 例如,假设容器有 10,000 RU/s 和两个物理分区 P1 和 P2,每个分区为 5000 RU/秒。 如果将 20,000 RU/秒分配给 P1,则容器的新总吞吐量为 25,000 RU/秒。

方法正确与否取决于工作负载要求。 常见方法包括:

  • 按百分比增加 RU/秒,测量 429 响应的速率,并重复,直到达到所需的吞吐量。

    • 如果你不确定正确的百分比,可以从 10% 开始以保持保守。

    • 如果知道此物理分区需要大部分吞吐量,请首先调整 RU/秒。 将 RU/s 加倍,或将其增加到最大 10,000 RU/秒,以较低者为准。 如果 10,000 RU/s 不够,而且分区中不只有一个热键,可以将设置提升到 20,000 RU/s 来拆分分区。

  • 将 RU/秒增加到 Total consumed RU/s of the physical partition + (Number of 429 responses per second * Average RU charge per request to the partition)

    • 此方法估计如果请求没有速率限制,则“实际”RU/秒消耗量会是什么。

以编程方式更改跨分区的吞吐量

让我们看一个示例:一个容器具有 6,000 RU/秒,总计(无论是手动 6,000 RU/秒还是自动缩放至 6,000 RU/秒),并且有两个物理分区。 在此示例中,我们需要以下吞吐量分布:

物理分区 当前 RU/秒 目标 RU/秒
0 3,000 5,000
1 3,000 20,000

重新分发后,所有分区的总吞吐量将从 6,000 RU/秒更新为 25,000 RU/秒,吞吐量分布:

物理分区 当前 RU/秒
0 5,000
2 10,000
3 10,000

使用 az cosmosdb sql container redistribute-partition-throughput 更新每个物理分区上的 RU/s。 此 CLI 命令没有等效的共享吞吐量。

az cosmosdb sql container redistribute-partition-throughput \
    --resource-group "<resource-group-name>" \
    --account-name "<cosmos-account-name>" \
    --database-name "<cosmos-database-name>" \
    --name "<cosmos-container-name>" \
    --target-partition-info "<0=5000 1=20000...>"

使用 Update-AzCosmosDBSqlContainerPerPartitionThroughput 适用于具有专用 RU/s 的容器,使用 Update-AzCosmosDBSqlDatabasePerPartitionThroughput 命令适用于具有共享 RU/s 的数据库,以便在物理分区之间重新分配吞吐量。 在共享吞吐量数据库中,GUID 字符串表示物理分区的唯一标识符。

$SourcePhysicalPartitionObjects =  @()
$TargetPhysicalPartitionObjects =  @()
$TargetPhysicalPartitionObjects += New-AzCosmosDBPhysicalPartitionThroughputObject -Id "0" -Throughput 5000
$TargetPhysicalPartitionObjects += New-AzCosmosDBPhysicalPartitionThroughputObject -Id "1" -Throughput 20000

# Container with dedicated RU/s
$containerParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    Name = "<cosmos-container-name>"
    TargetPhysicalPartitionThroughputObject = $TargetPhysicalPartitionObjects
	SourcePhysicalPartitionThroughputObject = $SourcePhysicalPartitionObjects
}
Update-AzCosmosDBSqlContainerPerPartitionThroughput @containerParams

# Shared Database RU/s
$dbParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    TargetPhysicalPartitionThroughputObject = $TargetPhysicalPartitionObjects
	SourcePhysicalPartitionThroughputObject = $SourcePhysicalPartitionObjects
}
Update-AzCosmosDBSqlDatabasePerPartitionThroughput @dbParams

重新分发后检查吞吐量

完成重新分发吞吐量后,请检查 Azure Monitor 中的 PhysicalPartitionThroughput 指标。 按 PhysicalPartitionId 维度拆分,以查看每个物理分区有多少 RU/s。 如果需要,请重置每个物理分区的 RU/秒,以均匀分布所有物理分区的吞吐量。

重要

重新分发吞吐量后,只能使用相同的重新分发命令更改吞吐量设置。 若要在所有分区之间均匀分配吞吐量,请使用 az cosmosdb sql container redistribute-partition-throughput 命令。

使用 az cosmosdb sql container redistribute-partition-throughput 和参数 --evenly-distribute 更新每个物理分区上的 RU/s。 此 CLI 命令没有等效的共享吞吐量。

az cosmosdb sql container redistribute-partition-throughput \
    --resource-group "<resource-group-name>" \
    --account-name "<cosmos-account-name>" \
    --database-name "<cosmos-database-name>" \
    --name "<cosmos-container-name>" \
    --evenly-distribute 

Update-AzCosmosDBSqlContainerPerPartitionThroughput 命令用于具有专用 RU/s 的容器,或使用 Update-AzCosmosDBSqlDatabasePerPartitionThroughput 命令结合参数 -EqualDistributionPolicy 在具有共享 RU/s 的数据库中,以在所有物理分区间均匀分配 RU/s。

# Container with dedicated RU/s
$containerParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    Name = "<cosmos-container-name>"
    EqualDistributionPolicy = $true
}
$resetPartitionsDedicatedRUContainer = Update-AzCosmosDBSqlContainerPerPartitionThroughput @containerParams

# Database with dedicated RU/s
$databaseParams = @{
    ResourceGroupName = "<resource-group-name>"
    AccountName = "<cosmos-account-name>"
    DatabaseName = "<cosmos-database-name>"
    EqualDistributionPolicy = $true
}
$resetPartitionsSharedThroughputDatabase = Update-AzCosmosDBSqlDatabasePerPartitionThroughput @databaseParams

验证和监视吞吐量消耗

完成重新分发吞吐量后,请验证并监视 RU/s 消耗,以确保最佳性能。 执行以下步骤:

  1. 在 Azure 门户中导航到 Azure Cosmos DB 帐户的 “指标 ”部分。

  2. 检查 Azure Monitor 中的 PhysicalPartitionThroughput 指标。 按 PhysicalPartitionId 维度拆分,以查看分配给每个物理分区的 RU/s。

  3. 监视 429 响应的总速率和 RU/秒的消耗。

  4. 查看每个分区的 规范化 RU 消耗 量。

    注释

    重新分发后,预期更高的规范化 RU 消耗量,因为 RU/s 分配得更接近每个分区的需求。 有关详细信息,请参阅 标准化的 RU 消耗

  5. 确认 429 异常情况的总发生率已降低。 热分区现在应该有更多的 RU/秒,降低速率限制并提高性能。

局限性

若要使用此预览功能,Azure Cosmos DB 帐户必须满足以下所有条件:

  • 必须具有 Azure Cosmos DB for NoSQL 或 Azure Cosmos DB for MongoDB 帐户。

  • 如果使用 API for MongoDB,版本必须大于或等于 3.6。

  • Azure Cosmos DB 帐户使用预配置的吞吐量(手动或自动缩放)。 跨分区的吞吐量分布不适用于无服务器帐户。