【问题标题】:JAVA GRPC server side stream keeps increasing max-inbound-message-sizeJAVA GRPC 服务器端流不断增加 max-inbound-message-size
【发布时间】:2020-05-31 12:47:03
【问题描述】:

使用 GRPC 流式传输大量数据的最佳做法是什么? 我正在向将流回数据的 GRPC 服务器发送请求。发回的数据可以是大约 100 条 protobuf 消息,也可以是一对 100.000 条 protobuf 消息。

service CrossEngineSelector {
    rpc QueryDB (QueryRequest) returns (stream QueryResponse) {}
}

服务器是发送 protobuf 消息的简单实现。

@Override
public void queryBD(QueryRequest request, StreamObserver<QueryResponse> responseObserver) {

      Iterables.partition( dataLoader.getData(), 1000).forEach(batch -> {
          responseObserver.onNext(QueryResponse.newBuilder().addAllRows(batch).build());
      });
      responseObserver.onCompleted();
}

客户端使用blockingStub调用该方法(protobuf生成代码):

public Iterator<QueryResponse> queryDB(QueryRequest request) {
            return ClientCalls.blockingServerStreamingCall(this.getChannel(),
                   CrossEngineSelectorGrpc.getQueryEnginesMethod(),
                   this.getCallOptions(), request);
}

一旦客户端调用此方法,我只需遍历 QueryResponse。

所有这些都适用于只发回少量消息的流。一旦我尝试流式传输 100.000 条消息,max-inbound-message-size 会不断增加,最终会出现错误:RESOURCE_EXHAUSTED: Compressed gRPC message exceeds maximum size 4194304: 4196022 bytes read

我目前的解决方法是将 max-inbound-message-size 设置得非常高 +1Gb。这是一个硬编码的值,所以它不会缩放。客户端不知道服务器将返回多少条消息。我可能会遇到一些用例,即使 1Gb max-inbound-message-size 也不够用。

我希望我犯了一个实施错误。我希望有一种方法可以重置来自服务器的每个流 (onNext()) 的消息大小,或者它不断增加消息大小是否正常?

我假设单个 responseObserver.onNext(QueryResponse.newBuilder().addAllRows(batch).build()); 发送了几个 Mb,并且只要它运行,这将被视为消息大小而不是整个流。

我将 Micronaut 用于服务器和客户端。

【问题讨论】:

    标签: java grpc micronaut grpc-java


    【解决方案1】:

    maxInboundMessageSize 用于在恶意对等方发送非常大的有效载荷进行攻击时保护接收方内存不足。 这里真正的问题是 1000 个块可能大于 4MB(默认 maxInboundMessageSize)。

    您可以通过两种方式解决此问题,

    • 修复发送方以限制负载的大小,而不是行数。
    • 或者,接收方有足够大的maxInboundMessageSize 来处理正常的 1000 行数据。

    后一种方法本质上是您实现的。它应该低于 1GB+。 gRPC 不会使用我上面提到的maxInboundMessageSize 内存量,这纯粹是为了保护。 (稍后添加)

    【讨论】:

    • 这确实是我期望它工作的方式。但是,从我的测试来看,它似乎将整个流大小作为最大大小。示例:在 1 Mb 块中流式传输 10 Mb 将在第 4 个流之后导致错误,除非您将 max-inbound-message-size 设置为 10Mb 在我的情况下,我总是可以流式传输大约 8500 行,然后它会崩溃 io.grpc.StatusRuntimeException: RESOURCE_EXHAUSTED: gRPC message exceeds maximum size 4194304: 4335181
    • grpc 从每个 http2 帧的头部检查帧大小(参见 MessageDeframer#processHeader)。因此,如果您可以创建一个最小的复制品,这与发生的情况不同(我希望 =p),我们绝对可以看看。
    • 谢谢@creamsoup,再次检查所有代码后,我发现服务器端出现错误,每次迭代都会增加protobuf消息。一切都按预期工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 2020-07-22
    相关资源
    最近更新 更多