

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 发布-订阅模式
<a name="publish-subscribe"></a>

## 意图
<a name="publish-subscribe-intent"></a>

发布-订阅模式，也称为“发-订”模式，是一种消息发送方（*发布者*）与感兴趣的接收方（*订阅用户*）解耦的消息模式。此模式通过称为*消息代理*或*路由器*（消息基础实施）的中介发布消息或事件，从而实现异步通信。发布-订阅模式将消息传递的责任转移给消息基础实施，从而提高了发送方的可扩展性和响应能力，由此发送方可以专注于核心消息处理。

## 动机
<a name="publish-subscribe-motivation"></a>

在分布式架构中，当系统内发生事件时，系统组件通常需要提供信息给其他组件。发布-订阅模式将关注点分开，以便应用程序可以专注于其核心功能，而消息基础设施则负责处理消息路由和可靠传送等通信职责。发布-订阅模式可实现异步消息发送，从而使发布者和订阅用户解耦。发布者也可以在订阅用户不知情的情况下发送消息。

## 适用性
<a name="publish-subscribe-applicability"></a>

在以下情况下使用发布-订阅模式：
+ 如果单条消息的工作流程不同，则需要并行处理。
+ 无需向多个订阅用户广播消息，也无需接收方的实时响应。
+ 系统或应用程序可以容忍数据或状态的最终一致性。
+ 应用程序或组件必须与其他可能使用不同语言、协议或平台的应用程序或服务进行通信。

