首页 > 解决方案 > 性能问题:使用 Gunicorn + Tornado 的异步 gRPC

问题描述

背景:

我们正在尝试将 API 网关从 REST 迁移到 gRPC。API Gateway 将由后端团队使用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 VM 实例完成。机器规格为: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_CALLS和选项。GRPC_ARG_KEEPALIVE_TIMEOUT_MS性能没有变化。
  3. 将 gRPC 服务器最大工作人员更改为10000. 结果:性能没有变化。
  4. 将 Gunicorn Worker 更改为1. 结果:性能没有变化。

我没有尝试过的方式:

  1. 使用流 RPC

任何帮助都会显现。谢谢你。

标签: performancetornadogunicorngrpcgrpc-python

解决方案


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

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

反正有没有让 gRPC 变得比 REST 更快?

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

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

每次在 Python 绑定中使用未来 API 时,都会创建一个新线程来服务该请求。如你所知,Python 有一个全局解释器锁,所以虽然一个进程可能有很多线程,但任何时候只有一个线程可以访问 Python 对象。此外,在 GIL 上竞争的线程越多,由于同步而发生的减速就越多。

为避免这种情况,您可以仅使用 gRPC Python API 的同步部分,也可以切换到旨在解决此问题的AsyncIO 绑定。


推荐阅读