异步请求/响应模式:微服务环境下典型请求响应机制探究
嘿,刚接触微服务异步架构的话,你举的这个场景正好是非常典型的「同步请求入口+异步业务处理」的案例,我来给你拆解清楚这里面的运作逻辑和常见模式~
首先先把你描述的场景补全,核心矛盾点在于:Web 应用发起的是同步 HTTP 请求(需要拿到“是否成功完成”的响应),但后端微服务用的是异步事件驱动架构(Microservice A 只发事件不处理实际业务),所以关键是要解决「同步请求」和「异步处理」的衔接问题。
基础流程框架
先看最底层的事件流转逻辑,这是所有模式的基础:
- Web 应用 → 发送 POST 请求到
/example/doStuff,携带业务参数(比如用户ID、操作内容等) - Microservice A 接收请求后做这几件事:
- 生成一个唯一的
requestId(比如 UUID),这个 ID 是贯穿整个请求链路的核心标记,所有后续事件、日志都要带上它 - 先做参数合法性校验,如果参数错了,直接返回同步错误响应(比如 400 Bad Request)
- 参数合法的话,向消息代理(比如 Kafka/RabbitMQ)发送
doStuffInitiated事件,事件里必须包含requestId、原始请求参数、超时时间等元数据
- 生成一个唯一的
- 后续微服务(比如 Microservice B/C/D)消费
doStuffInitiated事件,各自处理子任务:- 比如 B 做数据校验、C 执行核心业务操作、D 更新统计数据
- 每个服务完成任务后,发送对应的事件(比如
doStuffValidationPassed、doStuffCoreCompleted),同样带上requestId
- 最后需要一个协调者(可以是 Microservice A 本身,也可以是专门的编排服务)来监听所有子任务的完成事件:
- 当所有子任务都成功完成 → 标记该
requestId对应的请求为「成功」 - 如果任一子任务失败 → 标记为「失败」,并记录失败原因
- 当所有子任务都成功完成 → 标记该
接下来针对 Web 应用需要的「是否成功完成」的响应,给你讲几种最常用的实现模式:
模式1:同步响应+后续主动查询(最通用,适合处理时间较长的场景)
这是异步架构里最常见的模式,因为 HTTP 请求通常有超时限制(比如 30s),如果 doStuff 处理需要几分钟甚至更久,不可能让请求一直挂着。
具体流程:
- Web 应用发 POST 请求到 Microservice A
- Microservice A 校验参数、发送事件后,立即返回 202 Accepted 响应,响应体示例:
{ "requestId": "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv", "status": "ACCEPTED", "message": "请求已接收,正在处理中", "statusQueryUrl": "/example/doStuff/status/{requestId}" } - Web 应用拿到响应后,可以给用户提示「操作已提交,稍后查看结果」,然后定期调用
statusQueryUrl接口查询状态 - 协调者更新
requestId的状态后,查询接口就会返回对应的结果:- 成功时返回 200 OK + 结果数据
- 失败时返回 500 Internal Server Error + 失败原因
关键注意点:
- 一定要用
requestId串联所有环节,方便跟踪排查问题 - 状态数据可以存在 Redis(临时存储,过期自动清理)或者数据库(持久化存储)里,支持查询
模式2:长轮询/SSE(适合处理时间较短,需要快速拿到结果的场景)
如果 doStuff 的处理时间在几十秒内,Web 应用可以通过长轮询或 Server-Sent Events(SSE)来等待结果,不用频繁发起查询请求。
长轮询流程:
- Web 应用发 POST 请求时,在请求头里说明希望等待结果(比如
Prefer: wait=60,表示最多等 60s) - Microservice A 发送事件后,不立即返回响应,而是把请求挂起,监听协调者的状态更新
- 一旦协调者标记请求为成功/失败,Microservice A 立即返回对应的响应(200 OK 表示成功,500 表示失败)
- 如果超过等待时间还没结果,返回 202 Accepted,让 Web 应用重新发起长轮询
SSE 流程:
- Web 应用先发 POST 请求拿到
requestId - 接着建立 SSE 连接:
GET /example/doStuff/events/{requestId} - 当协调者更新状态时,Microservice A 通过 SSE 连接主动推送状态事件给 Web 应用
- Web 应用收到「SUCCESS」事件后,关闭连接并提示用户操作完成
关键注意点:
- 长轮询/SSE 会占用服务器连接资源,不适合高并发场景
- 必须设置超时时间,避免请求一直挂着消耗资源
模式3:回调通知(适合后端服务之间的调用场景)
如果发起请求的不是前端页面,而是另一个后端服务,可以用回调模式让后端主动通知结果:
- 请求方在 POST 请求里带上
callbackUrl参数(比如https://my-service.example.com/doStuff/callback) - Microservice A 发送
doStuffInitiated事件时,把callbackUrl和requestId一起放进事件元数据里 - 协调者完成所有子任务后,直接向
callbackUrl发送 POST 请求,携带requestId、状态和结果数据 - 请求方收到回调后,处理结果即可
关键注意点:
- 要处理回调失败的情况,比如加重试机制,用死信队列存储失败的回调请求
- 要验证回调的合法性(比如用签名),防止恶意请求
必踩的坑和注意事项
- 幂等性:异步事件可能会被重复消费(比如消息代理重试),所以所有微服务的处理逻辑必须是幂等的。比如用
requestId作为唯一键,重复处理同一个requestId的事件时,直接返回成功,不重复执行操作 - 错误处理:如果某个子任务失败,要提前定义好重试规则(比如最多重试3次),超过次数后直接标记整个请求失败,并通知用户
- 链路追踪:所有日志、事件都要带上
requestId,这样可以通过一个 ID 找到整个链路的所有日志,排查问题特别方便 - 消息可靠性:消息代理要开启持久化和确认机制(比如 Kafka 的 ack 机制、RabbitMQ 的消息确认),防止事件丢失
内容的提问来源于stack exchange,提问作者wishiwasabigdataguy
相关产品推荐
相关产品推荐

