用消息队列做 RPC:请求怎么告诉服务端“把结果发到哪”,多个请求并发时怎么把响应对回去?回复队列怎么建才不拖慢?服务端挂了怎么办?这篇逐项在线上和延迟上量一遍。
客户端声明了独占队列 amq.gen-…(服务器生成的名字,前缀 amq.gen-);请求 correlation_id = 1e550c17…;收到响应 'resp:ping',correlation_id 是否一致: True;往返 0.5 ms C→S ch1 Basic.Publish 26 字节 C→S ch1 ContentHeader 90 字节 S→C ch1 Basic.Deliver 92 字节 S→C ch1 ContentHeader 59 字节
请求带 reply_to(回复队列名)和 correlation_id(唯一标识)。服务端把响应发到默认 exchange、routing key=reply_to,并带回同一个 correlation_id。
请求发送顺序: req-0 .. req-5;响应到达顺序: ['req-0', 'req-2', 'req-3', 'req-4', 'req-5', 'req-1'];每个响应的 correlation_id 都能对回自己的请求: True
多个请求并发时响应可能乱序到达(服务端实例的速度不同),只有 correlation_id 能把响应对回请求。
(a) 每次新建独占队列 p50 3.317 ms,p99 5.261 ms,292 次/秒 (b) 复用独占回复队列 p50 0.257 ms,p99 0.459 ms,3738 次/秒 (c) direct reply-to p50 0.237 ms,p99 0.369 ms,4043 次/秒
为每个请求新建回复队列最慢(p50 3.317 ms),复用一个回复队列(0.257 ms)和 direct reply-to(0.237 ms)快一个数量级。
没有服务端,客户端等了 3 秒,收到回复: 0 条 发了两个请求:一个没有 expiration、一个 expiration=1000 ms。3.5 秒后 rpc_queue 里剩 2 条(没有 expiration 的那条当然还在;带 expiration 的那条排在它后面,出不了队头,也没有被丢掉——这就是第 11 篇的队头阻塞)
RPC 没有天然的超时,客户端要自己设;请求的 expiration 受队头阻塞影响,不是一个可靠的清理手段。