发布者-订阅者模式
使应用程序能够以异步方式向多个感兴趣的使用者公布事件,而无需将发送方与接收方耦合。 也称为:发布/订阅消息
上下文和问题
在基于云的分布式应用程序中,在发生事件时,系统组件通常需要向其他组件提供信息。 异步消息传送是将发件者与使用者解耦的有效方式,可避免阻止发送者等待响应。 但是,对每个使用者使用专用消息队列不能让多个使用者有效进行缩放。 此外,某些使用者可能仅对一部分信息感兴趣。 发送者如何在不知道使用者标识的情况下,向所有感兴趣的使用者公布事件?
解决方案
引入一个包括以下功能的异步消息传送子系统:
- 发送者使用的输入消息传送通道。 发送者使用已知的消息格式将事件打包成消息,然后通过输入通道发送这些消息。 在此模式中,发送者也称为“发布者”。 备注 消息是数据包。 事件是一条消息,告知其他组件已发生某项更改或操作。
- 每个使用者有一个输出消息传送通道。 使用者称为“订阅者”。
- 一个机制,用于将输入通道中的每条消息复制到对该消息感兴趣的所有订阅者的输出通道。 此操作通常由消息中转站或事件总线等中介处理。
下图显示了此模式的逻辑组件: 发布/订阅消息传送具有以下优势:
- 解耦仍然需要通信的子系统。 可以独立管理子系统,即使一个或多个接收者处于脱机状态,也能正确管理消息。
- 提高可伸缩性,改善发送者的响应能力。 发送者可以快速将一条消息发送到输入通道,然后恢复其核心处理责任。 消息传送基础结构负责确保将消息传送到感兴趣的订阅者。
- 它提高了可靠性。 异步消息传送可以帮助应用程序在负载增大的情况下继续保持平稳运行,并更有效地处理间歇性故障。
- 它允许延迟或计划的处理。 订阅者可以等到在非高峰期拾取消息,或者可以根据特定的计划路由或处理消息。
- 这样可以简化使用不同平台、编程语言或通信协议的系统之间的集成,以及本地系统与云中运行的应用程序之间的集成。
- 它简化了整个企业中的异步工作流。
- 它改善了可测试性。 在执行整个集成测试策略过程中,可以监视通道,并可以检查或记录消息。
- 它为应用程序提供关注点分离。 每个应用程序可以注重自身的核心功能,而消息传送基础结构可以处理所需的一切工作来可靠地将消息路由到多个使用者。
问题和注意事项
在决定如何实现此模式时,请考虑以下几点:
- 现有技术。 强烈建议使用支持发布-订阅模型的可用消息传送产品和服务,而不要自行构建。 在 Azure 中,考虑使用服务总线、事件中心或事件网格。 其他可用于发布/订阅消息传送的技术包括 Redis、RabbitMQ 和 Apache Kafka。
- 订阅处理。 消息传送基础结构必须提供相应的机制,让使用者通过可用的通道订阅或取消订阅。
- 安全性。 连接到任何消息通道必须受安全策略的限制,以防止未经授权的用户或应用程序窃听。
- 消息子集。 订阅者通常只对发布者分发的消息的子集感兴趣。 消息传送服务通常允许订阅者按以下各项缩小接收的消息集范围:
- 主题。 每个主题都有一个专用输出通道,每个使用者可以订阅所有相关主题。
- 内容筛选。 根据每个消息的内容检查和分发消息。 每个订阅者可以指定其感兴趣的内容。
- 通配符订阅者。 考虑允许订阅者通过通配符订阅多个主题。
- 双向通信。 发布-订阅系统中的通道被认为是单向的。 如果特定订阅者需要向发布者发回确认或通信状态,请考虑使用请求/回复模式。 此模式使用一个通道向订阅者发送消息,并使用一个独立的回复通道来与发布者通信。
- 消息排序。 不能保证使用者实例接收消息的顺序,且不一定反映创建消息的顺序。 精心设计系统以确保消息处理是幂等的,以帮助消除对消息处理顺序的任何依赖。
- 消息优先级。 某些解决方案可能要求按特定的顺序处理消息。 优先级队列模式提供一种机制用于确保按顺序传送特定的消息。
- 有害消息。 格式不正确的消息或需要访问不可用资源的任务可能会导致服务实例失败。 系统应阻止将此类消息返回到队列。 应该捕获这些消息的详细信息并将其存储在其他位置,以便可按需要对其进行分析。 某些消息中转站(如 Azure 服务总线)通过其死信队列功能支持此操作。
- 重复消息。 同一条消息可能会发送多次。 例如,在发布某条消息后,发送者可能会发生故障。 然后,该发送者的新实例可能会启动并重复发送该消息。 消息传送基础结构应该实施基于消息 ID 的重复消息检测和删除(也称为重复项删除),以便最多只传送消息一次。 或者,如果使用不删除重复消息的消息传递基础结构,请确保消息处理逻辑是幂等的。
- 消息过期。 消息可能带有有限的生存期。 如果在此期限内未处理该消息,则它不再有用,应该将其丢弃。 发送者可以在消息数据中指定过期时间。 接收者可以检查此信息,然后决定是否要执行与该消息关联的业务逻辑。
- 消息计划。 可以暂时禁止传送某条消息,在特定的日期和时间之前,不应处理该消息。 在此时间之前,不应将该消息提供给接收者。
何时使用此模式
在以下情况下使用此模式:
- 应用程序需要将信息广播到大量的使用者。
- 应用程序需要与一个或多个独立开发的、可能使用不同平台、编程语言和通信协议的应用程序或服务通信。
- 应用程序无需使用者的实时响应,即可将信息发送到使用者。
- 集成的系统旨在支持其数据的最终一致性模型。
- 应用程序需要向多个使用者传送信息,而这些使用者的可用性要求或运行时间计划可能与发送者不同。
在以下情况下,此模式可能不起作用:
- 应用程序只有少量的几个使用者,而这些使用者所需的信息与生成方应用程序截然不同。
- 应用程序需要与使用者进行近实时的交互。
示例
下图显示了一个使用服务总线来协调工作流,并使用事件网格来向子系统通知发生的事件的企业集成体系结构。 有关详细信息,请参阅 Azure 上使用消息队列和事件的企业集成。
后续步骤
实现此模式时,以下指南可能比较有用:
- 在传递消息的 Azure 服务之间进行选择。
- 异步消息传送入门。 消息队列是异步通信机制。 如果使用者服务需要向应用程序发送回复,则可能需要实现某种形式的响应消息传送。 异步消息传送入门提供了有关如何使用消息队列实现请求/回复消息传送的信息。
实现此模式时,以下模式可能有用:
此博客文章介绍了处理无序到达的消息的不同方法。
相关资源
- 事件驱动的体系结构样式是使用发布/订阅消息传送的体系结构样式。
- 幂等消息处理
- Azure 上使用消息队列和事件的企业集成