Asynchronous Request-Reply pattern - Azure Architecture Center | Microsoft Learn
把后台处理和前端解耦,后台处理需要异步处理,但是也需要给前端一个清晰的回应。
背景和问题
- 在现代应用开发中,代码通常在浏览器中运行,依赖于远程API接口提供的业务逻辑和功能。这些API直接与应用程序有关,或者是第三方提供的共享服务。通常这些API调用通过HTTP(S)协议调用,并且遵循REST语义。
- 大多情况下,客户端应用程序的API被设计为快速响应,100ms甚至更少。许多因素会造成响应延迟,包括:
- 应用的主机堆栈
- 安全组件
- 调用者和后台的相对物理位置
- 网络基础设施
- 当前负荷
- 请求有效负荷大小
- 处理队列长度
- 后台处理时间
- 任何一个因素都可以增加系统延迟。有一些可以通过扩展后台来缓解。其他的例如网络设施,已经超出了应用程序开发者的控制。大部分API可以很快的响应,以便通过同一连接返回。程序代码可以通过非阻塞的方式制作一个异步API请求,提供异步处理外观,这被推荐在IO操作上使用。
- 有时候,后台完成需要很长时间运行,在秒级之上,甚至可能需要执行几分钟或者几个小时。这种情况下,让请求等待完成响应是不可行的。这是任何同步请求-应答模式的潜在问题。
- 一些架构解决这个问题通过使用消息中间件来分开请求和响应阶段。这种分离通常使用Queue-Based Load Leveling pattern实现。这种分离可以允许客户端进程和后台API独立扩展。但是这种分离也带来了额外的复杂性,当客户端需要成功的通知,这一步需要是异步的。
- 针对客户机应用程序讨论的许多相同注意事项,也适用于分布式系统中的服务器到服务器REST API调用,例如,在微服务体系结构中。
解决办法
- 这个问题的一个思路是使用HTTP轮询,轮询是在客户端代码使用,因为很难提供回调端点或使用长时间运行的连接。尽管回调可能能做到,但是需要额外的库和服务有时也会增加额外的复杂性。
- 客户端程序调用一个同步请求API,触发了后台上长时间运行的操作。
- API同步尽可能的快速响应。返回一个HTTP202(已接收)的状态码,确认这个请求已经被接收处理。
- 在开始长时间运行操作前,API应该校验请求和执行动作。如果请求是无效的,立即回应错误代码例如HTTP400(错误请求)。
- 响应持有本地引用指向终端,所以客户端可以轮询检查长时间运行操作的结果。
- API将处理工作转移给另一个组件,比如消息队列。
- 对于每个成功请求,状态终端会返回HTPP200。当工作还在待处理时,状态终端返回一个资源,表明工作还在处理中。一旦工作完成,状态终端要么返回一个表明完成的资源,要么跳转去另一个资源URL。例如,如果异步操作创建了一个新资源,状态终端会跳转到该资源的URL。
- 下面的图表展示了一个典型的流程:
问题和考虑
- 有许多可能的方法可以通过HTTP实现此模式,但并不是所有的上游服务都具有相同的语义。例如,当远程请求尚未完成时,大多数服务不会从GET方法返回HTTP 202响应。遵循纯REST语义,它们应该返回HTTP 404(未找到)。当您考虑到调用的结果尚未出现时,此响应是有意义的。
- HTTP 202响应应该指明客户端应该轮询响应的位置和频率。它应该有以下额外的响应头:
- Location : 客户端应该轮询响应状态的URL。
- Retry-After:对处理完成时间的估计。
- 根据所使用的底层服务,您可能需要使用处理代理或facade来操作响应头或有效负载。
- 如果状态端点在完成时重定向,则HTTP 302或HTTP 303是适当的返回码,具体取决于您支持的确切语义。
- 成功处理后,Location标头指定的资源应该返回适当的HTTP响应代码,例如200 (OK)、201(创建)或204(无内容)。
- 如果在处理过程中发生错误,将错误保存在Location标头中描述的资源URL中,并理想地从该资源向客户端返回适当的响应代码(4xx代码)。
- 并不是所有的解决方案都以同样的方式实现这个模式,有些服务将包含额外的或备用的头。例如,Azure资源管理器使用此模式的修改版本。详情查看:https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations。
- 历史客户端不一定支持这个模式。在这种情况下,您可能需要在异步API上放置一个facade,以便对原始客户机隐藏异步处理。例如,Azure逻辑应用程序原生支持这种模式,可以用作异步API和进行同步调用的客户端之间的集成层。详情查看:https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-create-api-app#perform-long-running-tasks-with-the-webhook-action-pattern。
- 在有些场景下,你可能想要提供一个客户端可以取消长时间运行请求的方式。这样的话,后台服务必须支持某种形式的取消指令。
什么时候使用
- 客户端代码(例如浏览器应用)这些难以提供回调的终端,或者使用长连接增加了很多的额外的复杂性。
- 只允许HTTP协议调用服务,并且因为客户端的防火墙限制导致服务不可以回调。
- 服务调用需要适配不支持回调技术的遗留架构,例如WebSockets or webhooks。
不适用
- 你可以使用为异步通知构建的服务,例如Azure Event Grid。
- 响应必须实时返回给客户端。
- 客户端需要收集很多结果,这些结果的接收延迟很重要。可以考虑使用服务总线模式。
- 网络设计允许你开启端口来接收异步回调或webhook。
欢迎大家留言沟通