本文为开发人员提供了一种对发往 Azure Cosmos DB 的请求进行速率限制的方法。 实现此模式可以减少错误,并提高超出了目标数据库或容器预配吞吐量的工作负载的总体性能。
Azure Cosmos DB 中超出预配吞吐量的请求可能会导致暂时性故障,例如 TooManyRequests、Timeout 和 ServiceUnavailable。 通常,在有可用容量时你会重试这些请求,而且重试将会成功。 但是,此方法可能导致大量请求沿着代码中的错误路径,并且通常会导致吞吐量减少。
将客户端工作负载流量与服务器端预配吞吐量进行匹配,可以实现最佳系统性能(按照成本和时间来度量)。
假设出现了下面这种情景:
- 创建具有 20,000 RU/秒的 Azure Cosmos DB 帐户。
- 应用程序需要处理包含 10,000 条记录的引入作业,处理其中的每条记录需要消耗 10 个请求单位 (RU)。 完成此作业所需的总容量为 100,000 RU。
- 将整个作业发送至 Azure Cosmos DB,并且预计会出现大量的瞬态故障和需要重复尝试的大量请求。 之所以出现这种状况,是因为作业所需的请求单位总数 (100,000) 远远超过了预配的上限 (20,000)。 大约有 2,000 条记录被接受进入数据库,但约有 8,000 条记录被拒绝。 重试时,将大约 8,000 条记录发送到 Azure Cosmos DB,其中约 2,000 条记录被接受, 等等。 预期此模式会发送大约 30,000 条记录,而不是 10,000 条记录。
- 你选择将这些请求均匀地分布在 5 秒钟内发送,这样就可以预期不会出现任何错误,并且总体吞吐量更快,因为每批请求的数量不会超过预设的 20,000。
可以通过在代码中引入速率限制机制,在一段时间内分散发送请求。
为容器预配的 RU 将在一定数量的物理分区之间均匀共享。 在前面的示例中,如果 Azure Cosmos DB 预配了两个物理分区,则每个分区的 RU 为 10 K RU。
有关请求单位的详细信息,请参阅 Azure Cosmos DB 中的 Request Units。 有关如何估算工作负载消耗的 RU 数的详细信息,请参阅请求单位注意事项。 有关Azure Cosmos DB 分区的详细信息,请参阅 Azure Cosmos DB 中的分区和水平缩放。
方法
实现速率限制的方法类似于:
- 分析应用程序,以获取有关所用的写入和读取请求的数据。
- 定义所有索引。
- 在集合中填充合理数量的数据(可以是样本数据)。 如果预期应用程序在一般情况下会包含数百万条记录,请在其中填充数百万条记录。
- 编写有代表性的文档并记录 RU 成本。
- 运行有代表性的查询,然后记录 RU 成本。
- 在应用程序中实现一个函数,以根据结果确定任意给定请求的成本。
- 在代码中实现速率限制机制,以确保每秒发送到 Azure Cosmos DB 的所有作的总和不超过预配的吞吐量。
- 对应用程序进行负载测试,并验证是否不超过预配的吞吐量。
- 根据需要定期重新测试 RU 成本并更新成本函数。
索引
与您可能熟悉的其他 SQL 和 NoSQL 数据库不同,Azure Cosmos DB 对新创建的容器采用了默认索引策略,该策略会索引每个属性。 为每个属性建立索引会增大写入操作的 RU 成本。
默认索引策略可以降低读取密集型系统中的延迟,因为其中的查询筛选条件将合理分布在所有已存储的字段之间。 例如,Azure Cosmos DB 花费大部分时间为最终用户精心制作的即席搜索提供服务的系统可能会受益。
您可能希望排除从不被搜索的属性,以免它们被编入索引。 从索引中删除属性可以提高写入密集型系统的总体性能(成本和时间),并更严格地约束记录检索模式。
在度量任何成本之前,应该有意地根据用例配置相应的索引策略。 此外,如果以后更改索引,则需要重新运行所有成本计算。
在可能的情况下,在正常和峰值需求条件下使用一个可以反映典型查询的负载来测试开发中的系统,将有助于确定要使用的索引策略。
有关索引的详细信息,请参阅 Azure Cosmos DB 中的 Indexing 策略。
度量成本
度量成本时需要理解一些重要概念:
- 根据请求单位注意事项中所述,考虑影响 RU 使用量的所有因素。
- 数据库或容器中的所有读取和写入操作将共享相同的预配吞吐量。
- 无论使用 Azure Cosmos DB API,都会产生 RU 消耗。
- 集合的分区策略可能会对系统成本产生显著影响。 有关详细信息,请参阅 在 Azure Cosmos DB 中的分区和水平缩放。
- 使用有代表性的文档和有代表性的查询。
- 您认为这些是与操作系统可能遇到的文档和查询最为接近的。
- 获取这些有代表性的文档和查询的最佳方法就是检测应用程序的使用情况。 更好的做法始终是做出数据驱动的决策。
- 定期度量成本。
- 索引更改和索引大小可能会影响成本。
- 针对有代表性的文档和查询创建某种可重复的(甚至自动化的)测试会很有帮助。
- 确保有代表性的文档和查询仍具代表性。
用于确定请求成本的方法根据所用的每个 API 而异:
写入请求
写入操作的成本往往很容易预测。 插入记录并记录Azure Cosmos DB 报告的成本。
如果你的文档具有不同的大小和/或使用不同的索引,则必须衡量所有这些因素。 你可能发现,有代表性的文档在成本上足够接近,以致可以为所有写入分配一个值。 例如,如果你发现成本分别为 13.14 RU、16.01 RU 和 12.63 RU,则可以取这些成本的平均值,即 14 RU。
读取请求
查询操作的成本可能出于以下原因而更难预测:
- 如果系统支持用户定义的查询,则你需要将传入的查询映射到有代表性的查询,以帮助确定成本。 此过程可能采用多种形式:
- 也许可以对查询进行精确匹配。 如果没有直接匹配项,则可能需要找出与它最接近的有代表性查询。
- 你可能发现,可以根据查询的特征来计算成本。 例如,你可能发现,查询的每个子句产生了特定的成本,或者某个已编制索引的属性的成本为“x”,而某个未编制索引的属性的成本为“y”,等等。
- 结果数量可能会有所不同,除非你有统计数据,否则无法根据返回负载预测 RU 的影响。
查询操作很可能不会有单一的成本,而是由某个函数对查询进行评估并计算出一个成本。 如果使用的是 API for NoSQL,则可以估算操作的实际成本,并确定估算准确性(甚至可以在代码中自动优化这种估算)。
暂时性故障处理
即使实现了速率限制机制,应用程序也仍会出于以下原因而需要进行暂时性故障处理:
- 请求的实际成本可能不同于预计成本。
- 暂时性故障可能由于 TooManyRequests 以外的原因发生。
但是,在应用程序中正确实现速率限制机制会大幅减少暂时性故障数量。
备用和相关技术
尽管本文介绍的是工作负载的客户端协调和批处理,但也可以采用其他技术来管理总体系统吞吐量。
自动缩放
使用 Azure Cosmos DB 中的自动缩放预配吞吐量,可以自动和即时缩放数据库或容器的吞吐量(RU/秒)。 吞吐量会根据使用情况进行缩放,而不会影响工作负荷的可用性、延迟、吞吐量或性能。
自动缩放预配吞吐量非常适用于具有可变或不可预测流量模式,且在高性能和规模方面需要服务级别协议(SLA)的任务关键型工作负载量。
有关自动缩放的详细信息,请参阅 使用自动缩放吞吐量创建 Azure Cosmos DB 容器和数据库。
基于队列的负载调节模式
可以使用在客户端和 Azure Cosmos DB 之间作为缓冲区的队列,以平稳间歇性的繁重负载,从而避免服务失败或任务超时。
此模式适用于其使用的服务可能发生过载的任何应用程序。 但是,如果应用程序需要尽量降低从服务收到响应时的延迟,则此模式不适用。
此模式通常适用于引入操作。
缓存端模式
可以考虑按需将数据加载到缓存中,而不是每次查询 Azure Cosmos DB。 使用缓存可以提升性能,并且有助于在缓存中保存的数据与基础数据存储中的数据之间保持一致性。
具体化视图模式
将数据存储在 Azure Cosmos DB 中后,如果数据未理想地格式化为所需的查询作,则可以将视图预填充到其他集合中。 此模式有助于支持高效查询和数据提取,并可提高应用程序性能。