【问题标题】:Performance Issue: Async gRPC with Gunicorn + Tornado性能问题:使用 Gunicorn + Tornado 的异步 gRPC
【发布时间】:2020-10-17 00:51:34
【问题描述】:

背景:

我们正在尝试将 API 网关从 REST 迁移到 gRPC。 API 网关将由后端团队使用 REST 进行消费,并且从 API 网关到微服务的通信将使用 gRPC。我们的 API Gateway 使用 Tornado Python 框架Gunicorn 构建,并使用 tornado.curl_httpclient.CurlAsyncHTTPClient 为每个端点启用 Async / Future。每个端点都将使用 Unary 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_CALLSGRPC_ARG_KEEPALIVE_TIMEOUT_MS 选项。性能没有变化。
  3. 将 gRPC 服务器最大工作人员更改为 10000。结果:性能没有变化。
  4. 将 Gunicorn Worker 更改为 1。结果:性能没有变化。

我没试过的方式:

  1. 使用流 RPC

任何帮助都会显示出来。谢谢。

【问题讨论】:

    标签: performance tornado gunicorn grpc grpc-python


    【解决方案1】:

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

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

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

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

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

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

    为避免这种情况,您可以仅使用 gRPC Python API 的同步部分,也可以切换到专为解决此问题而设计的 AsyncIO bindings

    【讨论】:

    • 我有些困惑。我认为 Tornado 中的 future API 应该是协程,而不是线程。我错过了关键点吗?
    • 该问题涉及 gRPC Python,其未来的 API 使用 Tornado 期货。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多