简体   繁体   English

如何在 gRPC 中做服务端背压?

[英]How to do server-side backpressure in gRPC?

I just find that in C++, when using AsyncService, even if I don't request a new request, gRPC will still read data from the network.我只是发现在C++中,在使用AsyncService的时候,即使我没有请求新的请求,gRPC还是会从网络中读取数据。 This caused a huge memory usage in my system.这导致我的系统中大量使用 memory。

Detailed Scenario:详细场景:

I have a client that will send a lot of requests to the server.我有一个客户端会向服务器发送大量请求。

On the server-side, I didn't request any requests.在服务器端,我没有请求任何请求。 The server blocked in cq_->Next(&tag, &ok) but was kept consuming memory.服务器在cq_->Next(&tag, &ok)中阻塞,但一直在消耗 memory。 Caused an OOM in my system.导致我的系统出现 OOM。

So my question is how to prevent the server from reading data from the network when I don't request a new request?所以我的问题是,当我不请求新请求时,如何防止服务器从网络读取数据? ie how to do server-side backpressure so I can save the memory??即如何做服务器端背压,所以我可以保存 memory??

Could anyone help me?有人可以帮我吗? thanks!谢谢!

EDIT: Reproduce编辑:复制

I made a simple example for you to reproduce this problem, the code is based on the v1.46.3 tag of the official gRPC code base.我做了一个简单的例子给大家复现这个问题,代码基于gRPC官方代码库的v1.46.3标签。 I just modified the example to make the server don't request any requests and make the client send more requests.我只是修改了示例,使服务器不请求任何请求,并使客户端发送更多请求。 Check this commit for what I modified.检查此提交以了解我修改的内容。

  1. git clone -b v1.46.3_reproduce_oom --depth 1 https://github.com/lixin-wei/grpc.git && cd grpc
  2. git submodule update --init
  3. bazel build //examples/cpp/helloworld:all
  4. in one session, start server: ./bazel-bin/examples/cpp/helloworld/greeter_async_server在一个 session 中,启动服务器:./bazel-bin/examples/cpp/helloworld/ ./bazel-bin/examples/cpp/helloworld/greeter_async_server
  5. in aonther session, start client: ./bazel-bin/examples/cpp/helloworld/greeter_async_client2在另一个 session 中,启动客户端:./bazel-bin/examples/cpp/helloworld/ ./bazel-bin/examples/cpp/helloworld/greeter_async_client2
  6. keep running ps -aux | grep greeter_async_server继续运行ps -aux | grep greeter_async_server ps -aux | grep greeter_async_server , you'll notice an increasing memory usage in the server. ps -aux | grep greeter_async_server ,您会注意到服务器中 memory 的使用量在增加。

The server code is examples/cpp/helloworld/greeter_async_server.cc , the client code is examples/cpp/helloworld/greeter_async_client.cc .服务器代码是examples/cpp/helloworld/greeter_async_server.cc ,客户端代码是examples/cpp/helloworld/greeter_async_client.cc

One option is to use the ResourceQuota to restrict buffer memory usage across the server.一种选择是使用ResourceQuota来限制整个服务器的缓冲区 memory 使用。 The size you specify is not an absolute system memory limit, since not all memory in gRPC core/C++ is tracked, but it will result in a cap on the total memory usage.您指定的大小不是绝对的系统 memory 限制,因为并非 gRPC 核心/C++ 中的所有 memory 都被跟踪,但它会导致 ZCD69B4957F06CD818D7ZBF3D61980E291 的总使用量上限。

In the server, you can add:在服务器中,您可以添加:

    // Set a maximum memory cap
    grpc::ResourceQuota quota("greeter_callback_server");
    quota.Resize(30*1024*1024); // 30MB
    builder.SetResourceQuota(quota);

And after a memory cap is reached, adding the error code to the client output, the clients will see something like在达到 memory 上限后,将错误代码添加到客户端 output,客户端将看到类似

RPC failed with: Received RST_STREAM with error code 11

On my system, this happens when the server processes reach ~140MB RES memory.在我的系统上,当服务器进程达到 ~140MB RES memory 时会发生这种情况。


Edit : another option is to set the maximum number of concurrent streams that the server is willing to accept using the GRPC_ARG_MAX_CONCURRENT_STREAMS channel argument.编辑:另一个选项是使用GRPC_ARG_MAX_CONCURRENT_STREAMS通道参数设置服务器愿意接受的最大并发流数。 Each unary call is a separate RPC, and handled as a separate stream.每个一元调用都是一个单独的 RPC,并作为单独的 stream 处理。

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

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