## 问题和注意事项
<a name="publish-subscribe-issues"></a>
+ **订阅者可用性：**发布者不知道订阅用户是否在收听，订阅用户可能没有收听。发布的消息本质上是短暂的，如果订阅用户不可用，则可能会导致消息被丢弃。
+ **消息传送保证：**通常，发布-订阅模式不能保证向所有订阅者类型发送消息，尽管某些服务（例如 Amazon Simple Notiﬁcation Service（Amazon SNS））可以向某些订阅者子集提供[精确一次](https://docs.aws.amazon.com/sns/latest/dg/fifo-message-dedup.html)的传送。
+ **存活时间（TTL）：**消息有生命期，如果未在该时段内处理则过期。考虑将已发布的消息添加到队列中，以便其可以持续存在，并保证在 TTL 期限之后进行处理。
+ **消息相关性：**生产者可以将相关性的时间跨度设置为消息数据的一部分，并且可以在此日期之后丢弃消息。在决定如何处理消息之前，请考虑设计使用者来检查这些信息。
+ **最终一致性：**发布消息的时间与订阅用户使用消息的时间之间存在延迟。当需要强一致性时，这样可能会导致订阅用户数据存储最终变得一致。当生产者和使用者需要近乎实时的互动时，最终一致性也可能是一个问题。
+ **单向通信：**将发布-订阅模式视为单向通信。如果需要同步响应，则需要使用返回订阅通道进行双向消息传递的应用程序应考虑使用请求-回复模式。
+ **消息顺序：**不能保证消息排序。如果使用者需要有序的消息，则建议您使用 [Amazon SNS FIFO 主题](https://docs.aws.amazon.com/sns/latest/dg/fifo-topic-message-ordering.html)来保证顺序。
+ **消息复制：**基于消息收发基础实施，可以将重复的消息传送给使用者。必须将使用者设计为幂等性，才能处理重复的消息。或者，使用 [Amazon SNS FIFO 主题](https://docs.aws.amazon.com/sns/latest/dg/fifo-topic-message-ordering.html)来保证“精确一次”的传送。
+ **消息过滤：**使用者通常只对生产者发布的消息的子集感兴趣。提供机制，允许订阅用户通过提供主题或内容筛选器来筛选或缩小他们收到的消息范围。
+ **消息重播：**消息重播功能可能取决于消息收发基础实施。您还可以根据应用场景提供自定义实施。
+ **死信队列：**在邮政系统中，死信办公室是处理无法投递的邮件的设施。[发-订消息收发](https://aws.amazon.com/pub-sub-messaging/)中，死信队列（DLQ）是指无法传输给订阅端点的消息的队列。

## 实现
<a name="publish-subscribe-implementation"></a>

### 高级架构
<a name="publish-subscribe-high-level-arch"></a>

在发布-订阅模式中，被称为消息代理或路由器的异步消息收发子系统会跟踪订阅。当生产者发布事件时，消息收发基础设施会向每位使用者发送一条消息。将消息发送给订阅用户后，该消息将从消息基础设施中移除，因此无法重播，新订阅用户也看不到该事件。消息代理或路由器通过以下方式将事件产生器与消息使用者分离：
+ 为生产者提供输入通道，以使用定义的消息格式发布打包成消息的事件。
+ 为每个订阅创建一个单独的输出通道。*订阅*是指使用者的连接，他们在其中监听与特定输入通道关联的事件消息。
+ 事件发布时，将消息从输入通道复制到所有使用者的输出通道。

![\[将消息从输入渠道复制到输出渠道。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/publish-subscribe-1.png)


### 使用亚马逊云科技服务来实施
<a name="publish-subscribe-aws-services"></a>

**Amazon SNS** 

Amazon SNS 是一项完全托管的发布者-订阅用户服务，它提供应用程序对应用程序（A2A）的消息收发，用于分离分布式应用程序。它还提供应用程序对人（A2P）的消息收发，用于发送短信、电子邮件和其他推送通知。

Amazon SNS 提供两种类型的主题：标准主题和先进先出（FIFO）主题。
+ 标准主题支持每秒无限数量的消息，并提供最佳排序和重复数据删除。  
![\[Amazon SNS 中的标准主题。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/publish-subscribe-2.png)
+ FIFO 主题提供严格的排序和重复数据删除，每个 FIFO 主题最多支持每秒 300 条消息或每秒 10 MB（按先到者计算）。  
![\[Amazon SNS 中的 FIFO 主题\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/publish-subscribe-3.png)

下图显示了如何使用 Amazon SNS 实现发布-订阅模式。用户付款后，`Payments` Lambda 函数会向 `Payments` SNS 主题发送一条 SNS 消息。此 SNS 主题有三个订阅用户。每个订阅用户都会收到消息的一个副本并对其进行处理。

![\[如何使用 Amazon SNS 实现发布-订阅模式。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/publish-subscribe-4.png)


**Amazon EventBridge**

如果您需要更复杂地将来自多个生产者的消息通过不同协议路由到订阅的使用者，或者需要直接订阅和扇出订阅，则可以使用 Amazon EventBridge。EventBridge 还支持基于内容的路由、筛选、排序以及拆分或聚合。在下图中，EventBridge 用于构建发布-订阅模式的版本，在该模式中，使用事件规则定义订阅用户。用户付款后，`Payments` Lambda 函数使用基于自定义架构的默认事件总线向 EventBridge 发送消息，该架构包含三条指向不同目标的规则。每个微服务都会处理消息并执行所需的操作。

![\[如何使用 Amazon EventBridge 实现发布-订阅模式。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/publish-subscribe-5.png)


### 研讨会
<a name="publish-subscribe-workshop"></a>
+ [在亚马逊云科技云上构建事件驱动型架构](https://catalog.us-east-1.prod.workshops.aws/workshops/63320e83-6abc-493d-83d8-f822584fb3cb/en-US/) 
+ [使用 Amazon Simple Queue Service（Amazon SQS）、Amazon Simple Notiﬁcation Service（Amazon SNS）发送扇出事件通知](https://aws.amazon.com/getting-started/hands-on/send-fanout-event-notifications/)

## 参考博客文章
<a name="publish-subscribe-blog"></a>
+ [在无服务器应用程序的消息收发服务之间进行选择](https://aws.amazon.com/blogs/compute/choosing-between-messaging-services-for-serverless-applications/)
+ [使用 DLQ 为 Amazon SNS、Amazon SQS、Amazon Lambda 设计耐用的无服务器应用程序](https://aws.amazon.com/blogs/compute/designing-durable-serverless-apps-with-dlqs-for-amazon-sns-amazon-sqs-aws-lambda/)
+ [使用 Amazon SNS 消息筛选功能简化您的发-订消息收发方式](https://aws.amazon.com/blogs/compute/simplify-pubsub-messaging-with-amazon-sns-message-filtering/)

## 相关内容
<a name="publish-subscribe-resources"></a>
+ [发-订消息收发方式的特征](https://aws.amazon.com/what-is/pub-sub-messaging/)