

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

# 分散-收集模式
<a name="scatter-gather"></a>

## 意图
<a name="scatter-gather-intent"></a>

分散-收集模式是一种消息路由模式，它涉及向多个接收者广播相似或相关的请求，并使用称为*聚合器*的组件将它们的响应聚合回单条消息。此模式有助于实现并行化、减少处理延迟和处理异步通信。使用同步方法可以轻松实现分散-收集模式，但更强大的方法是将其作为异步通信中的消息路由来实现，无论是否使用消息收发服务。

## 动机
<a name="scatter-gather-motivation"></a>

在应用程序处理中，一个可能需要很长时间才能按顺序处理的请求可以分为多个并行处理的请求。您还可以通过 API 调用向多个外部系统发送请求以获得响应。当您需要来自多个来源的输入时，分散-收集模式非常有用。分散-收集聚合结果，以帮助您做出明智的决策或为请求选择最佳响应。

顾名思义，分散-收集模式由两个阶段组成：
+ *分散阶段*处理请求消息，并将其并行发送给多个接收者。在此阶段，应用程序将请求分散到网络中，并继续运行，无需等待即时响应。
+ 在*收集阶段*，应用程序收集接收者的响应，并对其进行筛选或合并，形成统一的响应。收集完所有响应后，可以将它们聚合为单个响应，也可以选择最佳响应进行进一步处理。

## 适用性
<a name="scatter-gather-applicability"></a>

在以下情况下使用分散-收集模式：
+ 您计划汇总和合并各种数据 APIs 以创建准确的响应。该模式将来自不同来源的信息整合成一个统一的整体。例如，预订系统可以向多个接收者发出请求，以获取来自多个外部合作伙伴的报价。
+ 必须将同一请求同时发送给多个接收者才能完成事务。例如，您可以使用此模式并行查询库存数据，以检查产品的可用性。
+ 您希望实现一个可靠且可扩展的系统，通过将请求分发给多个接收者来实现负载均衡。如果一个接收者失败或负载过高，其他接收者仍然可以处理请求。
+ 在实现涉及多个数据来源的复杂查询时，您需要优化性能。您可以将查询分散到相关数据库，收集部分结果，然后将它们组合成一个全面的答案。
+ 您正在实现一种 map-reduce 处理，其中数据请求路由到多个数据处理端点进行分片和复制。对部分结果进行筛选和组合，以构成正确的响应。
+ 您希望在键值数据库中写入密集型工作负载中跨分区键空间分配写入操作。聚合器通过查询每个分片中的数据来读取结果，然后将它们整合成单个响应。

## 问题和注意事项
<a name="scatter-gather-issues"></a>
+ **容错能力**：此模式依赖多个并行工作的接收者，因此妥善处理故障至关重要。为了减轻接收者故障对整个系统的影响，您可以实施冗余、复制和故障检测等策略。
+ **横向扩展限制**：随着处理节点总数的增加，关联的网络开销也会增加。每个涉及网络通信的请求都会增加延迟，且对并行化的好处产生负面影响。
+ **响应时间瓶颈**：对于需要在最终处理完成之前处理所有接收者的操作，整个系统的性能会受到最慢接收者响应时间的限制。
+ **部分响应**：在请求分散到多个接收者时，某些接收者可能会超时。在这些情况下，实现应告知客户端该响应是不完整的。您还可以使用界面前端显示响应聚合详细信息。
+ **数据一致性**：在您处理跨多个接收者的数据时，必须仔细考虑数据同步和冲突解决技术，以确保最终聚合结果的准确性和一致性。

## 实施
<a name="scatter-gather-implementation"></a>

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

分散-收集模式使用根控制器将请求分发给将处理请求的接收者。在分散阶段，此模式可以使用两种机制向接收者发送消息：
+ 按分发分散：应用程序有一个已知的接收者列表，必须调用这些接收者才能获得结果。接收者可以是具有独特功能的不同流程，也可以是已横向扩展以分发处理负载的单个流程。如果任何处理节点超时或显示响应延迟，则控制器可以将处理重新分发给另一个节点。
+ 按拍卖分散：应用程序使用[发布/订阅模式](publish-subscribe.md)向感兴趣的接收者广播消息。在这种情况下，接收者可以随时订阅消息或取消订阅。

#### 按分发分散
<a name="scatter-gather-high-distribution"></a>

在按分发分散方法中，根控制器将传入的请求分成独立的任务，并将它们分配给可用的接收者（*分散*阶段）。每个接收者（进程、容器或 Lambda 函数）独立并行地进行计算，并生成部分响应。在接收者完成任务时，他们会将响应发送给聚合器（*收集*阶段）。聚合器合并部分响应并将最终结果返回给客户端。下图说明了此工作流程。

