你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Azure 上任务关键型工作负载的数据平台

在任务关键型体系结构中,任何状态都必须尽可能地存储在计算之外。 技术的选择基于以下关键架构特征:

特征 注意事项
性能 需要多少计算?
延迟 用户和数据存储之间的距离对延迟有何影响? 在权衡延迟的情况下,期望的一致性级别是多少?
响应能力 数据存储是否需要始终可用?
可伸缩性 分区方案是什么?
持续性 数据是否预期会持续很长时间? 保留政策是什么?
复原 如果发生故障,数据存储是否能够自动进行故障转移? 可以采取哪些措施来减少故障转移时间?
安全性 数据是否已加密? 是否可以通过公用网络访问数据存储?

在此体系结构中,有两个数据存储:

  • Database

    与工作负载相关的存储。 建议将所有状态全局存储在与区域标记分开的数据库中。 通过跨区域部署数据库来构建冗余。 对于任务关键型工作负载,跨区域同步数据应该是主要关注点。 此外,如果发生故障,对数据库的写入请求应该仍然正常工作。

    强烈建议在主动-主动配置中进行数据复制。 应用程序应能够立即连接到另一区域。 所有实例都应能够处理读取和写入请求。

  • 消息代理

    区域标记中唯一的有状态服务是消息代理,它会将请求存储一小段时间。 该代理满足了缓冲和可靠消息传送的需求。 处理后的请求保存在全局数据库中。

有关其他数据注意事项,请参阅架构良好的框架的任务关键指南:数据平台注意事项

数据库

此体系结构使用 Azure Cosmos DB for NoSQL。 选择此选项是因为它提供了此设计所需的大多数功能:

  • 多区域写入

    通过部署到每个区域的副本启用了多区域写入,每个区域中都部署了一个标记。 每个缩放单元可以在本地写入,Azure Cosmos DB 处理缩放单元之间的数据复制和同步。 此功能显着降低了地理位置分散的应用程序最终用户的延迟。 Azure 任务关键型参考可实现使用多主数据库技术来提供最大的复原能力和可用性。

    每个复制区域中也启用了区域冗余。

    有关多区域写入的详细信息,请参阅在使用 Azure Cosmos DB 的应用程序中配置多区域写入

  • 冲突管理

    由于能够跨多个区域执行写入,因此有必要采用冲突管理模型,因为同时写入可能会造成记录冲突。 “以最后写入者为准”是默认模型,用于关键任务设计。 由记录的相关时间戳定义的最后写入者赢得冲突。 Azure Cosmos DB for NoSQL 还允许定义自定义属性。

  • 查询优化

    对于具有大量分区的读取密集型容器,一般查询效率建议是添加一个标识 itemID 的相等筛选器。 可以在排查使用 Azure Cosmos DB 时遇到的查询问题中深入了解查询优化建议。

  • 备份功能

    建议使用 Azure Cosmos DB 的本机备份功能来保护数据。 Azure Cosmos DB 备份功能支持联机备份和按需数据还原。

备注

大多数工作负载并不是纯粹的 OLTP。 对实时报告的需求也在增加,例如针对运营系统运行报表。 这也称为 HTAP(混合事务性和分析处理)。 Azure Cosmos DB 通过 Azure Synapse Link for Azure Cosmos DB 支持此功能。

工作负载的数据模型

数据模型应设计为无需传统关系数据库提供的功能。 例如外键、严格的行/列模式、视图等。

工作负载具有这些数据访问特征:

  • 读取模式:
    • 点读取 - 获取单个记录。 直接使用项 ID 和分区键进行最大优化(每个请求 1 RU)。
    • 列表读取 - 在列表中显示目录项。 使用限制结果数量的 FeedIterator
  • 写入模式:
    • 少量写入 - 请求通常在事务中插入单个或少量的记录。
  • 旨在处理来自最终用户的大量流量,并能够缩放以处理数百万用户的流量需求。
  • 小型负载或数据集大小 - 通常以 KB 为单位。
  • 短响应时间(以毫秒为单位)。
  • 低延迟(以毫秒为单位)。

配置

Azure Cosmos DB 配置如下:

  • 一致性级别设置为默认的会话一致性,因为它是单区域和全球分布式应用使用最广泛的级别。 由于写入处理异步且无需数据库写入时低延迟,因此不需要支持高吞吐量的弱一致性。

    备注

    “会话”一致性级别可合理权衡此特定应用程序的延迟、可用性和一致性保证。 请务必了解强一致性级别不适用于多主数据库写入数据库。

  • 所有集合的分区键都设为 /id。 此选定基于使用模式(通常是“以 GUID 为 ID 写入新文档”和“按 ID 读取大量文档”)。 如果应用程序代码保持其 ID 唯一性,新数据将由 Azure Cosmos DB 均匀分布到各分区,从而实现无限缩放。

  • 在集合上配置索引编制策略以优化查询。 若要优化 RU 成本和性能,请使用自定义索引编制策略。 此策略仅对查询谓词中使用的属性编制索引。 例如,应用程序不使用注释文本字段作为查询中的筛选器。 该字段已从自定义索引编制策略中排除。

以下示例来自实现,显示了使用 Terraform 的索引编制策略设置:

indexing_policy {

  excluded_path {
    path = "/description/?"
  }

  excluded_path {
    path = "/comments/text/?"
  }

  included_path {
    path = "/*"
  }

}

有关在此体系结构中从应用程序连接到 Azure Cosmos DB 的信息,请参阅任务关键型工作负载的应用程序平台注意事项

消息服务

任务关键型系统通常利用消息传送服务进行消息或事件处理。 这些服务促进松散耦合,并充当缓冲系统,使系统免受意外的需求峰值的影响。

  • 在处理高价值消息时,建议将 Azure 服务总线用于基于消息的工作负载。
  • 建议将 Azure 事件中心用于处理大量事件或遥测的基于事件的系统。

以下是任务关键型体系结构中 Azure 服务总线高级版和 Azure 事件中心的设计注意事项和建议。

处理负载

消息传送系统必须能够处理所需的吞吐量(以每秒 MB 为单位)。 考虑以下情况:

  • 系统的非功能性要求 (NFR) 应指定每个标记必须支持的平均消息大小和消息峰值数/秒。 此信息可用于计算每个标记所需的峰值 MB/秒。
  • 在计算每个标记所需的峰值 MB/秒时,必须考虑故障转移的影响。
  • 对于 Azure 服务总线,NFR 应指定任意高级服务总线功能,例如会话和重复数据删除消息。 这些功能会影响服务总线的吞吐量。
  • 具有所需功能的服务总线的吞吐量应通过测试计算为每个消息传送单元 (MU) 的 MB/秒。 有关此主题的详细信息,请参阅服务总线高级和标准消息传送层
  • Azure 事件中心的吞吐量应通过测试计算为标准层的每吞吐量单位 (TU) 或高级层的处理单元 (PU) 的 MB/秒。 有关此主题的更多信息,请参阅使用事件中心进行缩放
  • 上述计算可用于验证消息传送服务是否可以处理每个标记所需的负载,以及满足该负载所需的缩放单元数量。
  • 操作部分将讨论自动缩放。

必须处理每条消息

对于必须保证处理的高价值消息,建议的解决方案是使用 Azure 服务总线高级层。 以下是使用 Azure 服务总线高级版时有关此要求的详细信息:

  • 为确保消息正确传输到代理并被代理接受,消息生成者应使用某个受支持的服务总线 API 客户端。 仅当消息保留在队列/主题上时,受支持的 API 才会从发送操作中成功返回。

  • 为确保总线上的消息得到处理,应使用 PeekLock 接收模式。 此模式至少启用一次处理。 以下内容概述了该过程:

    • 消息使用者接收要处理的消息。
    • 使用者在给定的持续时间内被赋予对消息的排他锁。
    • 如果使用者成功处理了消息,则会向代理发送回一条确认消息,并将消息从队列中删除。
    • 如果代理在分配的时间段内没有收到确认,或者处理程序明确放弃消息,则会释放排他锁。 然后该消息可供其他使用者处理。
    • 如果消息未成功处理可配置的次数,或者处理程序将消息转发到死信队列
      • 为确保对发送到死信队列的消息执行操作,应对死信队列进行监视,并设置警报。
      • 系统中应包含可供操作员检查、更正和重新提交消息的工具。
  • 因为消息可能会被多次处理,因此应将消息处理程序设为幂等。

幂等消息处理

RFC 7231 中的超文本传输协议指出,“如果使用某个方法的多个相同请求对服务器造成的预期影响与单个此类请求所造成的影响相同,则认为该方法是幂等的。”

使消息处理具有幂等性的一种常用方法是在永久性存储(例如数据库)中检查是否已处理消息。 如果已处理该消息,则不需要运行逻辑来再次处理它。

  • 在某些情况下,消息处理包括数据库操作,具体而言,是插入带有数据库生成的标识符的新记录。 可将包含这些标识符的新消息发出到中转站。 由于没有分布式事务同时包含数据库和消息中转站,因此如果运行代码的进程正好失败,则可能会出现一些复杂情况。 参阅以下示例场景:
    • 发出消息的代码可能在提交数据库事务之前运行,许多开发人员在使用工作单元模式工作时正是这样做的。 如果在调用中转站之后、请求提交数据库事务之前发生失败,可能不会捕获这些消息。 随着事务回滚,这些数据库生成的 ID 也会被撤消,使其可用于可能同时运行的其他代码。 这可能会导致未捕获的消息的接收方处理错误的数据库条目,从而损害系统的整体一致性和正确性。
    • 如果开发人员在数据库事务完成之后放入发出消息的代码,则该进程仍可能在这些操作之间失败(事务已提交 - 消息已发送)。 发生这种情况时,消息将再次进行处理,但这一次,幂等临界子句将发现该消息已处理(根据数据库中存储的数据来判断)。 该子句将认为上次已成功完成所有操作,从而跳过消息发出代码。 本应收到有关已完成进程的通知的下游系统不会收到任何通知。 这种情况再次导致整体不一致状态。
  • 上述问题的解决方法涉及到使用事务发件箱模式:传出的消息存储在业务数据所在的同一事务存储中的另一个位置。 这些消息随后会在成功处理初始消息后传输到消息中转站。
  • 由于许多开发人员不熟悉这些问题或其解决方法,为了保证这些方法在任务关键型系统中得到一致应用,我们建议将发件箱功能以及与消息中转站的交互包装在某种库中。 所有处理和发送在事务上有意义的消息的代码都应使用该库,而不是直接与消息中转站交互。

高可用性和灾难恢复

消息代理必须可供生成者发送消息,供使用者接收消息。 以下是有关此要求的详细信息:

  • 若要确保服务总线的最高可用性,请使用高级层,该层支持区域中的可用性区域。 借助可用性区域,消息和元数据可以在同一区域的三个不同数据中心进行复制。
  • 使用受支持的服务总线或事件中心 SDK 自动重试读取或写入失败。
  • 考虑使用主动-主动复制主动-被动复制模式来抵御区域性灾难。

备注

Azure 服务总线异地灾难恢复仅跨区域复制元数据。 此功能不会复制消息。

监视

消息传送系统充当消息生成者和使用者之间的缓冲区。 应在关键任务系统中监视关键指标类型,这些指标类型可提供如下所述的宝贵见解:

  • 限制 - 限制指示系统没有处理请求所需的资源。 服务总线和事件中心都支持监视受限制的请求。 应对此指示器发出警报。
  • 队列深度 - 队列深度增加可能指示消息处理器不工作或没有足够的处理器来处理当前负载。 队列深度可用于通知处理程序的自动缩放逻辑。
    • 对于服务总线,队列深度显示为消息计数
    • 对于事件中心,使用者必须计算每个分区的队列深度并将指标推送到监视软件。 对于每次读取,使用者获取当前事件的序列号,以及最后一个入队事件的事件属性。 使用者可以计算偏移量。
  • 死信队列 - 死信队列中的消息表示无法处理的消息。 这些消息通常需要手动干预。 应在死信队列上设置警报。
    • 服务总线具有死信队列和 DeadLetteredMessages 指标。
    • 对于事件中心,此功能必须是内置于使用者的自定义逻辑。
  • CPU/内存使用情况 - 应监视 CPU 和内存,以确保消息传送系统有足够的资源来处理当前负载。 服务总线高级版和事件中心高级版都公开 CPU 和内存使用情况。
    • 服务总线中使用消息传送单元 (MU) 来隔离命名空间的资源,例如 CPU 和内存。 CPU 和内存高于阈值可能表示没有配置足够的 MU,而低于其他阈值可能表示配置的 MU 过多。 这些指标可用于自动缩放 MU
    • 事件中心高级层使用处理单元 (PU) 来隔离资源,而标准层使用吞吐量单元 (TU)。 这些层不需要与 CPU/内存交互来自动扩充 PU 或 TU。

运行状况检查

在任务关键型应用程序的运行状况检查中必须考虑消息传送系统的运行状况。 请考虑下列因素:

  • 消息传送系统充当消息生成者和使用者之间的缓冲区。 如果生成者能够成功地向中转站发送消息,并且使用者能够成功地处理来自中转站的消息,则可将缩放单元视为正常。
  • 运行状况检查应确保消息可以发送到消息系统。

后续步骤

部署参考实现,以便全面了解此体系结构中使用的资源及其配置。