dot Redis 8 已发布—且它是开源的

了解更多

发布/订阅

返回术语表

发布/订阅 定义

发布/订阅(Pub/Sub 的简称)是一种消息传递技术,它促进分布式系统中不同组件之间的通信。这种通信模式与传统的点对点消息传递不同,后者是一个应用直接向另一个应用发送消息。相反,它是一种异步且可扩展的消息传递服务,它将负责生成消息的服务与负责处理消息的服务分离开来。

Redis Streams 还是 Redis Pub/Sub 是您下一个应用的最佳选择? Redis Streams 和 Pub/Sub 入门

理解发布/订阅

发布/订阅 是一种消息传递模型,它允许分布式系统中的不同组件相互通信。发布者将消息发送到一个主题,订阅者则从该主题接收消息,这使得发布者可以在匿名的情况下向订阅者发送消息,当然如果他们在消息负载中包含识别信息,订阅者也可以识别他们。发布/订阅 系统确保消息到达所有对该主题感兴趣的订阅者。如果配置得当,它是一个高度可扩展且可靠的消息传递系统,可以处理大量数据。此外,在适当的消息大小、网络条件和订阅者处理时间下,发布/订阅 允许服务以 1 毫秒的延迟异步通信,这使得它对于快速且现代的分布式应用非常理想。

发布/订阅 的工作原理

发布/订阅 本质上是一个简单的通信模型,其中一个 消息代理 接收来自发布者的消息,并将其分发给一个或多个订阅者。然后,消息被传递给订阅者,订阅者根据其特定用例的需求解释这些消息。

根据通信中涉及的发布者和订阅者的数量,它们通常被分为四种模型,包括一对一(one-to-one)、一对多(one-to-many)、多对一(many-to-one)和多对多(many-to-many)。

发布/订阅 模型类型描述 
一对一(One-to-one)该模型包含一个发布者和一个订阅者。直接消息从发布者发送给订阅者。
一对多(One-to-many)该模型包含一个发布者和多个订阅者。发布者将消息发送到主题;所有感兴趣的订阅者都会收到该消息。
多对一(Many-to-one)该模型包含多个发布者和一个订阅者。订阅者从多个发布者那里接收特定主题的消息。
多对多(Many-to-many)该模型包含多个发布者和订阅者。发布者将消息发送到一个主题,所有订阅者都会收到该消息。

发布/订阅 核心概念

发布/订阅 系统由多个组件组成;下面表格描述了一些主要组件

组件 描述
1. 发布者发布者是发送消息的应用或服务。
2. 订阅者订阅者是接收消息的应用或服务。
3. 主题主题是消息的主题或信息流。发布者可以将消息推送到主题,该主题会将消息广播给订阅者。
4. 消息消息包含系统中接收或传输的数据。
5. 消息代理消息代理 负责在整个系统中引导消息。它充当中间人,建立发布者和订阅者之间的通信并进行交换。它可以维护主题及其各自订阅者的列表,这有助于它将从发布者接收到的消息路由发送给适当的订阅者。
6. 路由路由 是消息在系统中从发布者流向订阅者的过程,并根据特定订阅确保消息被传递给正确的订阅者。

发布/订阅 用例

