如何设计高效的幂等性 API

幂等性API意味着无论使用相同的请求体/参数成功调用该API多少次,数据/系统状态都将是相同的。

在本文中,我们将提出一种同样关注 API 性能的幂等性机制。

实现幂等 API 是建立安全重试机制的解决方案之一,确保提供健壮的 API 和弹性系统。

传统的幂等性 API 仅依赖于数据库 (DB) 来验证请求是否已被先前处理,这对数据库来说是额外的工作负载,可能会导致 API 性能不佳。
从常见的重试场景来看,大多是请求超时后的重试,或者异步消息消费者发起的重试等。大多数重试往往发生在较短的时间内。

因此,我们建议放置一个额外的内存缓存服务器(例如Redis)来通过缓存这些数据来帮助优化机制,从而提高其效率。

流程如下:
1、请求rid
调用幂等性 API 时,必须提供唯一的request-id(或rid),通常是时间戳、用户 ID 和随机数的组合。
rid存在于缓存中初始服务器操作涉及检查缓存中是否存在,以便根据其存在或不存在来确定后续流。

2、当缓存不存在时

  • 初始化缓存rid:如果不存在缓存,第一步是创建一个is-done属性设置为 的缓存false。此操作应在与 D1 相同的事务中进行,以防止竞争条件,可能使用setIfAbsentJava Redis 客户端或setnxRedis 中的方法。
  • rid存在于DB中那么在我们真正处理请求之前,我们仍然需要检查该请求之前是否已经进行过,以防止重复。
  • 执行原始API流程在没有缓存或DB记录的情况下,应执行原始流程来处理请求。
  • 处理是否成功处理请求时,根据处理结果触发不同的反应。成功执行会导致缓存更新并响应调用者。否则,需要进行详细的错误检查来决定下一步做什么。
  • 错误是否可重试正确的异常处理对于将错误分类为可重试或不可重试至关重要。可重试错误包括第 3 方 API 或其他数据源、文件系统等的网络错误。不可重试错误,例如验证错误、服务器内部错误等,需要修改代码或调整设置才能成功重试。
  • 更新缓存获得明确结果(成功或不可重试的错误)后,将使用实际响应和设置来更新缓存。is-donetrue
  • 删除缓存对于可重试的错误,应删除缓存,以预期重试请求的处理。
  • 返回响应无论流程结果如何,响应调用者都是必不可少的。

3、当缓存存在时

  • 完成检索:缓存值并检查is-done在 Subflow1 期间设置或更新的属性。
  • 返回缓存的响应:如果is-done缓存中的属性为ture,则表示之前已完成请求,立即返回缓存的响应。
  • 返回进程内错误:如果is-done缓存中的属性为false,则表示请求正在执行,为了防止竞争条件或其他一些多线程问题,我们应该返回一个错误代码,以通知调用者该请求正在进行中,建议稍后再试。

概括
本文介绍了一种与缓存服务器配合提高性能的幂等机制。以下是实施过程中需要考虑的一些关键点:

  1. 唯一请求标识符 ( rid):客户端必须在其请求中包含一个rid,以确保它足够独特以唯一地标识每个请求。
  2. 放置在身份验证过滤器之后:出于安全考虑,幂等性流应放置在身份验证过滤器之后。
  3. 原子缓存操作:检查缓存是否存在并创建缓存条目应以原子方式进行,以确保一致性。
  4. 针对不存在的缓存的数据库集成:尽管利用了缓存,但该机制需要数据库在缓存不存在时进行存在性检查。
  5. 附加属性的利用:将补充属性(例如 is-done)合并到缓存值中以表示请求的处理状态。
  6. 异常处理可重试性:定义请求处理期间遇到的每个异常的可重试性,有助于做出有关缓存更新或删除的决策。


参考