performance - 性能问题:使用 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 的性能。以下是您可能需要知道的细节:
- 我们有 3 个端点要测试。
/0
,/1
, 和/2
单个字符串有效负载。有效负载大小为 100KB、1MB 和 4MB。这些消息在实例刚启动时已经创建,因此端点只需要检索它。 - 每个端点的并发 = 1、4、10。
- gRPC 线程池最大工人数 = 1 和 Gunicorn 的工人数 = 16。
- 我们使用 APIB 进行负载测试。
- 所有负载测试均使用 GCP VM 实例完成。机器规格为:Intel Broadwell,n1-standard-1(1 个 vCPU,3.75 GB 内存),操作系统:Debian 9
- 代码具有相似的结构和相同的业务逻辑。
结论是并发和有效负载大小越高,gRPC 变得越慢,最终比 REST 慢。
问题:
- 与 REST 相比,gRPC 是否无法通过使用一元调用来处理大负载大小和大并发?
- 反正有没有让 gRPC 变得比 REST 更快?
- 有什么我错过的根本原因吗?
这是我尝试过的几种方法:
- 来自 grpcio 的 GZIP 压缩。结果是它变得比以前慢。
- 在存根和服务器配置上使用
GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS
和选项。GRPC_ARG_KEEPALIVE_TIMEOUT_MS
性能没有变化。 - 将 gRPC 服务器最大工作人员更改为
10000
. 结果:性能没有变化。 - 将 Gunicorn Worker 更改为
1
. 结果:性能没有变化。
我没有尝试过的方式:
- 使用流 RPC
任何帮助都会显现。谢谢你。
解决方案
与 REST 相比,gRPC 是否无法通过使用一元调用来处理大负载大小和大并发?
是的,gRPC Python 绑定在生产中用于以速度处理高达数 GB 的请求。
反正有没有让 gRPC 变得比 REST 更快?
我相信您的问题可能是这样的:
每个端点都将使用一元 RPC 调用微服务,并且 gRPC 存根将返回 Future。
每次在 Python 绑定中使用未来 API 时,都会创建一个新线程来服务该请求。如你所知,Python 有一个全局解释器锁,所以虽然一个进程可能有很多线程,但任何时候只有一个线程可以访问 Python 对象。此外,在 GIL 上竞争的线程越多,由于同步而发生的减速就越多。
为避免这种情况,您可以仅使用 gRPC Python API 的同步部分,也可以切换到旨在解决此问题的AsyncIO 绑定。
推荐阅读
- spring-amqp - 如何使用spring AMQP创建兔子监听器来监听多个虚拟主机的队列
- cron - Google App Engine cron 作业计划在 DST 更改的日子里重复
- amazon-web-services - Terraform AWS API Gateway 策略参考自己的 ARN
- javascript - 获取函数的 this 绑定
- arrays - 如何展平自定义对象数组 [[CustomModel?]] 的数组?
- django - 使用 Django REST 框架后端托管 HTML+CSS+JS 网站
- c++ - 将应用程序从 32 位移植到 64 位的问题
- python - 将 CSV 转换为嵌套的 Json
- java - 当另一个类的变量发生变化时如何更新 JLabel 文本?
- javascript - 出现错误:'() => () => boolean' 类型的参数不可分配给'EffectCallback' 类型的参数