

# 在分布式系统中设计交互来预防发生故障
<a name="design-interactions-in-a-distributed-system-to-prevent-failures"></a>

 分布式系统依靠通信网络来互连组件，例如服务器或服务。即使这些网络中出现数据丢失或延迟情况，您的工作负载也必须可靠运行。分布式系统组件的运行方式不得对其他组件或工作负载产生负面影响。这些最佳实践可以防止故障并缩短平均故障间隔时间 (MTBF)。

**Topics**
+ [REL04-BP01 确定所依赖的分布式系统的类型](rel_prevent_interaction_failure_identify.md)
+ [REL04-BP02 实施松耦合的依赖关系](rel_prevent_interaction_failure_loosely_coupled_system.md)
+ [REL04-BP03 持续工作](rel_prevent_interaction_failure_constant_work.md)
+ [REL04-BP04 使变异操作幂等](rel_prevent_interaction_failure_idempotent.md)

# REL04-BP01 确定所依赖的分布式系统的类型
<a name="rel_prevent_interaction_failure_identify"></a>

 分布式系统可以是同步系统、异步系统或批处理系统。同步系统必须尽可能快地处理请求，并使用 HTTP/S、REST 或远程过程调用（RPC，Remote Procedure Call）协议，同步地发出请求和响应调用，来彼此通信。异步系统在彼此通信时通过中间服务来异步交换数据，无需将各个系统耦合在一起。批处理系统则会接收大量输入数据，无需人工干预即可运行自动数据处理，并生成输出数据。

 **期望结果**：设计能够与同步、异步和批处理依赖项进行有效交互的工作负载。

 **常见反模式：**
+  工作负载无限期地等待其依赖项的响应，这可能导致工作负载客户端超时，不知道其请求是否已被接收。
+  工作负载使用会同步调用彼此的依赖系统链。这种模式要求每个系统都可用并能成功处理请求，整个链才能成功运行，这导致很容易出现崩溃行为，影响到整体可用性。
+  工作负载与其依赖项异步通信，并依赖于保证消息传递且仅传递一次的概念，但仍然会经常收到重复的消息。
+  工作负载没有使用正确的批处理调度工具，导致允许并行执行相同的批处理作业。

 **建立此最佳实践的好处：**对于给定的工作负载，通常能够在同步、异步和批处理之间实施一种或多种通信方式。此最佳实践可帮助您确定，选择每种通信方式所面对的不同权衡，以便让您的工作负载能够承受其任意依赖项中断所带来的干扰。

 **在未建立这种最佳实践的情况下暴露的风险等级：**高 

## 实施指导
<a name="implementation-guidance"></a>

 以下各节针对每种依赖项，介绍了一般性实施指导和具体实施指导。

 **一般指导** 
