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

标签 python grpc http2 grpc-python

我有一个具有以下原型(prototype)的 gRPC 服务器:

syntax = "proto3";

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

我的服务器是使用以下 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 和 max_send_message_length 设置为 -1 以允许传输大消息(通常为 8Mb)。客户端也定义相同的选项。

情况 1:考虑客户端以高于服务器承受能力的速率向服务器发送 InputBigData。如何配置可以在输入流中排队的InputBigData(或字节)数量?

情况 2:考虑客户端以低于客户端可承受的速率从服务器读取响应 OutputBigData。如何配置可以在输出流中排队的 OutputBigData(或字节)数量?

我知道gRPC流量控制是基于HTTP/2的:https://httpwg.org/specs/rfc7540.html#FlowControl 我尝试将 grpc.http2.write_buffer_size 设置为 67108864(似乎是最大值),但没有任何反应。

下面是突出显示案例 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()

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

我的客户端输出是:

Client received data

我的服务器接收了 3 个 InputBigData 并发送了 2 个 OutputBigData。现在它被阻塞,直到客户端消耗输出数据。在这种情况下,我想增加(2 或 3 倍)输出缓冲区大小,以便即使客户端延迟使用结果,它也可以继续处理更多输入数据。

最佳答案

感谢您提出详细的问题。我尝试了你的示例,但仍然无法调整 gRPC 以自由地增加其窗口大小。

可以找到 gRPC channel 参数 here 。流量控制实现是here只有几个可能影响流量控制,它们是:

  • grpc.http2.bdp_probe=0:禁用自动窗口增大
  • grpc.http2.max_frame_size:HTTP/2 最大帧大小
  • grpc.http2.write_buffer_size:并不是真正的流量控制选项,它用于 GRPC_WRITE_BUFFER_HINT(无阻塞写入)。此外,gRPC Python 尚不支持 GRPC_WRITE_BUFFER_HINT

没有任何参数可以触发窗口大小更新。默认窗口大小为 64KB。 gRPC 将通过 BDP 估计来增加窗口大小。例如,在我的笔记本电脑上,客户端出站窗口大小增加到 8380679 (~8MB)。但我还没有找到手动干预这个过程的方法。

因此,不幸的是,您可能需要应用程序级缓冲。您可以在异步中使用协程,或者在客户端和服务器端使用带有线程安全队列的线程。

关于python - 如何在python中配置gRPC HTTP/2流量控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64050027/

相关文章:

python - 'zpopmax' 可以与 redis-py-cluster 一起使用吗?

c# - 如何在 grpc 中返回 list<model>

http - 与 HTTP/1.1 相比,HTTP/2 如何提供更快的浏览速度?

python - 我可以用 Nose 嵌套测试用例吗?

Python - 从另一个类调用函数

testing - 我如何模拟或模拟 gRPC API?

c++ - grpc & protobuf -- 错误:std::result_of<> 中没有名为 'type' 的类型

HTTP 1.1 到 HTTP/2 : what about headers?

apache - 尽管发送了 "Upgrade" header ,但浏览器不会升级到 h2 (HTTP/2)

python - CI 与 Jenkins : restart python bjoern server with Jenkins shell script