发布/订阅 提供的异步集成增强了系统的整体灵活性和鲁棒性,从而支持多种用例,包括

  1. 实时消息和聊天:发布/订阅 可以创建实时消息和聊天应用,例如社交媒体平台、即时通讯应用和协作工作环境。
  2. 物联网设备:发布/订阅 可用于将物联网设备连接到云端,在那里它们可以与集中的消息代理通信并发送和接收数据。通过这种方法,可以收集和处理它们生成的海量数据,这些数据稍后可用于数据分析。
  3. 新闻更新和警报:订阅者可以接收实时新闻更新和警报。此用例常见于股票交易平台、新闻应用和应急响应系统。
  4. 分布式计算和微服务:发布/订阅 可用于构建分布式系统和微服务架构,其中应用的不同组件以解耦的方式进行通信,从而提高了可扩展性和灵活性。
  5. 事件驱动架构:发布/订阅 支持事件驱动架构,其中应用的各个组件响应其他组件采取的操作。它提高了应用设计的灵活性并简化了复杂的工作流程。
  6. 解耦组件并减少依赖:发布/订阅 可以解耦应用组件并减少它们之间的依赖,从而随着时间推移更容易维护应用。
  7. 扇出处理:同时将一条消息发送给多个订阅者的过程称为扇出处理。它用于将数据或事件分发给大量消费者。例如,发布/订阅 可用于将数据扇出给多个订阅者,每个订阅者可以并行独立处理数据并将其馈送到多个下游系统。
  8. 扇入处理:将多条消息合并成一条消息的过程称为扇入处理。它对于合并来自各种源的数据处理非常有用。例如,发布/订阅 可以收集来自每个组件的数据,并将其扇入单个流以进行后续处理,在后续处理中可以聚合和分析由多个组件生成的数据。
  9. 刷新分布式缓存:在分布式缓存的多个实例之间维护一致性可能很困难。使用 发布/订阅 可以解决这个问题,它提供了一种 缓存失效 和刷新机制。当后端数据源中的数据更新时,会向一个 发布/订阅 主题发布一条消息,这会触发所有缓存实例进行刷新。因此,它降低了向用户提供过时数据的可能性,并确保所有缓存实例保持同步。
  10. 负载均衡以提高可靠性:发布/订阅 可以通过向主题发布消息并让多个订阅者并行处理这些消息来将工作负载分配到多个实例。因此,您可以根据工作负载需求调整实例数量,在保持高可用的同时增加或减少系统容量。

发布/订阅 服务类型

发布/订阅 服务可大致分为云端、自托管和实时服务。

云端发布/订阅 服务

云端发布/订阅 服务提供完全由云提供商(如 Google Cloud、AWS 和 Microsoft Azure)管理的消息传递基础设施。云端发布/订阅 系统提供高消息持久性和可用性,这使得它适用于构建需要实时不断更新的云原生应用,例如检查可用机票的航空公司应用或检查外币汇率的银行应用。此外,借助这些主要的云提供商,您可以轻松构建高度可扩展的解耦消息传递系统。

自托管发布/订阅 服务

自托管发布/订阅 服务提供可定制的消息传递系统,以满足组织内部应用的特定需求,例如简化数据传输或实现异步工作流。这为企业提供了对其系统的更大灵活性和控制权,这些系统可以部署在本地或云环境中。流行的自托管发布/订阅 服务示例包括 RabbitMQ、Apache Kafka 和 Apache Pulsar。

实时发布/订阅 服务

实时发布/订阅 服务促进实时发送和接收消息,而无需频繁轮询消息队列。这减少了传输延迟并提高了整体用户体验。该模型还包括安全功能,如通道加密、用于系统响应性的在线状态检测、消息历史记录和备份。实时发布/订阅 服务系统最适合社交媒体聊天应用、在线游戏和直播等用例。实时发布/订阅 服务系统的示例包括 Pusher 和 PubNub。

发布/订阅 与其他消息技术的比较

除了 发布/订阅 之外,还有各种可用的消息传递技术,包括点对点消息传递和消息队列。消息传递技术的选择取决于个人或组织对应用的期望。通常,在根据其预期用例决定使用哪种技术之前,会评估系统的优缺点。

点对点消息传递

点对点消息传递 是一种基本的消息传递模型,其中发送者将消息发送给特定的接收者。接收者随后可以读取消息并进行响应。这项技术最适合发送者和接收者有直接连接,并且接收者可以实时处理传入消息的情况。点对点消息传递的一些示例包括 HTTPTCP/IP

消息队列 

消息队列 是一种消息传递模型,其中消息被排队并由消费者处理。这项技术非常适用于有多个生产者和消费者,且消息需要按顺序传递的场景。消息队列技术的示例包括 RabbitMQ 和 Apache ActiveMQ。

与点对点消息传递和消息队列相比,发布/订阅 消息传递提供了几个优点。首先,发布/订阅 消息传递实现了发布者和订阅者的解耦,消除了发布者需要了解其订阅者的必要性。这使得系统能够更有效地扩展,因为可以在不影响发布者的情况下添加新的订阅者。其次,借助 发布/订阅 消息传递对异步处理的支持,订阅者可以按照自己的速度读取消息。这通过减轻系统负载来帮助提高性能。此外,发布/订阅 消息传递支持使用事件驱动架构,其中事件触发系统中的操作。

