You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步请求/响应模式:微服务环境下典型请求响应机制探究

嘿,刚接触微服务异步架构的话,你举的这个场景正好是非常典型的「同步请求入口+异步业务处理」的案例,我来给你拆解清楚这里面的运作逻辑和常见模式~

首先先把你描述的场景补全,核心矛盾点在于:Web 应用发起的是同步 HTTP 请求(需要拿到“是否成功完成”的响应),但后端微服务用的是异步事件驱动架构(Microservice A 只发事件不处理实际业务),所以关键是要解决「同步请求」和「异步处理」的衔接问题。

基础流程框架

先看最底层的事件流转逻辑,这是所有模式的基础:

  • Web 应用 → 发送 POST 请求到 /example/doStuff,携带业务参数(比如用户ID、操作内容等)
  • Microservice A 接收请求后做这几件事:
    1. 生成一个唯一的 requestId(比如 UUID),这个 ID 是贯穿整个请求链路的核心标记,所有后续事件、日志都要带上它
    2. 先做参数合法性校验,如果参数错了,直接返回同步错误响应(比如 400 Bad Request)
    3. 参数合法的话,向消息代理(比如 Kafka/RabbitMQ)发送 doStuffInitiated 事件,事件里必须包含 requestId、原始请求参数、超时时间等元数据
  • 后续微服务(比如 Microservice B/C/D)消费 doStuffInitiated 事件,各自处理子任务:
    • 比如 B 做数据校验、C 执行核心业务操作、D 更新统计数据
    • 每个服务完成任务后,发送对应的事件(比如 doStuffValidationPassed、doStuffCoreCompleted),同样带上 requestId
  • 最后需要一个协调者(可以是 Microservice A 本身,也可以是专门的编排服务)来监听所有子任务的完成事件:
    • 当所有子任务都成功完成 → 标记该 requestId 对应的请求为「成功」
    • 如果任一子任务失败 → 标记为「失败」,并记录失败原因

接下来针对 Web 应用需要的「是否成功完成」的响应,给你讲几种最常用的实现模式:


模式1:同步响应+后续主动查询(最通用,适合处理时间较长的场景)

这是异步架构里最常见的模式,因为 HTTP 请求通常有超时限制(比如 30s),如果 doStuff 处理需要几分钟甚至更久,不可能让请求一直挂着。

具体流程:

  1. Web 应用发 POST 请求到 Microservice A
  2. Microservice A 校验参数、发送事件后,立即返回 202 Accepted 响应,响应体示例:
    {
      "requestId": "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv",
      "status": "ACCEPTED",
      "message": "请求已接收,正在处理中",
      "statusQueryUrl": "/example/doStuff/status/{requestId}"
    }
    
  3. Web 应用拿到响应后,可以给用户提示「操作已提交,稍后查看结果」,然后定期调用 statusQueryUrl 接口查询状态
  4. 协调者更新 requestId 的状态后,查询接口就会返回对应的结果:
    • 成功时返回 200 OK + 结果数据
    • 失败时返回 500 Internal Server Error + 失败原因

关键注意点:

  • 一定要用 requestId 串联所有环节,方便跟踪排查问题
  • 状态数据可以存在 Redis(临时存储,过期自动清理)或者数据库(持久化存储)里,支持查询

模式2:长轮询/SSE(适合处理时间较短,需要快速拿到结果的场景)

如果 doStuff 的处理时间在几十秒内,Web 应用可以通过长轮询或 Server-Sent Events(SSE)来等待结果,不用频繁发起查询请求。

长轮询流程:

  1. Web 应用发 POST 请求时,在请求头里说明希望等待结果(比如 Prefer: wait=60,表示最多等 60s)
  2. Microservice A 发送事件后,不立即返回响应,而是把请求挂起,监听协调者的状态更新
  3. 一旦协调者标记请求为成功/失败,Microservice A 立即返回对应的响应(200 OK 表示成功,500 表示失败)
  4. 如果超过等待时间还没结果,返回 202 Accepted,让 Web 应用重新发起长轮询

SSE 流程:

  1. Web 应用先发 POST 请求拿到 requestId
  2. 接着建立 SSE 连接:GET /example/doStuff/events/{requestId}
  3. 当协调者更新状态时,Microservice A 通过 SSE 连接主动推送状态事件给 Web 应用
  4. Web 应用收到「SUCCESS」事件后,关闭连接并提示用户操作完成

关键注意点:

  • 长轮询/SSE 会占用服务器连接资源,不适合高并发场景
  • 必须设置超时时间,避免请求一直挂着消耗资源

模式3:回调通知(适合后端服务之间的调用场景)

如果发起请求的不是前端页面,而是另一个后端服务,可以用回调模式让后端主动通知结果:

  1. 请求方在 POST 请求里带上 callbackUrl 参数(比如 https://my-service.example.com/doStuff/callback)
  2. Microservice A 发送 doStuffInitiated 事件时,把 callbackUrl 和 requestId 一起放进事件元数据里
  3. 协调者完成所有子任务后,直接向 callbackUrl 发送 POST 请求,携带 requestId、状态和结果数据
  4. 请求方收到回调后,处理结果即可

关键注意点:

  • 要处理回调失败的情况,比如加重试机制,用死信队列存储失败的回调请求
  • 要验证回调的合法性(比如用签名),防止恶意请求

必踩的坑和注意事项

  • 幂等性:异步事件可能会被重复消费(比如消息代理重试),所以所有微服务的处理逻辑必须是幂等的。比如用 requestId 作为唯一键,重复处理同一个 requestId 的事件时,直接返回成功,不重复执行操作
  • 错误处理:如果某个子任务失败,要提前定义好重试规则(比如最多重试3次),超过次数后直接标记整个请求失败,并通知用户
  • 链路追踪:所有日志、事件都要带上 requestId,这样可以通过一个 ID 找到整个链路的所有日志,排查问题特别方便
  • 消息可靠性:消息代理要开启持久化和确认机制(比如 Kafka 的 ack 机制、RabbitMQ 的消息确认),防止事件丢失

内容的提问来源于stack exchange,提问作者wishiwasabigdataguy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:01:17