我已经实现了 2 个服务 A 和 B,其中 A 可以通过 gRPC(在 Mali 中使用 grpc-node)和纯 HTTP REST 调用与 B 对话。
请求大小可以忽略不计。
响应大小为 1000 个项目,如下所示:
{
"productId": "product-0",
"description": "some-text",
"price": {
"currency": "GBP",
"value": "12.99"
},
"createdAt": "2020-07-12T18:03:46.443Z"
}
A 和 B 都作为服务部署在 GKE 中,它们使用 kube-proxy 通过内部网络进行通信。
我发现 REST 版本比 gRPC 快很多。REST 调用的 p99 小于 1 秒,而 gRPC 的 p99 可以超过 30 秒。
细节
节点版本和操作系统:node:14.7.0-alpine3.12
依赖项:
"google-protobuf": "^3.12.4",
"grpc": "^1.24.3",
"mali": "^0.21.0",
我什至通过设置 gRPC 选项创建了客户端 TCP 池grpc.use_local_subchannel_pool=1
,但这似乎没有帮助。
问题似乎出在服务器端,正如我从日志中看到的那样,grpc lib 的call.startBatch
调用花费了很多秒来发送大小约为 51kb 的数据。这比 REST 版本慢得多。
我还检查了服务的 CPU 和网络是否健康。REST 版本可以发送 > 2mbps,而 gRPC 版本仅管理 ~150kbps。
在服务 B 上运行netstat
(在 gRPC 中)显示了许多 ESTABLISHED TCP 连接(正如预期的那样,因为 TCP 池)。
我怀疑 grpc-core C++ 代码在某种程度上不如 REST 最佳,但我没有证据。
有什么想法我接下来应该看看吗?感谢您的帮助
更新 1
以下是一些基准:
设置
Blazemeter --REST--> services A --gRPC/REST--> service B
- 请求正文(两个滞后)可以忽略不计
service A
是节点服务+Koaservice B
有3个选项:grpc-node
: 带有 grpc-node 的节点gRPC + Go
: 同一个 gRPC 服务的 Go 实现REST + Koa
: 带有 Koa 的节点
Blazemeter --> service A
:响应负载可以忽略不计,所有测试都相同serivce A --> service B
:gRPC/REST 响应负载为 1000 个ProductPrice
:
message ProductPrice {
string product_id = 1; // Hard coded to "product-x", x in [0 ... 999]
string description = 2; // Hard coded to random string, length = 10
Money price = 3;
google.protobuf.Timestamp created_at = 4; // Hard coded
}
message Money {
Currency currency = 1; // Hard coded to GBP
string value = 2; // Hard coded to "12.99"
}
enum Currency {
CURRENCY_UNKNOWN = 0;
GBP = 1;
}
这些服务在 GCP 中部署到 Kubernetes,
- 实例类型:
n1-highcpu-4
- 每个服务 5 个 pod
- 2 个 CPU,每个 pod 1 GB 内存
- kube-proxy 使用集群 IP(不通过互联网)(我也测试了 headless with
clusterIP: None
,得到了类似的结果)
加载
50rps
结果
使用 grpc-node 的服务 B
使用 Go gRPC 的服务 B
使用 REST 和 Koa 的服务 B
网络 IO
观察
gRPC + Go
REST
与(我认为 gRPC 会更快)大致相当grpc-node
比慢 4 倍REST
- 网络不是瓶颈