性能问题:使用 Gunicorn + Tornado 的异步 gRPC

Kas*_*lie 5 performance tornado gunicorn grpc grpc-python

背景:

我们正在尝试将我们的 API 网关从 REST 迁移到 gRPC。API Gateway 将由 Backend Team 使用REST 使用,API Gateway 与微服务的通信将使用gRPC。我们的 API 网关使用Tornado Python 框架Gunicorn构建,并tornado.curl_httpclient.CurlAsyncHTTPClient用于为每个端点启用 Async/Future。每个端点将使用一元 RPC调用微服务,gRPC 存根将返回Future

因此,在完全迁移到 gRPC 之前,我们尝试比较 gRPC 与 REST 的性能。以下是您可能需要了解的详细信息:

  1. 我们有 3 个端点要测试。/0, /1, 和/2单个字符串负载。有效载荷大小为 100KB、1MB 和 4MB。这些消息在实例刚启动时就已经创建好了,所以端点只需要检索它。
  2. 每个端点的并发性 = 1、4、10。
  3. gRPC 线程池最大工人数 = 1 和 Gunicorn 的工人数 = 16。
  4. 我们使用 APIB 进行负载测试。
  5. 所有负载测试都是使用 GCP 虚拟机实例完成的。机器规格为:Intel Broadwell,n1-standard-1(1 个 vCPU,3.75 GB 内存),操作系统:Debian 9
  6. 代码共享相似的结构和相同的业务逻辑。

结果如下: 在此处输入图片说明

结论是并发性和负载大小越高,gRPC 变得越慢,最终比 REST 慢。

题:

  1. 与 REST 相比,gRPC 是否无法通过使用一元调用来处理大负载大小和大并发?
  2. 有没有办法让 gRPC 变得比 REST 更快?
  3. 我错过了什么根本原因吗?

这是我尝试过的几种方法:

  1. 来自 grpcio 的 GZIP 压缩。结果是它变得比以前慢。
  2. 在存根和服务器配置上使用GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLSGRPC_ARG_KEEPALIVE_TIMEOUT_MS选项。性能没有变化。
  3. 将 gRPC 服务器最大工作人员更改为10000. 结果:性能没有变化。
  4. 将 Gunicorn Worker 更改为1. 结果:性能没有变化。

我没试过的方法:

  1. 使用流 RPC

任何帮助是appareciated。谢谢你。

Ric*_*lle 0

与 REST 相比,gRPC 是否无法通过使用一元调用来处理大负载大小和大并发?

是的,gRPC Python 绑定在生产中用于快速处理高达数 GB 的请求。

有没有办法让 gRPC 变得比 REST 更快?

我相信你的问题很可能是这样的:

每个端点将使用 Unary RPC 调用微服务,并且 gRPC 存根将返回 Future。

每次您在 Python 绑定中使用未来的 API 时,都会创建一个新线程来服务该请求。如您所知,Python 有一个全局解释器锁,因此虽然一个进程可能有多个线程,但在任何时候只有一个线程可以访问 Python 对象。此外,争夺 GIL 的线程越多,同步导致的速度减慢就越严重。

为了避免这种情况,您可以仅使用 gRPC Python API 的同步部分,也可以切换到AsyncIO 绑定,它的设计正是为了解决这个问题。