![\[分散-收集模式的按分发分散方法\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/scatter-gather-1.png)


控制器（数据文件处理器）负责编排整组调用，并识别要调用的所有预订端点。它可以配置超时参数，以忽略花费时间过长的响应。发送请求后，聚合器会等待来自每个端点的响应。为了实现韧性，可以将每个微服务与多个实例一起部署，以实现负载均衡。聚合器获取结果，将它们组合成单条响应消息，并在进一步处理之前删除重复数据。超时的响应被忽略。控制器也可以充当聚合器，而不是使用单独的聚合器服务。

#### 按拍卖分散
<a name="scatter-gather-high-auction"></a>

如果控制器不知道接收者，或者接收者是松耦合的，您可以使用按拍卖分散方法。在此方法中，接收者订阅主题，控制器向该主题发布请求。接收者将结果发布到响应队列。由于根控制器不知道接收者，因此收集过程使用聚合器（另一种消息收发模式）来收集响应，并将其提炼成单个响应消息。聚合器使用唯一 ID 来识别一组请求。

例如，在下图中，按拍卖分散方法用于实现航空公司网站的航班预订服务。该网站允许用户搜索和显示航空公司自身及其合作伙伴航空公司的航班，且必须实时显示搜索状态。航班预订服务由三个搜索微服务组成：直飞航班、中转航班和合作伙伴航空公司。合作伙伴航空公司搜索会调用合作伙伴的 API 端点来获取响应。

![\[分散-收集模式的按拍卖分散方法\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/scatter-gather-2.png)


1. 航班预订服务（控制器）将搜索条件作为客户端的输入，然后处理请求并将其发布到该主题。

1. 控制器使用唯一 ID 来识别一组请求。

1. 客户端将唯一 ID 发送给步骤 6 的聚合器。

1. 已订阅预订主题的预订搜索微服务会收到请求。

1. 微服务处理请求，并将给定搜索条件的席位可用性返回到响应队列。

1. 聚合器整理存储在临时数据库中的所有响应消息，按唯一 ID 对航班进行分组，创建单个统一响应，然后将其发送回客户端。

### 使用实现 AWS 服务
<a name="scatter-gather-aws-services"></a>

#### 按分发分散
<a name="scatter-gather-services-distribution"></a>

在以下架构中，根控制器是一个数据文件处理器 (Amazon ECS)，它将传入的请求数据拆分为单独的亚马逊简单存储服务 (Amazon S3) 存储桶并启动工作流程。 AWS Step Functions 该工作流程下载数据，并启动并行文件处理。`Parallel` 状态等待所有任务返回响应。 AWS Lambda 函数会聚合数据并将其保存回 Amazon S3。

![\[在架构上 AWS 通过分布方法实现分散\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/scatter-gather-3.png)


下图说明了处于 `Parallel` 状态的 Step Functions 工作流程。

![\[在 AWS -Step Functions 工作流程中实现按分布分散的方法\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/scatter-gather-4.png)


#### 按拍卖分散
<a name="scatter-gather-services-auction"></a>

下图显示了按拍卖方法分散的 AWS 架构。根控制器**航班预订服务**将航班搜索请求分散到多个微服务。发布/订阅渠道是通过 Amazon Simple Notification Service（Amazon SNS）实现的，它是一种用于通信的托管式消息收发服务。Amazon SNS 支持解耦的微服务应用程序之间的消息或与用户的直接通信。您可以在 Amazon Elastic Kubernetes Service（Amazon EKS）或 Amazon Elastic Container Service（Amazon ECS）上部署收件者微服务，以实现更好的管理和可扩展性。**航班结果服务**将结果返回到客户端。它可以在其他容器编排服务（例如 Amazon ECS AWS Lambda 或 Amazon EKS）中实现。

![\[按拍卖分散方法的 AWS 架构\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/cloud-design-patterns/images/scatter-gather-5.png)


1. 航班预订服务（控制器）将搜索条件作为客户端的输入，然后处理请求并将其发布到 SNS 主题。

1. 控制器将唯一 ID 发布到 Amazon Aurora 数据库以识别请求。

1. 客户端将唯一 ID 发送给步骤 6 的客户端。

1. 已订阅预订主题的预订搜索微服务会收到请求。

1. 微服务处理请求，并将给定搜索条件的席位可用性返回到 Amazon Simple Queue Service（Amazon SQS）中的响应队列。聚合器整理所有响应消息，并将其存储在临时数据库中。

1. 航班结果服务按唯一 ID 对航班进行分组，创建单个统一响应，然后将其发送回客户端。

如果要向此架构添加其他航空公司搜索，您可以添加微服务以订阅 SNS 主题并发布到 SQS 队列。

总而言之，分散-收集模式使分布式系统能够实现高效的并行化、减少延迟并无缝处理异步通信。

#### GitHub 存储库
<a name="scatter-gather-repo"></a>

有关此模式示例架构的完整实现，请参阅 [https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-3](https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-3) 中的 GitHub 存储库。

## 研讨会
<a name="scatter-gather-workshop"></a>
+ *解耦微服务*讲习会中的[分散-收集实验室](https://catalog.us-east-1.prod.workshops.aws/workshops/e8738cf6-6eb0-4d1d-9e98-ae240d229535/en-US/scatter-gather)

## 参考博客文章
<a name="scatter-gather-blog"></a>
+ [Application integration patterns for microservices](https://aws.amazon.com/blogs/compute/application-integration-patterns-running-distributed-rfqs/)

## 相关内容
<a name="scatter-gather-resources"></a>
+ [发布/订阅](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/publish-subscribe.html)模式