教程:使用 Redis Enterprise 实现基于事件的架构

发布/订阅 集成

现在很明显,发布/订阅 消息传递是构建分布式系统和实现事件驱动架构的强大工具。这是因为它提供了与许多其他技术和服务的集成。下面列出了一些最常用的集成类型

云平台集成:发布/订阅 消息传递是大多数云计算平台(包括 Amazon Web Services (AWS)、Google Cloud Platform (GCP) 和 Microsoft Azure)提供的服务,提供消息过滤和备份等功能。

编程语言集成:发布/订阅 消息传递支持多种编程语言及其库,例如 Java、Python 和 Node.js,从而使应用与 发布/订阅 消息传递服务之间的通信更加便捷。

API 集成:发布/订阅 消息传递允许使用针对多种语言的客户端库以及标准的 gRPC 和 REST 服务 API 技术,通过标准 API 调用来发送和接收消息。

数据库集成:发布/订阅 消息传递可以通过事件驱动架构触发数据库更新和数据处理。例如,当收到新消息时,发布/订阅 消息传递可以导致执行数据库更新。

第三方服务集成:发布/订阅 消息系统允许集成多种第三方服务,例如 Apache Kafka 和 Amazon SNS,以丰富应用功能并实现无缝数据交换。

自定义集成:发布/订阅 还允许根据组织的用例和需求进行自定义集成,以支持其内部应用。

安全和身份验证集成:发布/订阅 系统与身份和访问管理系统(例如 LDAPOAuthSAML)集成,以确保只有授权用户才能访问敏感数据,并通过通知系统以采取适当措施来帮助防止安全漏洞。

监控和日志记录集成:发布/订阅 系统受到 Prometheus 和 Grafana 等监控、警报和日志记录产品的支持。这使企业能够跟踪和监控其系统性能,并分析数据以获取见解和优化。

CI/CD 集成:与 CI/CD 工具(例如 Jenkins 和 GitLab)的集成实现了构建、测试和应用部署的自动化。此外,这也使得更容易跟踪应用的进度。

Python Redis 发布/订阅

Python 是一种编程语言,它提供了一个 Redis 客户端库,允许 Python 开发者与 Redis(一种内存数据结构存储)交互。Redis 提供了一个发布/订阅(pub/sub)消息系统,允许客户端订阅通道并在消息发布到这些通道时接收消息。

Python 可以通过发送 PUBLISH 命令发布消息和发送 SUBSCRIBE 命令订阅通道来使用 Redis 实现 发布/订阅 功能。适用于 Python 的 Redis 客户端库提供了一种便捷的方式来在 Python 应用中处理 发布/订阅 消息传递。

Redis 中处理 发布/订阅 的命令

命令使用示例和描述
SUBSCRIBESUBSCRIBE channel [channel …] – 订阅给定的通道
UNSUBSCRIBEUNSUBSCRIBE [channel [channel …]] – 取消订阅提供的通道,如果未指定通道则取消订阅所有通道
PUBLISHPUBLISH channel message – 发布消息到给定的通道
PSUBSCRIBEPSUBSCRIBE pattern [pattern …] – 订阅广播到与给定模式匹配的通道的消息
PUNSUBSCRIBEPUNSUBSCRIBE [pattern [pattern …]] – 取消订阅提供的模式,如果未指定模式则取消订阅所有已订阅的模式
来源:Redis in Action

为了有效展示该功能,由于 PUBLISH 和 SUBSCRIBE 命令在 Python 端的实现方式,使用辅助线程处理 PUBLISH 操作会更方便。

Redis 中的 发布/订阅 最佳实践

在 发布/订阅 模式中,发布者可以在一个通道上向任意数量的订阅者发送消息。这些消息是即发即忘的(fire-and-forget),也就是说,如果消息被发布时没有任何订阅者存在,该消息就会消失,无法恢复。

一旦订阅了通道,客户端将进入订阅模式,客户端无法发送任何命令。这样,客户端就变成了只读状态。发布操作没有这种限制。

可以同时订阅多个通道。让我们首先使用 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 还允许基于模式的订阅。glob 风格的模式由 PSUBSCRIBE 命令启用

> 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)。