-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance implications of using the grpc-gateway for a REST API #1458
Comments
Hi Cyan, thanks for raising this issue! Performance measurements aren't something we've been great at, I think the assumption has mostly been that using well known patterns will give us the best performance, but if you'd like to dig into why you're seeing these numbers we'd be happy to make any changes you propose. Have you tried benchmarking the RegisterXXXHandlerFromService interface? That skips the gRPC roundtrip altogether and should be higher throughput, though it comes with other compromises. |
Where can I find 'RegisterXXXHandlerFromService" this interface? It doesn't exist in the *.pb.gw.go file |
Sorry, it will be something like this: func RegisterGreeterHandlerClient(ctx context.Context, mux *runtime.ServeMux, client GreeterClient) error { |
So it needs client, which means dialing to the gRPC server to initiate a gRPC client? If yes, then it's using the network layer again. So how does it skip the RoundTripping? Can you please look at the grpcweb-proxy implementation? They don't use network layer to proxy pass the HTTP request to gRPC request |
No, it depends on your generated types what it's called, but it expects the same interface that you use to register a server with gRPC. |
I've changed the code as you said: func (h *HttpRestTransport) Register(client link.LinkClient) error {
return link.RegisterLinkHandlerClient(context.Background(), h.gMux, client)
} No change, still the same poor performance:
|
Sorry, this is what I meant:
|
Perfect! Now it's upto the mark. I think the README or doc should explicitly mention this issues
|
Heck, no gRPC interceptors support with this method? :( @johanbrandhorst |
There's a comment warning of this when you use this method. It also doesn't support streaming right now. The reason there's no interceptor support is because it's not using gRPC at all. If you want interceptor functionality, you have to wrap the grpc-gateway mux in HTTP middleware. Eventually we hope to be able to support a grpc-in-process transport, which should help this sort of situation immensely, but that doesn't exist yet, see grpc/grpc-go#906. You can use third-party solutions mentioned in that thread though. |
Yeah I've seen the comment on code. And it's understandable too why it is like that. |
@johanbrandhorst Do we have interceptor functionality available now? If not can you please provide an example of the above method. |
See https://www.alexedwards.net/blog/making-and-using-middleware for the general Go HTTP middleware pattern. Because the |
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:
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:
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:
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
The text was updated successfully, but these errors were encountered: