Performance implications of using the grpc-gateway for a REST API #1458
Description
Hi, I'm using the grpc-gateway "runtime" package to expose REST endpoint from proto buffers.
When I deployed to production, I observed very poor performance, something like 400 req/s.
So I started benchmarking in localhost using "bombardier" as benchmarking tool. Here's the result:
Bombarding http://localhost:5400/v1/link/ping with 1000000 request(s) using 100 connection(s)
1000000 / 1000000 [===============] 100.00% 58s
Done!
Statistics Avg Stdev Max
Reqs/sec 17102.51 1810.68 25905.78
Latency 5.85ms 1.00ms 59.33ms
HTTP codes:
1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 6.31MB/s
No database or I/O calls, just ping response by calling the service layer function. Still the throughput is very low.
So I wrote my custom HTTP endpoint that will call the same service layer functions that the gRPC function is using. And now look at the benchmark:
Bombarding http://localhost:5400/v1/link/ping with 1000000 request(s) using 100 connection(s)
1000000 / 1000000 [=============] 100.00% 7s
Done!
Statistics Avg Stdev Max
Reqs/sec 147464.89 22618.44 190638.47
Latency 677.75us 551.27us 48.33ms
HTTP codes:
1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 35.51MB/s%
Boom! 6x faster than using the grpc-gateway "runtime" package.
I went further down into the rabbit hole. the grpc gateway runtime package has a http mux frontend that receives request from HTTP client and then calls the grpc server as a client.
So I try to simulate it manually. In my code, instead of calling the service layer function from the HTTP endpoint handler, I call the grpc server as a client.
And now the benchmark looks like this:
Bombarding http://localhost:5400/v1/link/ping with 1000000 request(s) using 100 connection(s)
1000000 / 1000000 [==================] 100.00% 28s
Done!
Statistics Avg Stdev Max
Reqs/sec 35193.17 3242.29 46530.99
Latency 2.84ms 459.67us 53.38ms
HTTP codes:
1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 8.59MB/s%
Still not great, but its 2x better (35k req/s) than grpc gateway runtime (17k req/s)
So, gRPC gateway uses this flow:
HTTP Request -> REST Handler gRPC Client -> Call gRPC Server -> Returns response to the REST Handler gRPC Client -> Returns to the original caller
It looks like this is not the most efficient way to put a REST frontend before the gRPC server.
Anyway, I think you guys should take a look at this issue. Or maybe I'm doing something wrong