+  确保您的依赖项提供的性能和可靠性服务级别目标（SLO，Service-Level Objective），能够满足工作负载的性能和可靠性要求。
+  使用 [AWS 可观测性服务](https://aws.amazon.com/cloudops/monitoring-and-observability)来[监控响应时间和错误率](https://www.youtube.com/watch?v=or7uFFyHIX0)，确保依赖项提供的服务达到工作负载所需的水平。
+  确定您的工作负载在与其依赖项进行通信时，可能会遇到的潜在挑战。分布式系统[面临着诸多挑战](https://aws.amazon.com/builders-library/challenges-with-distributed-systems/)，可能会增加架构的复杂性、运营负担和成本。常见的挑战包括延迟、网络中断、数据丢失、可扩展性和数据复制延迟。
+  实施强大的错误处理和[日志记录](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)，在依赖项遇到问题时帮助排查问题。

 **同步依赖项** 

 在同步通信中，工作负载会向其依赖项发送请求并停止操作来等待响应。当其依赖项收到请求时，依赖项会尝试尽快处理请求并将响应发送回工作负载。同步通信面临的一个巨大挑战是它会导致时间耦合，这要求您的工作负载及其依赖项同时可用。当您的工作负载需要与其依赖项以同步方式通信时，请考虑以下指南：
+  工作负载在执行单个功能时，不应依赖多个同步依赖项。这种依赖项链会导致整体更加脆弱，因为要想完成请求，路径中的所有依赖项都必须可用。
+  请确定当依赖项运行状况不佳或不可用时，您采用的错误处理和重试策略。避免使用双模态行为。双模态行为是指工作负载在正常模式和故障模式下表现出不同的行为。有关双模态行为的更多详细信息，请参阅 [REL11-BP05 使用静态稳定性来防止双模态行为](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_withstand_component_failures_static_stability.html)。
+  请记住，快速失效机制比让工作负载等待要好。例如，《[AWS Lambda 开发人员指南](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html)》描述了在调用 Lambda 函数时如何处理重试和失败。
+  设置工作负载调用其依赖项时的超时。这种技术可以避免等待太长时间或无限期等待响应。有关此主题的实用讨论，请参阅 [Tuning AWS Java SDK HTTP request settings for latency-aware Amazon DynamoDB applications](https://aws.amazon.com/blogs/database/tuning-aws-java-sdk-http-request-settings-for-latency-aware-amazon-dynamodb-applications/)。
+  在完成单个请求时，尽可能减少从工作负载对依赖项进行的调用次数。在它们之间进行的频繁调用会增加耦合和延迟。

 **异步依赖项** 

 要想临时将工作负载与其依赖项解耦，就应该采取异步通信。使用异步方法，您的工作负载无需等待其依赖项或依赖项链发送响应，即可继续进行任何其他处理。

 当您的工作负载需要与其依赖项以异步方式通信时，请考虑以下指南：
+  根据应用场景和要求，确定是使用消息收发还是事件流。[消息收发](https://aws.amazon.com/messaging/)可让工作负载通过消息代理发送和接收消息，从而与其依赖项进行通信。[事件流](https://aws.amazon.com/streaming-data/)可让工作负载及其依赖项利用流服务来发布和订阅以连续数据流形式交付且需尽快处理的事件。
+  消息收发和事件流以不同的方法来处理消息，因此您需要根据以下因素作出权衡决策：
  +  **消息优先级：**消息代理可以先处理高优先级消息，再处理普通消息。在事件流中，所有消息具有相同的优先级。
  +  **消息使用**：消息代理确保使用者能够收到消息。事件流使用器必须跟踪所读取的每一条消息。
  +  **消息排序**：除非对消息收发使用先进先出（FIFO）方法，否则无法保证按照发送消息的确切顺序接收消息。事件流则始终保留数据生成的顺序。
  +  **消息删除**：使用消息收发时，使用者必须在处理消息后将其删除。事件流服务则将消息附加到流并一直保留在流中，直到消息的保留期到期。这种删除策略让事件流非常适合重放消息。
+  定义如何让工作负载在其依赖项完成工作时了解这一信息。例如，当工作负载[异步调用 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html)时，Lambda 将请求置于队列中并返回成功响应，而不返回其他信息。处理完成后，Lambda 函数可以[将结果发送到目标](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-async-destinations)，该目标可根据成功或失败进行配置。
+  利用幂等性，构建工作负载以处理重复的消息。幂等性意味着，即使您的工作负载针对同一消息多次生成结果，这些结果也会保持不变。需要指出的是，如果发生网络故障或未收到确认，则[消息收发](https://aws.amazon.com/sqs/faqs/#FIFO_queues)或[流](https://docs.aws.amazon.com/streams/latest/dev/kinesis-record-processor-duplicates.html)服务将重新发送消息。
+  如果您的工作负载没有从其依赖项获得响应，则需要重新提交请求。请考虑限制重试次数，以保留工作负载的 CPU、内存和网络资源用于处理其他请求。[AWS Lambda 文档](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-async-errors)介绍了如何处理异步调用错误。
+  利用合适的可观测性、调试和跟踪工具，来管理和操作工作负载与其依赖项的异步通信。您可以使用 [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) 来监控[消息收发](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html)和[事件流](https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html)服务。您还可以使用 [AWS X-Ray](https://aws.amazon.com/xray/) 检测工作负载，快速[获得洞察](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html)来排查问题。

 **批处理依赖项** 

 批处理系统获取输入数据，启动一系列作业来处理数据，然后生成一些输出数据，整个过程无需人工干预。根据数据大小，作业的运行时间可能只需要几分钟，而在某些情况下，也可能长达数天。当您的工作负载与其批处理依赖项通信时，请考虑以下指南：
+  定义工作负载应运行批处理作业的时间窗口。工作负载可以设置重复模式来调用批处理系统，例如每小时或每月月底。
+  确定数据输入的位置，以及处理后数据输出的位置。选择一种能让工作负载大规模读取和写入文件的存储服务，例如 [Amazon Simple Storage Service（Amazon S3）](https://aws.amazon.com/s3/)、[Amazon Elastic File System（Amazon EFS）](https://docs.aws.amazon.com/efs/latest/ug/whatisefs.html)和[适用于 Lustre 的 Amazon FSx](https://docs.aws.amazon.com/fsx/latest/LustreGuide/what-is.html)。
+  如果工作负载需要调用多个批处理作业，则可以利用 [AWS Step Functions](https://aws.amazon.com/step-functions/?step-functions.sort-by=item.additionalFields.postDateTime&step-functions.sort-order=desc) 来简化在 AWS 内部或本地运行的批处理作业的编排。此[示例项目](https://github.com/aws-samples/aws-stepfunction-complex-orchestrator-app)演示了使用 Step Functions、[AWS Batch](https://aws.amazon.com/batch/) 和 Lambda 编排批处理作业。
+  监控批处理作业以发现异常情况，例如作业完成用时超过了应有的时间。您可以使用 [CloudWatch Container Insights](https://docs.aws.amazon.com/batch/latest/userguide/cloudwatch-container-insights.html) 之类的工具来监控 AWS Batch 环境和作业。在这种情况下，工作负载会从头停止下一个作业，并向相关人员通知异常情况。

## 资源
<a name="resources"></a>

 **相关文档：**
+  [AWS 云 运维：监控和可观测性](https://aws.amazon.com/cloudops/monitoring-and-observability) 
+  [Amazon Builders' Library：分布式系统相关挑战](https://aws.amazon.com/builders-library/challenges-with-distributed-systems/) 
+  [REL11-BP05 使用静态稳定性来防止双模态行为](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_withstand_component_failures_static_stability.html) 
+  [AWS Lambda 开发人员指南：AWS Lambda 中的错误处理和自动重试](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html) 
+  [Tuning AWS Java SDK HTTP request settings for latency-aware Amazon DynamoDB applications](https://aws.amazon.com/blogs/database/tuning-aws-java-sdk-http-request-settings-for-latency-aware-amazon-dynamodb-applications/) 
+  [AWS 消息收发](https://aws.amazon.com/messaging/) 
+  [什么是流数据？](https://aws.amazon.com/streaming-data/) 
+  [AWS Lambda 开发人员指南：异步调用](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html) 
+  [Amazon Simple Queue Service 常见问题：FIFO 队列](https://aws.amazon.com/sqs/faqs/#FIFO_queues) 
+  [Amazon Kinesis Data Streams Developer Guide: Handling Duplicate Records](https://docs.aws.amazon.com/streams/latest/dev/kinesis-record-processor-duplicates.html) 
+  [Amazon Simple Queue Service Developer Guide: Available CloudWatch metrics for Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html) 
+  [Amazon Kinesis Data Streams Developer Guide: Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch](https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html) 
+  [AWS X-Ray Developer Guide: AWS X-Ray concepts](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html) 
+  [AWS Samples on GitHub: AWS Step functions Complex Orchestrator App](https://github.com/aws-samples/aws-stepfunction-complex-orchestrator-app) 
+  [AWS Batch User Guide: AWS Batch CloudWatch Container Insights](https://docs.aws.amazon.com/batch/latest/userguide/cloudwatch-container-insights.html) 

 **相关视频：**
+  [AWS Summit SF 2022 – Full-stack observability and application monitoring with AWS (COP310)](https://www.youtube.com/watch?v=or7uFFyHIX0) 

 **相关工具：**
+  [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) 
+  [Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html) 
+  [AWS X-Ray](https://aws.amazon.com/xray/) 
+  [Amazon Simple Storage Service（Amazon S3）](https://aws.amazon.com/s3/) 
+  [Amazon Elastic File System (Amazon EFS)](https://docs.aws.amazon.com/efs/latest/ug/whatisefs.html) 
+  [适用于 Lustre 的 Amazon FSx](https://docs.aws.amazon.com/fsx/latest/LustreGuide/what-is.html) 
+  [AWS Step Functions](https://aws.amazon.com/step-functions/?step-functions.sort-by=item.additionalFields.postDateTime&step-functions.sort-order=desc) 
+  [AWS Batch](https://aws.amazon.com/batch/) 

# REL04-BP02 实施松耦合的依赖关系
<a name="rel_prevent_interaction_failure_loosely_coupled_system"></a>

 队列系统、流系统、工作流和负载均衡器等依赖关系是松耦合的。松耦合有助于隔离某个组件的行为与依赖于它的其他组件的行为，从而提升韧性和敏捷性。

 解耦依赖关系（例如排队系统、流系统和工作流程），有助于最大限度地减少更改或故障对系统的影响。这种分离将组件的行为与依赖该组件的其他行为隔离开来，从而提高了韧性和敏捷性。

 在紧耦合的系统中，更改一个组件可能导致需要更改依赖该组件的其他组件，从而使所有组件的性能均降低。*松*耦合会打破这种依赖关系，使存在依赖关系的组件只需了解经过版本控制而且已发布的接口。在依赖项之间实施松耦合将隔离一个组件中的故障，防止对其他组件造成影响。

 松耦合允许您修改代码或向组件添加功能，同时最大限度地降低依赖于该组件的其他组件的风险。它还允许在组件级别实现精细的韧性，让您可以横向扩展或甚至改变依赖项的底层实施。

 要通过松耦合进一步提升韧性，在可能的情况下采用异步组件交互。若确定对请求进行注册已足够，则此模型适用于无需立即响应的任何交互。它包含一个生成事件的组件和另外一个使用事件的组件。两个组件不会通过直接点对点交互，但通常经由中间持久存储层集成，例如 Amazon SQS 队列或是 Amazon Kinesis 或 AWS Step Functions 这样的就流数据平台。

![\[图中显示了队列系统和负载均衡器等依赖关系是松散耦合的\]](http://docs.aws.amazon.com/zh_cn/wellarchitected/latest/reliability-pillar/images/dependency-diagram.png)


 Amazon SQS 队列和 AWS Step Functions 只是为松耦合增加中间层的两种方式。您还可以使用 Amazon EventBridge 在 AWS 云 中构建事件驱动型架构，而 Amazon EventBridge 可从其依赖的服务（事件使用器）中提取客户端（事件产生器）。如果需要进行高吞吐量、基于推送的多对多消息收发，Amazon Simple Notiﬁcation Service（Amazon SNS）是可供选择的高效解决方案。通过 Amazon SNS 主题，您的发布者系统可以将消息扇出到大量订阅用户端点以便进行并行处理。

 虽然队列具有多项优点，但在大多数硬性实时系统中，早于阈值时间（通常为秒）的请求应被视为过时（客户端已放弃而且不再等待响应）而不被处理。因此，较新（而且可能依然有效）的请求会被处理。

 **期望结果：**实施松耦合依赖项可以将故障的影响范围最大限度地缩小到组件级别，有助于诊断和解决问题。松耦合还简化了开发周期，允许团队在模块级别实施更改，而不会影响依赖它的其他组件的性能。这种方法能够根据资源需求以及有助于提高成本效益的组件利用率，在组件层面进行横向扩展。

 **常见反模式：**
+  部署整体工作负载。
+  直接在工作负载层之间调用 API，不具备失效转移或异步处理请求的功能。
+  使用共享数据进行紧密耦合。松耦合的系统应避免通过共享数据库或其他形式的紧密耦合数据存储共享数据，这可能会重新引入紧耦合并阻碍可扩展性。
+  忽略背压。当组件无法以相同速度处理传入数据时，您的工作负载应该能够减慢或停止传入数据。

 **建立此最佳实践的好处：**松耦合有助于隔离某个组件的行为与依赖于它的其他组件的行为，从而提升韧性和敏捷性。组件中的故障相互隔离。

 **在未建立这种最佳实践的情况下暴露的风险等级：**高 

## 实施指导
<a name="implementation-guidance"></a>

 实施松耦合的依赖关系。可利用多种解决方案来构建松耦合的应用程序。其中包括用于实施全面托管的队列、自动化工作流、对事件的反应以及 API 等内容的服务，这些服务有助于将组件的行为相互隔离，从而提高韧性和敏捷性。
+  **构建事件驱动型架构：**[Amazon EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html) 有助于构建松耦合和分布式的事件驱动架构。
+  **在分布式系统中实施队列：**可以使用 [Amazon Simple Queue Service（Amazon SQS）](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html)集成或解耦分布式系统。
+  **将组件容器化为微服务：**[微服务](https://aws.amazon.com/microservices/)有助于团队构建由小型独立组件组成且通过明确定义的 API 进行通信的应用程序。[Amazon Elastic Container Service（Amazon ECS）](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html)和 [Amazon Elastic Kubernetes Service（Amazon EKS）](https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html)有助于快速使用容器。
+  **使用 Step Functions 管理工作流程：**[Step Functions ](https://aws.amazon.com/step-functions/getting-started/) 有助于将多个 AWS 服务协调为灵活的工作流程。
+  **利用发布-订阅（pub/sub）消息收发架构：**[Amazon Simple Notification Service（Amazon SNS）](https://docs.aws.amazon.com/sns/latest/dg/welcome.html)提供从发布者到订阅用户（也称为生产者和使用者）的消息传输。

### 实施步骤
<a name="implementation-steps"></a>
+  事件驱动型架构中的组件由事件启动。事件是系统中发生的操作，例如用户将商品添加到购物车。操作成功后，将生成一个激活系统的下一个组件的事件。
  + [Building Event-driven Applications with Amazon EventBridge](https://aws.amazon.com/blogs/compute/building-an-event-driven-application-with-amazon-eventbridge/)
  + [AWS re:Invent 2022 – Designing Event-Driven Integrations using Amazon EventBridge](https://www.youtube.com/watch?v=W3Rh70jG-LM)
+  分布式消息收发系统主要有三个部分，需要为基于队列的架构实施这些部分。它们包括分布式系统的组件、用于解耦的队列（分布在 Amazon SQS 服务器上）以及队列中的消息。典型的系统有将消息发送到队列中的产生器和从队列接收消息的使用器。该队列将消息存储在多台 Amazon SQS 服务器上以实现冗余。
  + [Basic Amazon SQS architecture](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html)
  + [使用 Amazon Simple Queue Service 在分布式应用程序间发送消息](https://aws.amazon.com/getting-started/hands-on/send-messages-distributed-applications/)
+  由于松耦合的组件由独立团队管理，因此微服务如果得到充分利用，可以增强可维护性并提高可扩展性。它还允许在发生变化时将行为隔离到单个组件。
  + [在 AWS 上实施微服务](https://docs.aws.amazon.com/whitepapers/latest/microservices-on-aws/microservices-on-aws.html)
  + [Let's Architect\$1 Architecting microservices with containers](https://aws.amazon.com/blogs/architecture/lets-architect-architecting-microservices-with-containers/)
+  借助 AWS Step Functions，您可以构建分布式应用程序、实现流程自动化、编排微服务等。将多个组件编排到一个自动化工作流程中，让您可以将应用程序中的依赖关系解耦。
  + [使用 AWS Step Functions 和 AWS Lambda 创建无服务器工作流程](https://aws.amazon.com/tutorials/create-a-serverless-workflow-step-functions-lambda/)
  + [AWS Step Functions 入门](https://aws.amazon.com/step-functions/getting-started/)

## 资源
<a name="resources"></a>

 **相关文档：**
+  [Amazon EC2: Ensuring Idempotency](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html) 
+  [Amazon Builders' Library：分布式系统相关挑战](https://aws.amazon.com/builders-library/challenges-with-distributed-systems/) 
+  [Amazon Builders' Library：Reliability, constant work, and a good cup of coffee](https://aws.amazon.com/builders-library/reliability-and-constant-work/) 
+  [什么是 Amazon EventBridge？](https://docs.aws.amazon.com/eventbridge/latest/userguide/what-is-amazon-eventbridge.html) 
+  [What Is Amazon Simple Queue Service?](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html)
+ [Break up with your monolith](https://pages.awscloud.com/break-up-your-monolith.html)
+ [Orchestrate Queue-based Microservices with AWS Step Functions and Amazon SQS](https://aws.amazon.com/tutorials/orchestrate-microservices-with-message-queues-on-step-functions/)
+ [Basic Amazon SQS architecture](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html)
+ [Queue-Based Architecture](https://docs.aws.amazon.com/wellarchitected/latest/high-performance-computing-lens/queue-based-architecture.html)

 **相关视频：**
+  [AWS New York Summit 2019: Intro to Event-driven Architectures and Amazon EventBridge (MAD205)](https://youtu.be/tvELVa9D9qU) 
+  [AWS re:Invent 2018: Close Loops and Opening Minds: How to Take Control of Systems, Big and Small ARC337 (includes loose coupling, constant work, static stability)](https://youtu.be/O8xLxNje30M) 
+  [AWS re:Invent 2019: Moving to event-driven architectures (SVS308)](https://youtu.be/h46IquqjF3E) 
+ [AWS re:Invent 2019: Scalable serverless event-driven applications using Amazon SQS and Lambda ](https://www.youtube.com/watch?v=2rikdPIFc_Q)
+ [AWS re:Invent 2022 – Designing Event-Driven Integrations using Amazon EventBridge](https://www.youtube.com/watch?v=W3Rh70jG-LM)
+ [AWS re:Invent 2017: Elastic Load Balancing Deep Dive and Best Practices ](https://www.youtube.com/watch?v=9TwkMMogojY)

# REL04-BP03 持续工作
<a name="rel_prevent_interaction_failure_constant_work"></a>

 系统会在负载中存在剧烈快速更改时失败。例如，如果您的工作负载执行的一项运行状况检查监控着数千个服务器的运行状况，每次都应发送相同大小的有效负载（当前状态的完整快照）。无论是否有服务器或有多少服务器发生故障，运行状况检查系统都会持续工作，而不会有剧烈、快速的变动。

 例如，如果运行状况检查系统正在监控 10 万台服务器，在通常较低的服务器故障率下，它的负载是正常的。但如果发生重大事件让一半的服务器运行状况不佳，则运行状况检查系统会因为尝试更新通知系统以及向其客户端传送状态而变得不堪重负。因此，运行状况检查系统每次都应发送当前状态的完整快照，10 万台服务器的运行状况状态（每个状态都用一位表示）仅占 12.5 KB 的有效负载。无论是没有服务器发生故障还是所有服务器都发生故障，运行状况检查系统都会持续工作，而大幅度骤变也不会威胁到系统的稳定性。这实际上就是 Amazon Route 53 处理对端点（例如 IP 地址）运行状况检查的方式，从而确定最终用户如何路由到这些端点。

 **在未建立这种最佳实践的情况下暴露的风险等级：**低 

## 实施指导
<a name="implementation-guidance"></a>
+  持续工作，这样系统就不会在负载发生骤变时出现故障。
+  实施松耦合的依赖关系。队列系统、流系统、工作流和负载均衡器等依赖关系是松耦合的。松耦合有助于隔离某个组件的行为与依赖于它的其他组件的行为，从而提升韧性和敏捷性。
  +  [Amazon Builders' Library：Reliability, constant work, and a good cup of coffee](https://aws.amazon.com/builders-library/reliability-and-constant-work/) 
  +  [AWS re:Invent 2018: Close Loops and Opening Minds: How to Take Control of Systems, Big and Small ARC337 (includes constant work)](https://youtu.be/O8xLxNje30M?t=2482) 
    +  以监控 10 万台服务器的运行状况检查系统为例，对工作负载进行设计，确保无论成功或失败次数如何，有效负载大小都保持不变。

## 资源
<a name="resources"></a>

 **相关文档：**
+  [Amazon EC2: Ensuring Idempotency](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html) 
+  [Amazon Builders' Library：分布式系统相关挑战](https://aws.amazon.com/builders-library/challenges-with-distributed-systems/) 
+  [Amazon Builders' Library：Reliability, constant work, and a good cup of coffee](https://aws.amazon.com/builders-library/reliability-and-constant-work/) 

 **相关视频：**
+  [AWS New York Summit 2019: Intro to Event-driven Architectures and Amazon EventBridge (MAD205)](https://youtu.be/tvELVa9D9qU) 
+  [AWS re:Invent 2018: Close Loops and Opening Minds: How to Take Control of Systems, Big and Small ARC337 (includes constant work)](https://youtu.be/O8xLxNje30M?t=2482) 
+  [AWS re:Invent 2018: Close Loops and Opening Minds: How to Take Control of Systems, Big and Small ARC337 (includes loose coupling, constant work, static stability)](https://youtu.be/O8xLxNje30M) 
+  [AWS re:Invent 2019: Moving to event-driven architectures (SVS308)](https://youtu.be/h46IquqjF3E) 

# REL04-BP04 使变异操作幂等
<a name="rel_prevent_interaction_failure_idempotent"></a>

 幂等服务承诺每个请求只确切处理一次，因此发起多个相同请求与发起单个请求的效果相同。这使客户端可以更轻松地进行重试，而不必担心多次错误地处理请求。要执行此操作，客户端可以发出具有幂等性令牌的 API 请求，每当重复该请求时都会使用此令牌。幂等服务 API 使用令牌来返回响应，该响应与首次完成请求时返回的响应相同，即使系统的底层状态已经改变也是如此。

 在分布式系统中，至多（客户端仅发起一个请求）或至少（持续发起请求直到客户端收到成功确认）执行某项操作一次相对简单。难就难在要保证某项操作*确切执行一次*，从而使发出多个相同的请求和发出单个请求具有一样的效果。在 API 中使用幂等性令牌，服务可以一次或多次收到变异请求，而不需要创建重复的记录或产生副作用。

 **期望结果：**您有一个一致、有据可查且广泛采用的方法来确保跨所有组件和服务的幂等性。

 **常见反模式：**
+  您不加选择地应用幂等性，即使不需要也是如此。
+  您引入过于复杂的逻辑来实现幂等性。
+  您使用时间戳作为幂等性的密钥。由于时钟偏差或多个客户端使用相同的时间戳来应用更改，这可能会导致不准确。
+  您存储整个有效载荷以保持幂等性。在这种方法中，您为每个请求保存完整的数据有效载荷，并对于每个新请求将其覆盖。这可能会降低性能并影响可扩展性。
+  您在不同服务之间以不一致的方式生成密钥。如果密钥不一致，服务可能无法识别重复的请求，从而导致意想不到的结果。

 **建立此最佳实践的好处：**
+  提高了可扩展性：系统可以处理重试和重复的请求，而无需执行额外的逻辑或复杂的状态管理。
+  增强了可靠性：幂等性有助于服务以一致的方式处理多个相同的请求，从而降低意外副作用或重复记录的风险。这在分布式系统中尤其重要，在此类系统中，网络故障和重试很常见。
+  提高了数据一致性：由于同一个请求会产生相同的响应，因此幂等性有助于保持分布式系统间的数据一致性。这对于维护事务和操作的完整性至关重要。
+  错误处理：幂等性令牌使错误处理变得更加简单。如果客户端由于问题而未收到响应，则它可以使用相同的幂等性令牌安全地重新发送请求。
+  操作透明度：通过幂等性，可以更好地进行监控和日志记录。服务可以使用其幂等性令牌记录请求，这可以更轻松地跟踪和调试问题。
+  简化了 API 合约：它可以简化客户端和服务器端系统之间的合约，并减少对错误数据处理的担忧。

 **在未建立这种最佳实践的情况下暴露的风险等级：**中 

## 实施指导
<a name="implementation-guidance"></a>

 在分布式系统中，至多（客户端仅发起一个请求）或至少（客户端持续发起请求直到确认成功）执行某项操作一次相对简单。然而，*确切一次* 实施此行为则具有挑战性。为了实现这一点，客户端应该为每个请求生成并提供幂等性令牌。

 通过使用幂等性令牌，服务可以区分新请求和重复的请求。当服务收到带有幂等性令牌的请求时，它会检查该令牌是否已被使用。如果该令牌已被使用，则该服务会检索并返回存储的响应。如果令牌是新的，则服务会处理请求，将响应与令牌一起存储，然后返回响应。这种机制使所有响应都是幂等的，从而提高了分布式系统的可靠性和一致性。

 幂等性也是事件驱动型架构的一项重要行为。这些架构通常由消息队列提供支持，例如 Amazon SQS、Amazon MQ、Amazon Kinesis Streams 或 Amazon Managed Streaming for Apache Kafka（MSK）。在某些情况下，只发布一次的消息可能会意外地传送多次。当发布者生成幂等性令牌并将其包含在消息中时，它要求对收到的任何重复消息的处理不会导致对同一消息执行重复的操作。使用者应跟踪收到的每个令牌，并忽略包含重复令牌的消息。

 服务和使用者还应将收到的幂等性令牌传递给它调用的任何下游服务。处理链中的每个下游服务都同样负责确保实施幂等性，以避免多次处理消息的副作用。

### 实施步骤
<a name="implementation-steps"></a>

1.  **确定幂等操作** 

    确定哪些操作需要幂等性。这些操作通常包括 POST、PUT 和 DELETE HTTP 方法以及数据库插入、更新或删除操作。不变异状态的操作（例如只读查询）通常不需要幂等性，除非它们有副作用。

1.  **使用唯一标识符** 

    在发送者发送的每个幂等操作请求中包含一个唯一的令牌，既可以直接在请求中，也可以作为其元数据的一部分（例如，HTTP 标头）。这可让接收者识别和处理重复的请求或操作。通常用于令牌的标识符包括 [Universally Unique Identifiers (UUIDs)](https://datatracker.ietf.org/doc/html/rfc9562) 和 [K-Sortable Unique Identifiers (KSUIDs)](https://github.com/segmentio/ksuid)。

1.  **跟踪和管理状态** 

    维护工作负载中每个操作或请求的状态。这可以通过将幂等性令牌和相应的状态（例如待处理、已完成或失败）存储在数据库、缓存或其它持久存储中来实现。此状态信息可让工作负载识别和处理重复的请求或操作。

    如果需要，可通过使用适当的并发控制机制（例如锁定、事务或乐观并发控制）来保持一致性和原子性。这包括记录幂等令牌以及运行与为请求提供服务相关联的所有变异操作的过程。这有助于防止竞争条件并验证幂等操作是否正确运行。

    定期从数据存储中移除旧的幂等性令牌来管理存储和性能。如果存储系统支持此操作，请考虑对数据使用过期时间戳（通常称为生存时间或 TTL 值）。重用幂等性令牌的可能性会随时间推移而降低。

    通常用于存储幂等性令牌和相关状态的常见 AWS 存储选项包括：
   +  **Amazon DynamoDB**：DynamoDB 是一项 NoSQL 数据库服务，可提供低延迟性能和高可用性，因此非常适合存储与幂等性相关的数据。DynamoDB 的键值和文档数据模型支持高效存储和检索幂等性令牌和关联的状态信息。如果应用程序在插入幂等性令牌时设置了 TTL 值，则 DynamoDB 也可以自动使这些令牌过期。
   +  **Amazon ElastiCache**：ElastiCache 能够以高吞吐量、低延迟和低成本存储幂等性令牌。如果应用程序在插入幂等性令牌时设置了 TTL 值，ElastiCache（Redis）和 ElastiCache（Memcached）也可以自动使这些令牌过期。
   +  **Amazon Relational Database Service（RDS）**：可以使用 Amazon RDS 存储幂等性令牌和相关状态信息，特别是在应用程序已经将关系数据库用于其它用途的情况下。
   +  **Amazon Simple Storage Service（S3）**：Amazon S3 是一项高度可扩展和耐用的对象存储服务，可用于存储幂等性令牌和相关元数据。S3 的版本控制功能对于维护幂等操作的状态特别有用。存储服务的选择通常取决于诸如因素，例如：与幂等性相关的数据量、所需的性能特征、对耐久性和可用性的需求，以及幂等性机制如何与整体工作负载架构集成。

1.  **实施幂等操作** 

    将 API 和工作负载组件设计为幂等的。将幂等性检查纳入工作负载组件。在处理请求或执行操作之前，请检查是否已经处理了唯一标识符。如果已处理，则返回之前的结果，而不是再次执行该操作。例如，如果客户端发送一个创建用户的请求，请检查是否已存在具有相同唯一标识符的用户。如果该用户存在，则应返回现有用户信息，而不是创建新用户。同样，如果队列使用者收到带有重复幂等性令牌的消息，则该使用者应忽略该消息。

    创建全面的测试套件来验证请求的幂等性。它们应涵盖各种各样的场景，例如成功的请求、失败的请求和重复的请求。

    如果工作负载利用 AWS Lambda 函数，请考虑使用 Powertools for AWS Lambda。Powertools for AWS Lambda 是一个开发人员工具包，有助于在使用 AWS Lambda 函数时实施无服务器最佳实践并提高开发人员速度。特别是，它提供了一个实用程序，可将 Lambda 函数转换为可以安全重试的幂等操作。

1.  **清晰地传达幂等性** 

    记录 API 和工作负载组件，以清晰地传达操作的幂等性质。这有助于客户了解预期行为以及如何可靠地与工作负载进行交互。

1.  **监控和审计** 

    实施监控和审计机制，以检测与响应的幂等性相关的任何问题，例如意外的响应变化或过多的重复请求处理。这有助于您检测和调查工作负载中的任何问题或意外行为。

## 资源
<a name="resources"></a>

 **相关最佳实践：**
+  [REL05-BP03 控制与限制重试调用](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_mitigate_interaction_failure_limit_retries.html) 
+  [REL06-BP01 为工作负载监控全部组件（生成）](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_monitor_aws_resources_monitor_resources.html) 
+  [REL06-BP03 发送通知（实时处理和报警）](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_monitor_aws_resources_notification_monitor.html) 
+  [REL08-BP02 将功能测试作为部署的一部分进行集成](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_tracking_change_management_functional_testing.html) 

 **相关文档：**
+  [The Amazon Builders' Library: Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/) 
+  [Amazon Builders' Library：分布式系统相关挑战](https://aws.amazon.com/builders-library/challenges-with-distributed-systems/) 
+  [Amazon Builders' Library：Reliability, constant work, and a good cup of coffee](https://aws.amazon.com/builders-library/reliability-and-constant-work/) 
+  [Amazon Elastic Container Service: Ensuring idempotency](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/ECS_Idempotency.html) 
+  [如何让我的 Lambda 函数保持幂等性？](https://repost.aws/knowledge-center/lambda-function-idempotent) 
+  [Ensuring idempotency in Amazon EC2 API requests](https://docs.aws.amazon.com/ec2/latest/devguide/ec2-api-idempotency.html) 

 **相关视频：**
+  [Building Distributed Applications with Event-driven Architecture - AWS Online Tech Talks](https://www.youtube.com/watch?v=gA2-eqDVSng&t=1668s) 
+  [AWS re:Invent 2023 - Building next-generation applications with event-driven architecture](https://www.youtube.com/watch?v=KXR17uwLEC8) 
+  [AWS re:Invent 2023 - Advanced integration patterns & trade-offs for loosely coupled systems](https://www.youtube.com/watch?v=FGKGdUiZKto) 
+  [AWS re:Invent 2023 - Advanced event-driven patterns with Amazon EventBridge](https://www.youtube.com/watch?v=6X4lSPkn4ps) 
+  [AWS re:Invent 2018 - Close Loops and Opening Minds: How to Take Control of Systems, Big and Small ARC337 (includes loose coupling, constant work, static stability)](https://youtu.be/O8xLxNje30M) 
+  [AWS re:Invent 2019 - Moving to event-driven architectures (SVS308)](https://youtu.be/h46IquqjF3E) 

 **相关工具：**
+  [Idempotency with AWS Lambda Powertools (Java)](https://docs.powertools.aws.dev/lambda/java/utilities/idempotency/) 
+  [Idempotency with AWS Lambda Powertools (Python)](https://docs.powertools.aws.dev/lambda/python/latest/utilities/idempotency/) 
+  [AWS Lambda Powertools GitHub page](https://github.com/aws-powertools/) 