简体   繁体   English

如何在python中配置gRPC HTTP/2流控制

[英]How to configure gRPC HTTP/2 flow control in python

I have a gRPC server with the following proto:我有一个带有以下原型的 gRPC 服务器:

syntax = "proto3";

service MyServicer {
  rpc DoSomething(stream InputBigData) returns (stream OutputBigData) {}
}
message InputBigData {
    bytes data = 1;
}
message OutputBigData {
    bytes data = 1;
}

And my server is created with the following Python code:我的服务器是使用以下 Python 代码创建的:

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10),
                     options=[('grpc.max_receive_message_length', -1),
                              ('grpc.max_send_message_length', -1))])

max_receive_message_length and max_send_message_length are set to -1 to allow the transfer of big messages (typically 8Mb). max_receive_message_length 和 max_send_message_length 设置为 -1 以允许传输大消息(通常为 8Mb)。 The client also define the same options.客户端也定义了相同的选项。

Case 1: Consider the client sends to the server InputBigData at a higher rate than the server can afford.案例 1:考虑客户端以高于服务器可承受的速率向服务器发送 InputBigData。 How can I configure how many InputBigData (or bytes) can be queued in the input stream?如何配置可以在输入流中排队多少 InputBigData(或字节)?

Case 2: Consider the client reads the response OutputBigData from the server at a lower rate than the client can afford.情况 2:考虑客户端以低于客户端可承受的速率从服务器读取响应 OutputBigData。 How can I configure how many OutputBigData (or bytes) can be queued in the output stream?如何配置可以在输出流中排队多少个 OutputBigData(或字节)?

I know gRPC flow control is based on HTTP/2: https://httpwg.org/specs/rfc7540.html#FlowControl I tried to set grpc.http2.write_buffer_size at 67108864 (seems to be the max value) but nothing happened.我知道 gRPC 流量控制基于 HTTP/2: https ://httpwg.org/specs/rfc7540.html#FlowControl 我试图将 grpc.http2.write_buffer_size 设置为 67108864(似乎是最大值)但什么也没发生。

Here is an implementation which highlights the case 2:这是一个突出显示案例 2 的实现:

# server.py
from concurrent import futures

import grpc
import myservicer_pb2_grpc, myservicer_pb2


class MyServicer(myservicer_pb2_grpc.MyServicer):

    def DoSomething(self, request_iterator, target, **kwargs):
        big_data = b'0' * 1920*1080*4
        for r in request_iterator:
            print("server received input big data")
            yield myservicer_pb2.OutputBigData(data=big_data)
            print("server sent output big data")


if __name__ == '__main__':
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10),
                         options=[('grpc.max_receive_message_length', -1),
                                  ('grpc.max_send_message_length', -1)])
    myservicer_pb2_grpc.add_MyServicerServicer_to_server(
        MyServicer(), server)
    server.add_insecure_port("[::]:50051")
    server.start()
    server.wait_for_termination()

# client.py
import time
import grpc

import myservicer_pb2_grpc
import myservicer_pb2


def big_data_generator():
    big_data = b'0' * 1920*1080*4
    for i in range(100):
        yield myservicer_pb2.InputBigData(data=big_data)


def run():
    with grpc.insecure_channel('localhost:50051',
                               options=[('grpc.max_send_message_length', -1),
                                        ('grpc.max_receive_message_length', -1)]) as channel:
        stub = myservicer_pb2_grpc.MyServicerStub(channel)
        res = stub.DoSomething(big_data_generator())

        for r in res:
            print("Client received data")
            time.sleep(10)

if __name__ == '__main__':
    run()

After 10 seconds my server output is: 10 秒后,我的服务器输出为:

server received input big data
server sent output big data
server received input big data
server sent output big data
server received input big data

And my client output is:我的客户端输出是:

Client received data

My server received 3 InputBigData and sent 2 OutputBigData.我的服务器收到 3 个 InputBigData 并发送 2 个 OutputBigData。 It is now blocked until the client consumes the output data.它现在被阻塞,直到客户端使用输出数据。 In this scenario I want to increase (2 or 3 times) the output buffer size so it can continue to process more input data even if the client is late in consuming the result.在这种情况下,我想增加(2 或 3 倍)输出缓冲区大小,以便即使客户端延迟使用结果,它也可以继续处理更多输入数据。

Thanks for the detailed question.谢谢你的详细问题。 I tried your example, but still can't tune gRPC to increase its window size freely.我尝试了您的示例,但仍然无法调整 gRPC 以自由增加其窗口大小。

gRPC Channel arguments can be found here . gRPC 通道参数可以在这里找到。 The flow control implementation is here There are only several might affect flow-control, which are:流量控制实现在这里只有几个可能会影响流量控制,它们是:

  • grpc.http2.bdp_probe=0 : disables automatic window increase grpc.http2.bdp_probe=0 :禁用自动窗口增加
  • grpc.http2.max_frame_size : HTTP/2 max frame size grpc.http2.max_frame_size : HTTP/2 最大帧大小
  • grpc.http2.write_buffer_size : Not really a flow-control option, it is used for GRPC_WRITE_BUFFER_HINT (write without blocking). grpc.http2.write_buffer_size :不是真正的流量控制选项,它用于 GRPC_WRITE_BUFFER_HINT(无阻塞写入)。 Also, GRPC_WRITE_BUFFER_HINT is not supported yet in gRPC Python此外,gRPC Python 尚不支持 GRPC_WRITE_BUFFER_HINT

There is no argument that could trigger a window size update.没有参数可以触发窗口大小更新。 The default window size is 64KB.默认窗口大小为 64KB。 gRPC will increase the window size via BDP estimation. gRPC 将通过 BDP 估计增加窗口大小。 Eg, on my laptop, the client-outbound window size increased to 8380679 (~8MB).例如,在我的笔记本电脑上,客户端出站窗口大小增加到 8380679 (~8MB)。 But I yet to find a way to manually intervene this process.但是我还没有找到手动干预这个过程的方法。

So, unfortunately, you might need application-level buffering.因此,不幸的是,您可能需要应用程序级缓冲。 You could use coroutines in asyncio or threading with a thread-safe queue on both the client-side and server-side.您可以在异步或线程中使用协程,并在客户端和服务器端使用线程安全队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM