发布/订阅(简称 Pub/Sub)是一种消息传递技术,它促进了分布式系统中不同组件之间的通信。这种通信模型不同于传统的点对点消息传递,其中一个应用程序直接向另一个应用程序发送消息。相反,它是一种异步且可扩展的消息传递服务,将负责生成消息的服务与负责处理消息的服务分开。
Redis Streams 或 Redis 发布/订阅是您下一个应用程序的最佳选择吗? Redis Streams 和发布/订阅简介
发布/订阅是一种消息传递模型,它允许分布式系统中的不同组件彼此通信。发布者将消息发送到主题,订阅者从此主题接收消息,这让发布者在保持匿名性的同时将消息发送到订阅者,不过订阅者如果在消息负载中包含标识信息,则发布者也可以被识别。发布/订阅系统可确保消息发送到所有关注此主题的订阅者。如果配置得当,它是一个高度可扩展且可靠的消息传递系统,可以处理海量数据。此外,发布/订阅允许服务以毫秒级的延迟异步通信,消息大小合适、网络条件好且订阅者处理时间短,使其成为快速现代化分布式应用程序的理想之选。
从根本上说,发布/订阅是一种简单的通信模型,其中 代理 接收来自发布者的消息,并将这些消息分发给一个或多个订阅者。然后将消息传递给订阅者,这些订阅者根据其特定用例的需求解读消息。
通常根据通信所涉及的发布者和订阅者数量将它们归类为四种模型,包括一对一、一对多、多对一和多对多。
发布/订阅模型的类型 | 描述 |
一对一 | 此模型包含一个发布者和一个订阅者。直接消息从发布者发送到订阅者。 |
一对多 | 此模型包含一个发布者和多个订阅者。发布者将消息发送到主题;所有相关订阅者都会收到该消息。 |
多对一 | 此模型包含多个发布者和一个订阅者。订阅者从多个发布者收到特定主题的消息。 |
多对多 | 此模型包含多个发布者和订阅者。消息由发布者发送到主题,且所有订阅者都会收到该消息。 |
发布/订阅系统由多个组件组成;其中一些主要组件在以下表格中进行了描述。
组件 | 描述 |
1. 发布者 | 发布者是发送消息的应用程序或服务。 |
2. 订阅者 | 订阅者是接收消息的应用程序或服务。 |
3. 主题 | 主题是话题或信息馈送。发布者可以将消息推送到主题,主题会将消息广播给订阅者。 |
4. 消息 | 消息在整个系统中保存已接收或已传输的数据。 |
5. 代理 | 代理负责在整个系统中引导消息。它充当中间人,在发布者和订阅者之间建立和交换通信。它可以保存一个主题及其各自订阅者的列表,这有助于它将从发布者收到的消息路由到适当的订阅者。 |
6. 路由 | 路由是消息在系统内从发布者流向订阅者,并基于特定订阅确保消息送达正确订阅者的过程。 |
Pub/Sub 提供的异步集成提高了系统的整体灵活性和鲁棒性,这使得能够拥有各种用例,包括
发布/订阅服务可以大致分为基于云、自托管和实时。
基于云的发布/订阅服务提供由云提供商(如 Google Cloud、AWS 和 Microsoft Azure)完全管理的消息传递基础设施。基于云的发布/订阅系统提供高消息持久性和可用性,这使其适合构建需要实时持续更新的云原生应用程序,例如检查可用机票的航空公司应用程序或检查外币汇率的银行应用程序。此外,借助这些主要的云提供商,您可以轻松构建高度可扩展的解耦消息传递系统。
自托管发布/订阅服务提供可以定制以满足组织内部应用程序特定需求(例如简化数据传输或实现异步工作流)的消息传递系统。这为企业提供了更大的灵活性并对其系统(可以部署到本地环境或云环境)拥有更大的控制权。自托管发布/订阅服务的流行示例包括 RabbitMQ、Apache Kafka 和 Apache Pulsar。
实时发布/订阅服务促进了实时发送和接收消息,无需频繁轮询消息队列。这减少了传递延迟并改善了整体用户体验。该模型还包括安全功能,例如信道加密、检测系统响应的在线状态、消息历史记录和备份。实时发布/订阅服务系统最适合以下用例:社交媒体聊天应用程序、在线游戏和直播。实时发布/订阅服务系统的示例包括 Pusher 和 PubNub。
除了发布/订阅外,还有各种可用的消息传递技术,包括点对点消息和消息队列。选择消息传递技术取决于个人或组织对应用程序的期望。通常,在根据预期用例决定使用哪种技术之前,会评估系统的优点和缺点。
点对点消息传递是一种基本的传递模型,其中发送者发送消息给特定的接收者。接收者可以阅读消息并回复。此技术最适合那些发送者和接收者有直接连接,并且接收者可以实时处理传入消息的情况。点对点消息传递的一些示例是 HTTP 和 TCP/IP。
消息队列是一种消息传递模型,其中消息被排队并由使用者处理。此技术非常适用于有多个生产者和使用者的场景,其中消息需要按顺序传递。消息队列技术的一些示例是 RabbitMQ 和 Apache ActiveMQ。
与点对点消息传递和消息队列相比,发布/订阅消息传递提供了几个优势。首先,发布/订阅消息传递能够解耦发布者和订阅者,无需发布者了解自己的订阅者。这让系统能够更有效地进行扩展,因为可以添加新的订阅者而不影响发布者。其次,由于发布/订阅消息传递支持异步处理,因此订阅者可以按照自己的节奏读取消息。这有助于通过降低系统上的负载来增强性能。此外,发布/订阅消息传递能够使用事件驱动的架构,其中事件在系统中触发操作。
现在很明显,发布/订阅消息传递是构建分布式系统和实施事件驱动的架构的一个强大工具。这是因为它和其他技术和服务提供了多个集成。下面列出了一些最常用的集成类型
云平台集成:发布/订阅消息传递是大多数云计算平台提供的服务,包括 Amazon Web Services (AWS)、Google Cloud Platform (GCP) 和 Microsoft Azure,提供消息过滤和备份等功能。
编程语言集成:发布/订阅消息传递支持多种编程语言及其库,例如 Java、Python 和 Node.js,使得应用程序和发布/订阅消息传递服务之间的通信变得更加容易。
API 集成:发布/订阅消息传递允许使用标准 API 调用发送和接收消息,使用面向多种语言的客户端库和标准 gRPC 和 REST 服务 API 技术。
数据库集成:发布/订阅消息传递可以通过事件驱动的架构触发数据库更新和数据处理。例如,当收到新消息时,发布/订阅消息传递可以导致数据库更新执行。
第三方服务集成:发布/订阅消息传递系统允许使用多个第三方服务集成,例如 Apache Kafka 和 Amazon SNS,以丰富应用程序功能并实现无缝数据交换。
自定义集成:发布/订阅还允许基于组织的用例和要求进行自定义集成,以支持其内部应用程序。
安全和身份验证集成:发布/订阅系统与身份和访问管理系统集成,例如 **LDAP**、**OAuth** 和 **SAML**,以确保只有授权用户才能访问敏感数据,并通过通知系统以采取适当措施,帮助防止安全漏洞。
监控和日志集成:发布/订阅系统受监控、警报和日志产品的支持,例如 Prometheus 和 Grafana。它使企业能够跟踪和监控其系统的性能,并分析数据以获取见解和优化。
CI/CD 集成:CI/CD 工具(例如 Jenkins 和 GitLab)的集成允许构建、测试和应用程序部署自动化。此外,它还能更容易地跟踪应用程序的进度。
Python 是一种编程语言,它提供一个 Redis 客户端库,允许 Python 开发人员与 Redis(一个内存数据结构存储)进行交互。Redis 提供了一个发布/订阅 (pub/sub) 消息传递系统,允许客户端订阅频道并在向这些频道发布消息时接收消息。
Python 可用于通过向频道发送 PUBLISH 命令并订阅频道发送 SUBSCRIBE 命令来使用 Redis 实现发布/订阅功能。Redis 客户端库的 Python 版本提供了一种便捷的方式来处理 Python 应用程序中的发布/订阅消息传递。
命令 | 示例用法和说明 |
---|---|
SUBSCRIBE | SUBSCRIBE channel [channel …] – 订阅给定的频道 |
UNSUBSCRIBE | UNSUBSCRIBE [channel [channel …]] – 取消订阅提供的频道,或者如果未给出频道,则取消订阅所有频道 |
PUBLISH | PUBLISH channel message – 向给定频道发布消息 |
PSUBSCRIBE | PSUBSCRIBE pattern [pattern …] – 订阅广播到与给定模式匹配的频道的消息 |
PUNSUBSCRIBE | PUNSUBSCRIBE [pattern [pattern …]] – 取消订阅提供的模式,或者如果没有给出模式,则取消订阅所有订阅模式 |
为了有效展示该功能,更方便的是利用一个辅助线程来处理 PUBLISH,因为 PUBLISH 和 SUBSCRIBE 命令是在 Python 端实现的。
在发布/订阅模式中,发布者可以向频道的任意数目的订阅者发送消息。这些消息是不可恢复的,这意味着如果发布消息且没有订阅者,则该消息将消失并且无法恢复。
一旦订阅频道,客户端就会进入订阅者模式,并且客户端无法发出命令。通过这种方式,客户端已变为只读。发布没有这样的限制。
可同时关注多个频道。我们通过使用SUBSCRIBE命令关注两个频道:weather 和 sports,开始学习。
> SUBSCRIBE weather sports Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "weather" 3) (integer) 1 1) "subscribe" 2) "sports" 3) (integer) 2
在独立客户端中(例如,在独立终端中),我们可以将项目发布到这两个频道中的任意一个。我们可以通过运行 PUBLISH 命令完成此操作
> PUBLISH sports oilers/7:leafs/1 (integer) 1
第一个参数是频道,第二个参数是消息。消息可以是任何内容,在此情况下,它是一个经过编码的体育比分。它返回其将传递到的客户端数量。回到订阅者模式客户端,我们很快会看到消息
1) "message" 2) "sports" 3) "oilers/7:leafs/1"
响应包含三个元素:通知(一条消息)、频道和最后是消息本身。客户端在收到消息后会立即返回收听。我们可以返回另一个客户端发布另一条消息
> PUBLISH weather snow/-4c (integer) 1
在另一个客户端中,我们看到相同的格式,但频道和事件有所不同
1) "message" 2) "weather" 3) "snow/-4c"
在没有人关注的频道中发布一个发布。
> PUBLISH currency CADUSD/0.787 (integer) 0
由于我们没有客户端监听频道currency,因此返回结果为 0。此消息现在已丢失,随后订阅currency频道的客户端不会收到此消息通知——消息已被触发并已丢失。
除订阅个人频道外,Redis 还允许模式化订阅。PSUBSCRIBE 命令可启用 glob 样式模式
> PSUBSCRIBE sports:*
此命令将获取从“sports:*”开始的任意频道的消息。在其他客户端中,发布以下命令
> PUBLISH sports:hockey oilers/7:leafs/1 (integer) 1 > PUBLISH sports:basketball raptors/33:pacers/7 (integer) 1 > PUBLISH weather:edmonton snow/-4c (integer) 0
请注意,前两个命令返回的结果为 1,而最后一个命令的结果为 0。即使我们没有sports:hockey或sports:basketball的直接订阅者,模式订阅也会将消息接收情况作为接收消息处理。返回到我们订阅的客户端上,我们可以看到仅返回与模式匹配的频道的结果。
1) "pmessage" 2) "sports:*" 3) "sports:hockey" 4) "oilers/7:leafs/1" 1) "pmessage" 2) "sports:*" 3) "sports:basketball" 4) "raptors/33:pacers/7"
此响应与直接 SUBSCRIBE 响应略有不同,因为它同时具有匹配的模式 (2) 和实际频道的名称 (3)。