REL04-BP04 使变异操作幂等
幂等服务承诺每个请求只确切处理一次,因此发起多个相同请求与发起单个请求的效果相同。这使客户端可以更轻松地进行重试,而不必担心多次错误地处理请求。要执行此操作,客户端可以发出具有幂等性令牌的 API 请求,每当重复该请求时都会使用此令牌。幂等服务 API 使用令牌来返回响应,该响应与首次完成请求时返回的响应相同,即使系统的底层状态已经改变也是如此。
在分布式系统中,至多(客户端仅发起一个请求)或至少(持续发起请求直到客户端收到成功确认)执行某项操作一次相对简单。难就难在要保证某项操作确切执行一次,从而使发出多个相同的请求和发出单个请求具有一样的效果。在 API 中使用幂等性令牌,服务可以一次或多次收到变异请求,而不需要创建重复的记录或产生副作用。
期望结果:您有一个一致、有据可查且广泛采用的方法来确保跨所有组件和服务的幂等性。
常见反模式:
-
您不加选择地应用幂等性,即使不需要也是如此。
-
您引入过于复杂的逻辑来实现幂等性。
-
您使用时间戳作为幂等性的密钥。由于时钟偏差或多个客户端使用相同的时间戳来应用更改,这可能会导致不准确。
-
您存储整个有效载荷以保持幂等性。在这种方法中,您为每个请求保存完整的数据有效载荷,并对于每个新请求将其覆盖。这可能会降低性能并影响可扩展性。
-
您在不同服务之间以不一致的方式生成密钥。如果密钥不一致,服务可能无法识别重复的请求,从而导致意想不到的结果。
建立此最佳实践的好处:
-
提高了可扩展性:系统可以处理重试和重复的请求,而无需执行额外的逻辑或复杂的状态管理。
-
增强了可靠性:幂等性有助于服务以一致的方式处理多个相同的请求,从而降低意外副作用或重复记录的风险。这在分布式系统中尤其重要,在此类系统中,网络故障和重试很常见。
-
提高了数据一致性:由于同一个请求会产生相同的响应,因此幂等性有助于保持分布式系统间的数据一致性。这对于维护事务和操作的完整性至关重要。
-
错误处理:幂等性令牌使错误处理变得更加简单。如果客户端由于问题而未收到响应,则它可以使用相同的幂等性令牌安全地重新发送请求。
-
操作透明度:通过幂等性,可以更好地进行监控和日志记录。服务可以使用其幂等性令牌记录请求,这可以更轻松地跟踪和调试问题。
-
简化了 API 合约:它可以简化客户端和服务器端系统之间的合约,并减少对错误数据处理的担忧。
在未建立这种最佳实践的情况下暴露的风险等级:中
实施指导
在分布式系统中,至多(客户端仅发起一个请求)或至少(客户端持续发起请求直到确认成功)执行某项操作一次相对简单。然而,确切一次 实施此行为则具有挑战性。为了实现这一点,客户端应该为每个请求生成并提供幂等性令牌。
通过使用幂等性令牌,服务可以区分新请求和重复的请求。当服务收到带有幂等性令牌的请求时,它会检查该令牌是否已被使用。如果该令牌已被使用,则该服务会检索并返回存储的响应。如果令牌是新的,则服务会处理请求,将响应与令牌一起存储,然后返回响应。这种机制使所有响应都是幂等的,从而提高了分布式系统的可靠性和一致性。
幂等性也是事件驱动型架构的一项重要行为。这些架构通常由消息队列提供支持,例如 Amazon SQS、Amazon MQ、Amazon Kinesis Streams 或 Amazon Managed Streaming for Apache Kafka(MSK)。在某些情况下,只发布一次的消息可能会意外地传送多次。当发布者生成幂等性令牌并将其包含在消息中时,它要求对收到的任何重复消息的处理不会导致对同一消息执行重复的操作。使用者应跟踪收到的每个令牌,并忽略包含重复令牌的消息。
服务和使用者还应将收到的幂等性令牌传递给它调用的任何下游服务。处理链中的每个下游服务都同样负责确保实施幂等性,以避免多次处理消息的副作用。
实施步骤
-
确定幂等操作
确定哪些操作需要幂等性。这些操作通常包括 POST、PUT 和 DELETE HTTP 方法以及数据库插入、更新或删除操作。不变异状态的操作(例如只读查询)通常不需要幂等性,除非它们有副作用。
-
使用唯一标识符
在发送者发送的每个幂等操作请求中包含一个唯一的令牌,既可以直接在请求中,也可以作为其元数据的一部分(例如,HTTP 标头)。这可让接收者识别和处理重复的请求或操作。通常用于令牌的标识符包括 Universally Unique Identifiers (UUIDs)
和 K-Sortable Unique Identifiers (KSUIDs) 。 -
跟踪和管理状态
维护工作负载中每个操作或请求的状态。这可以通过将幂等性令牌和相应的状态(例如待处理、已完成或失败)存储在数据库、缓存或其它持久存储中来实现。此状态信息可让工作负载识别和处理重复的请求或操作。
如果需要,可通过使用适当的并发控制机制(例如锁定、事务或乐观并发控制)来保持一致性和原子性。这包括记录幂等令牌以及运行与为请求提供服务相关联的所有变异操作的过程。这有助于防止竞争条件并验证幂等操作是否正确运行。
定期从数据存储中移除旧的幂等性令牌来管理存储和性能。如果存储系统支持此操作,请考虑对数据使用过期时间戳(通常称为生存时间或 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 的版本控制功能对于维护幂等操作的状态特别有用。存储服务的选择通常取决于诸如因素,例如:与幂等性相关的数据量、所需的性能特征、对耐久性和可用性的需求,以及幂等性机制如何与整体工作负载架构集成。
-
-
实施幂等操作
将 API 和工作负载组件设计为幂等的。将幂等性检查纳入工作负载组件。在处理请求或执行操作之前,请检查是否已经处理了唯一标识符。如果已处理,则返回之前的结果,而不是再次执行该操作。例如,如果客户端发送一个创建用户的请求,请检查是否已存在具有相同唯一标识符的用户。如果该用户存在,则应返回现有用户信息,而不是创建新用户。同样,如果队列使用者收到带有重复幂等性令牌的消息,则该使用者应忽略该消息。
创建全面的测试套件来验证请求的幂等性。它们应涵盖各种各样的场景,例如成功的请求、失败的请求和重复的请求。
如果工作负载利用 AWS Lambda 函数,请考虑使用 Powertools for AWS Lambda。Powertools for AWS Lambda 是一个开发人员工具包,有助于在使用 AWS Lambda 函数时实施无服务器最佳实践并提高开发人员速度。特别是,它提供了一个实用程序,可将 Lambda 函数转换为可以安全重试的幂等操作。
-
清晰地传达幂等性
记录 API 和工作负载组件,以清晰地传达操作的幂等性质。这有助于客户了解预期行为以及如何可靠地与工作负载进行交互。
-
监控和审计
实施监控和审计机制,以检测与响应的幂等性相关的任何问题,例如意外的响应变化或过多的重复请求处理。这有助于您检测和调查工作负载中的任何问题或意外行为。
资源
相关最佳实践:
相关文档:
相关视频:
-
Building Distributed Applications with Event-driven Architecture - AWS Online Tech Talks
-
AWS re:Invent 2023 - Building next-generation applications with event-driven architecture
-
AWS re:Invent 2023 - Advanced integration patterns & trade-offs for loosely coupled systems
-
AWS re:Invent 2023 - Advanced event-driven patterns with Amazon EventBridge
-
AWS re:Invent 2019 - Moving to event-driven architectures (SVS308)
相关工具: