异步消息传送选项
本文介绍参与消息基础结构的不同类型的消息和实体。 根据每种消息类型的要求,本文建议使用 Azure 消息传送服务。 这些选项包括 Azure 服务总线消息传送、Azure 事件网格和 Azure 事件中心。 有关产品比较,请参阅 比较消息服务。
在体系结构级别,消息是由实体(生成者)创建的数据报,用于分发信息,以便其他实体(使用者)可以识别并相应地采取行动。 生成者和使用者可以通过中介实体(消息代理)直接或选择性地进行通信。 本文重点介绍使用消息代理的异步消息传送。
我们可以将消息分类为两个主要类别。 如果生成者需要使用者的作,则消息是 命令。 如果消息通知使用者已执行某个作,则消息是一个 事件。
指令
生成者发送一个命令,其意图是使用者(s)将在业务事务范围内执行作。
命令是高值消息,必须至少传递一次。 如果命令丢失,整个业务事务可能会失败。 此外,不应多次处理命令。 这样做可能会导致错误事务。 客户可能会收到重复的订单或两次计费。
命令通常用于管理多步骤业务事务的工作流。 根据业务逻辑,生成者可能需要使用者确认消息并报告作结果。 根据该结果,生成者可以选择适当的作过程。
事件
事件是生成者引发以宣布事实的消息类型。
生成者(在此上下文中称为 发布者 )没有期望事件导致任何作。
感兴趣的使用者可以订阅、侦听事件,并根据其使用方案采取措施。 事件可以有多个订阅者或根本没有订阅者。 两个不同的订阅者可以响应具有不同作的事件,并且不知道彼此。
生产者和使用者是松散耦合和管理的。 生成者不希望使用者向生成者确认事件。 不再对事件感兴趣的使用者可以取消订阅,这会从管道中删除使用者,而不会影响生成者或系统的整体功能。
有两类事件:
制作者引发事件,宣布离散事实。 常见的用例是事件通知。 例如,Azure 资源管理器在创建、修改或删除资源时引发事件。 这些事件的订阅者可以是发送警报电子邮件的逻辑应用。
生成者在一段时间内按序列或事件流引发相关事件。 通常,流用于统计评估。 评估可以在临时窗口中发生,或者当事件到达时发生。 遥测是一个常见用例(例如,系统的运行状况和负载监视)。 另一种情况是从 IoT 设备流式传输事件。
实现事件消息传送的常见模式是 发布服务器-订阅服务器 模式。
消息代理的角色和优势
中间消息中转站提供将消息从生成者移动到使用者的功能,并可提供更多好处。
解耦
消息中转站将生成者与逻辑中的使用者分离,这些使用者分别生成和使用消息。 在复杂的工作流中,中转站可以鼓励业务运营分离并帮助协调工作流。
例如,单个业务事务需要业务逻辑序列中执行的不同作。 生成者发出一个命令,指示使用者启动作。 使用者在为生成者排队响应而保留的单独队列中确认消息。 只有在收到响应后,生成者才会发送新消息以启动序列中的下一个作。 不同的使用者处理该消息并将完成消息发送到响应队列。 服务通过使用消息传送来协调事务的工作流。
消息中转站提供时态分离。 生成者和使用者不必同时运行。 无论使用者的可用性如何,生成者都可以向消息中转站发送消息。 相反,使用者不受生成者可用性的限制。
例如,Web 应用的用户界面生成消息,并使用队列作为消息代理。 使用者准备就绪后,它可以从队列中检索消息并执行工作。 临时分离有助于用户界面保持响应。 在异步处理消息时,不会阻止它。
某些作可能需要很长时间才能完成。 发出命令后,生成者不必等到使用者完成该命令。 消息代理有助于异步处理消息。
负载均衡
生成者可以发布大量由许多使用者提供服务的消息。 使用消息代理跨服务器分配处理并提高吞吐量。 使用者可以在不同的服务器上运行以分散负载。 如果需要或删除系统,可以动态添加使用者以横向扩展系统。
竞争使用者模式说明了如何同时处理多个消息以优化吞吐量、提高可伸缩性和可用性,以及平衡工作负荷。
负载分级
生成者或一组生成者生成的消息量可以是可变的。 有时,可能会有大量卷导致消息激增。 消息代理可以充当缓冲区,并且使用者无需强调系统,而是按自己的速度逐步清空消息,而不是添加使用者来处理此工作。
基于队列的负载调配模式提供了更多信息。
可靠消息传送
消息中转站有助于确保即使生成者和使用者之间的通信失败,消息也不会丢失。 生成者可以将消息发布到消息中转站,使用者可以在重新建立通信时检索它们。 除非生成者与消息代理失去连接,否则不会阻止生成者。
复原消息传送
消息代理可以向系统中的使用者添加复原能力。 如果使用者在处理消息时失败,则使用者的另一个实例可以处理该消息。 由于消息保留在中转站中,因此可以重新处理。
消息中转站的技术选择
Azure 提供了多个消息代理服务,每个服务都有一系列功能。 在选择服务之前,请确定消息的意向和要求。
Azure 服务总线消息传送
Azure 服务总线消息传送 队列非常适合用于将命令从生成者传输到使用者。 下面是一些注意事项。
拉取模型
服务总线队列的使用者会不断轮询服务总线,以检查是否有新消息可用。 用于服务总线的客户端 SDK 和 Azure Functions 触发器 抽象化该模型。 当新消息可用时,将调用使用者的回调,并将消息发送到使用者。
有保证的交付
服务总线允许使用者查看队列并锁定来自其他使用者的消息。
使用者负责报告消息的处理状态。 仅当使用者将消息标记为已使用时,服务总线才会从队列中删除该消息。 如果发生故障、超时或崩溃,服务总线会解锁消息,以便其他使用者可以检索它。 这样,传输中不会丢失消息。
生成者可能会意外地发送同一消息两次。 例如,发送消息后,生成者实例会失败。 另一个生成者将替换原始实例,并再次发送消息。 Azure 服务总线队列提供 内置的取消复制功能 ,用于检测和删除重复的消息。 仍有一个消息传递两次的机会。 例如,如果在处理过程中使用者失败,消息将返回到队列,并由同一使用者或其他使用者检索。 使用者中的消息处理逻辑应是幂等的,因此即使重复工作,系统的状态也不会更改。
消息排序
如果希望使用者按照消息的发送顺序获取消息,服务总线队列会使用会话保证先出(FIFO)有序传递。 会话可以包含一个或多个消息。 这些消息与 SessionId 属性相关。 作为会话一部分的消息永远不会过期。 会话可以锁定给使用者,以防止其消息由其他使用者处理。
有关详细信息,请参阅消息会话。
消息持久性
服务总线队列支持临时分离。 即使使用者不可用或无法处理消息,它仍保留在队列中。
检查点长时间运行的事务
业务事务可以长时间运行。 事务中的每个作可以有多个消息。 使用检查点协调工作流,并在事务失败时提供复原能力。
服务总线队列允许通过 会话状态功能进行检查点。 状态信息以增量方式记录在队列(SetState)中,用于属于会话的消息。 例如,使用者可以每隔一次检查状态(GetState)来跟踪进度。 如果使用者失败,另一个使用者可以使用状态信息来确定最后一个已知检查点以恢复会话。
死信队列 (DLQ)
服务总线队列具有默认的子队列,称为 死信队列(DLQ), 用于保存无法传递或处理的消息。 使用者中的服务总线或消息处理逻辑可以将消息添加到 DLQ。 DLQ 会保留消息,直到从队列中检索到它们。
下面是消息最终出现在 DLQ 中的示例:
病毒消息是无法处理的消息,因为它格式不正确或包含意外信息。 在服务总线队列中,可以通过设置队列的 MaxDeliveryCount 属性来检测病毒消息。 如果收到相同消息的次数超过该属性值,服务总线会将消息移动到 DLQ。
如果在一段时间内未处理消息,则消息可能不再相关。 服务总线队列允许生成者使用生存时间属性发布消息。 如果此时间段在收到消息之前过期,则会将消息置于 DLQ 中。
检查 DLQ 中的消息以确定失败原因。
混合解决方案
服务总线桥接本地系统和云解决方案。 由于防火墙限制,本地系统通常难以到达。 生成者和使用者(可以是本地或云)都可以使用服务总线队列终结点作为消息的取件和下车位置。
消息传送桥模式是处理这些方案的另一种方法。
主题和订阅
服务总线通过服务总线主题和订阅支持 Publisher-Subscriber 模式。
此功能为生成者提供了向多个使用者广播消息的方法。 当主题收到消息时,它会转发给所有订阅的使用者。 (可选)订阅可以具有筛选器条件,允许使用者获取一部分消息。 每个使用者都以类似于队列的方式从订阅中检索消息。
有关详细信息,请参阅 Azure 服务总线主题。
Azure 事件网格
建议将 Azure 事件网格 用于离散事件。 事件网格遵循 Publisher-Subscriber 模式。 当事件源触发事件时,它们将发布到 事件网格主题。 这些事件的使用者通过指定将处理事件的事件类型和事件处理程序来创建事件网格订阅。 如果没有订阅者,则丢弃事件。 每个事件可以有多个订阅。
推送模型
事件网格将消息传播到推送模型中的订阅者。 假设你有一个包含 Webhook 的事件网格订阅。 新事件到达时,事件网格会将事件发布到 Webhook 终结点。
与 Azure 集成
如果要获取有关 Azure 资源的通知,请选择事件网格。 许多 Azure 服务充当具有内置事件网格主题 的事件源 。 事件网格还支持可配置为 事件处理程序的各种 Azure 服务。 可以轻松订阅这些主题,以将事件路由到所选的事件处理程序。 例如,创建或删除 Blob 存储时,可以使用事件网格调用 Azure 函数。
自定义主题
如果要从应用程序或未与事件网格集成的 Azure 服务发送事件,请创建自定义事件网格主题。
例如,若要查看整个业务事务的进度,希望参与的服务在处理单个业务运营时引发事件。 Web 应用显示这些事件。 完成此任务的一种方法是创建自定义主题,并使用通过 HTTP WebHook 注册的 Web 应用添加订阅。 当业务服务将事件发送到自定义主题时,事件网格会将事件推送到 Web 应用。
筛选的事件
可以在订阅中指定筛选器,以指示事件网格仅将一部分事件路由到特定的事件处理程序。 在 订阅架构中指定筛选器。 发送到主题且值与筛选器匹配的任何事件都会自动转发到该订阅。
例如,各种格式的内容将上传到 Blob 存储。 每次添加文件时,都会引发事件并将其发布到事件网格。 事件订阅可能有一个筛选器,它只发送图像的事件,以便事件处理程序可以生成缩略图。
有关筛选的详细信息,请参阅 事件网格的筛选事件。
高吞吐量
事件网格可以为每个区域每秒路由 10,000,000 个事件。 每月前 100,000 个操作是免费的。 有关成本注意事项,请参阅 事件网格的成本是多少?
可复原交付
即使成功传递事件与命令并不一样重要,但仍可能需要一些保证,具体取决于事件类型。 事件网格提供可以启用和自定义的功能,例如重试策略、过期时间和死信。 有关详细信息,请参阅事件网格消息传递和重试。
事件网格的重试过程可以帮助复原,但它不是故障安全的。 在重试过程中,如果终结点长时间无响应,事件网格可能会多次传递消息、跳过或延迟某些重试。 有关详细信息,请参阅 重试计划。
可以通过启用死信将未传递的事件保存到 Blob 存储帐户。 将消息传送到 Blob 存储终结点时存在延迟,如果该终结点无响应,则事件网格会丢弃该事件。 有关详细信息,请参阅 “设置死信位置和重试策略”。
Azure 事件中心
使用事件流时, 建议使用 Azure 事件中心 消息中转站。 从本质上讲,它是一个能够接收大量数据且延迟较低的大型缓冲区。 可以通过并发作快速读取收到的数据。 可以使用任何实时分析提供程序转换收到的数据。 事件中心还提供在存储帐户中存储事件的功能。
快速引入
事件中心每秒能够引入数百万个事件。 事件仅追加到流中,按时间排序。
拉取模型
与事件网格一样,事件中心还提供 Publisher-Subscriber 功能。 事件网格和事件中心之间的主要区别在于事件数据对订阅者可用的方式。 事件网格将引入的数据推送到订阅服务器,而事件中心使数据在拉取模型中可用。 收到事件后,事件中心会将它们追加到流中。 订阅者管理其游标,并且可以在流中向前和后移,选择时间偏移量,并按顺序重播序列。
流处理器是用于转换和统计分析目的从事件中心拉取数据的订阅者。 使用 Azure 流分析和Apache Spark 进行复杂处理,例如随时间推移的聚合或异常情况检测。
如果要对每个分区的每个事件执行作,可以使用 事件处理程序主机或内置连接器(例如 Azure 逻辑应用 )来拉取数据,以提供转换逻辑。 另一种选择是使用 Azure Functions。
分区
分区是事件流的一部分。 事件使用分区键进行除法。 例如,多个 IoT 设备将设备数据发送到事件中心。 分区键是设备标识符。 引入事件时,事件中心会将它们移动到单独的分区。 在每个分区中,所有事件按时间排序。
使用者是处理事件数据的代码实例。 事件中心遵循分区使用者模式。 每个使用者只读取特定分区。 具有多个分区会导致更快的处理,因为多个使用者可以同时读取流。
同一使用者的实例构成单个使用者组。 多个使用者组可以读取具有相同意向的同一流。 假设事件流包含来自温度传感器的数据。 一个使用者组可以读取流来检测异常,例如温度峰值。 另一个流可以读取相同的流,以计算临时窗口中的滚动平均温度。
事件中心通过允许多个使用者组支持 Publisher-Subscriber 模式。 每个使用者组都是订阅者。
有关事件中心分区的详细信息,请参阅 分区。
事件中心捕获
使用捕获功能可将事件流存储到 Azure Blob 存储 或 Data Lake Storage。 这种存储事件的方式可靠,因为即使存储帐户不可用,捕获也会保留数据一段时间,然后在存储可用后写入存储。
存储服务还可以提供用于分析事件的其他功能。 例如,利用 Blob 存储帐户的访问层,可以将事件存储在热层中,以获取需要频繁访问的数据。 可以使用该数据进行可视化。 或者,可以将数据存储在存档层中,并偶尔检索数据以进行审核。
捕获存储事件中心引入 的所有 事件,并且可用于批处理。 可以使用 MapReduce 函数生成有关数据的报表。 捕获的数据还可以用作事实来源。 如果在聚合数据时错过了某些事实,则可以引用捕获的数据。
有关此功能的详细信息,请参阅 通过 Azure Blob 存储或 Azure Data Lake Storage 中的 Azure 事件中心捕获事件。
对 Apache Kafka 客户端的支持
事件中心为 Apache Kafka 客户端提供终结点。 现有客户端可以更新其配置以指向终结点并开始将事件发送到事件中心。 无需进行任何代码更改。
有关详细信息,请参阅适用于 Apache Kafka 的事件中心。
交叉方案
在某些情况下,合并两个消息传送服务是有利的。
合并服务可以提高消息系统的效率。 例如,在业务事务中,使用 Azure 服务总线队列来处理消息。 大多数处于空闲状态且偶尔接收消息的队列效率低下,因为使用者会不断轮询队列中的新消息。 可以使用 Azure 函数作为事件处理程序设置事件网格订阅。 每当队列收到消息且没有使用者侦听时,事件网格都会发送通知,该通知会调用清空队列的 Azure 函数。
有关将服务总线连接到事件网格的详细信息,请参阅 Azure 服务总线到事件网格集成概述。
使用消息队列和事件参考体系结构的企业集成显示了服务总线到事件网格集成的实现。
下面是另一个示例:事件网格接收一组事件,其中某些事件需要工作流,而另一些事件则用于通知。 消息元数据指示事件的类型。 区分的一种方法是使用事件订阅中的筛选功能检查元数据。 如果需要工作流,事件网格会将其发送到 Azure 服务总线队列。 该队列的接收方可以采取必要的作。 通知事件将发送到逻辑应用以发送警报电子邮件。
相关模式
实现异步消息传送时,请考虑以下模式:
- 竞争使用者模式。 多个使用者可能需要竞争才能从队列中读取消息。 此模式说明如何同时处理多个消息以优化吞吐量、提高可伸缩性和可用性以及平衡工作负荷。
- 优先级队列模式。 对于业务逻辑要求先处理某些消息之前,此模式描述生成者发布的优先级较高的消息的接收和处理速度比优先级较低的消息更快。
- 基于队列的负载调节模式。 此模式使用消息中转站充当生成者和使用者之间的缓冲区,以帮助最大程度地降低这两个实体间歇性重负载的可用性和响应能力的影响。
- 重试模式。 生成者或使用者可能无法连接到队列,但此失败的原因可能是暂时的且快速传递。 此模式介绍如何处理这种情况,以向应用程序添加复原能力。
- 计划程序代理监督程序模式。 消息传递通常用作工作流实现的一部分。 此模式演示消息传送如何跨分布式服务和其他远程资源协调一组作,并使系统能够恢复和重试失败的作。
- 编舞模式。 此模式显示服务如何使用消息传送来控制业务事务的工作流。
- Claim-Check 模式。 此模式演示如何将大型消息拆分为声明检查和有效负载。