grpc-java双向流中流创建数量及相关技术问题咨询
gRPC-Java双向流场景下的流复用与流ID验证问题
代码上下文
StreamObserver<Response> responseStreamObserver1 = getResponseObserver(); StreamObserver<Response> responseStreamObserver2 = getResponseObserver(); StreamObserver<Request> streamClientSender1 = stub.sendRequest(responseStreamObserver1); StreamObserver<Request> streamClientSender2 = stub.sendRequest(responseStreamObserver2);
问题
- 当调用
streamClientSender1.onNext(request)时会创建一个流,再次调用该方法发送另一个请求时,只要流处于活跃状态(未达到最大连接时长),是否会复用同一个流? - 使用
streamClientSender1和streamClientSender2这两个不同的对象,在客户端调用onNext时是否会创建两个独立的流? - 是否有办法获取调用过程中创建的流的StreamID并打印,以此验证上述问题的答案?
已做验证
- 客户端使用同一个发送对象发送不同请求时,服务端使用同一个
responseObserver接收响应 - 客户端使用不同发送对象时,服务端会创建不同的
responseObserver接收响应
解答
流复用问题
是的,同一个StreamObserver<Request>对象(如streamClientSender1)对应单个双向流。只要该流处于活跃状态(未调用onCompleted()/onError(),且未触发gRPC的流超时、连接限制等终止条件),多次调用onNext()发送的请求都会复用这个已创建的流。双向流的核心设计就是支持在同一个流上双向传输多组请求-响应,无需每次发送都新建流。独立流的创建
是的,每调用一次stub的双向流方法(stub.sendRequest(...)),就会创建一个独立的双向流。streamClientSender1和streamClientSender2是两个完全独立的流发送器,分别对应两个互不干扰的gRPC流,各自的onNext()调用不会共享流资源。获取并打印StreamID
可以通过gRPC拦截器来获取并打印StreamID,客户端和服务端都支持:
- 服务端拦截器示例:
public class StreamIdLoggingInterceptor implements ServerInterceptor { private static final Attributes.Key<Long> STREAM_ID = Attributes.Key.create("stream-id"); @Override public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { Long streamId = call.getAttributes().get(STREAM_ID); System.out.println("当前请求对应的流ID: " + streamId); return next.startCall(call, headers); } }
将该拦截器注册到服务端,就能在每个请求到来时打印对应的流ID,以此验证流的复用和独立情况。
- 客户端拦截器:实现
ClientInterceptor,在interceptCall方法中通过ClientCall的getAttributes()获取STREAM_ID即可。
验证结果对应关系
你在服务端观察到的responseObserver对应关系完全正确——每个streamClientSender对象对应一个唯一的服务端responseObserver,本质原因就是每个发送对象对应一个独立的gRPC流。流与发送对象是一一对应的,复用发送对象就等同于复用对应的流。
内容的提问来源于stack exchange,提问作者djGowda
相关产品推荐
相关产品推荐

