grpc / grpc/grpc.io

Performance Best Practices

Open
#852 11 comments 1 reaction 0 assignees View on GitHub
Dominant language
HTML
Stars
479
Forks
545
Avg merge
2d 7h
Merged PRs (30d)
5

Description

The general section of https://grpc.io/docs/guides/performance/ led me to believe that to scale my application, I needed to use many gRPC channels and only one gRPC stream per channel between my long lived client and servers. This interpretation didn't match my understanding of a stream being a point-to-point path via 'sub-channels' from client to server and my understanding of a channel as a Y shaped collection of one sub-channel from client to each server. Nor does it match https://grpc.io/blog/grpc-on-http2/ which shows a single channel with many streams.

> **Streams**, however, cannot .... **They** also might increase performance at a small scale but can reduce scalability due to load balancing and complexity, so **they** should only be used when they provide substantial performance

I now **suspect** that the author is recommending the use of a 'Unary RPC' API such as
```
service MyUnaryService {
rpc myOperation(MyRequest) returns (MyResponse)
}
```
over a 'Streaming RPC' API where the both MyRequests and MyResponse are streamed
```
service MyStreamedService {
rpc myOperation(**stream** MyRequest) returns (**stream** MyResponse)
}
```
I find this confusing because the paragraph is headed with "Use streaming RPCs" for long lived connections. My original interpretation was that I should use streaming RPCs" for long lived connections but avoid using more than one 'Stream' on my 'Streaming RPC'. I interpreted the word "Streams" (plural) to be more than one instance of class io.grpc.internal.Stream, such as that created from pseudo code
```
myStub = MyStreamedServiceGrpc.newStub(myChannel);
myStream = myStub.myOperation(myResponseStreamObserver);
```
which to my knowledge
a) causes the client to use a new Stream (I see that class:io.grpc.internal.ClientCallIimpl method:startInternal invokes class:clientStreamProvider method:newStream)
and from my own recent reading elsewhere ...
b) the client must normally ensure that it does not create more than 100 'myStream' per channel.

I currently cache just one instance of myStream and invoke many times myStream.onNext(myRequest) but I now suspect that I may not need to use a Streaming RPC API at all, but that if I do, I should cache up to N instances of myStream ... where N is the number of servers and should be < 100 and that I should do my own load-balancing so that the load is shared over each myStream.

Am wondering therefore if the documentation should be updated to disambiguate between a 'streaming RPC API' and a GRPC stream such as io.grpc.internal.ClientStream. E.g. text "They also might increase performance " could be replaced with "Streaming RPC API also might increase performance".

Something like the following text would have been clearer to me;
Use keepalive pings ...(as is)
Use Unary RPCs for short or long lived connections unless the data based passed in each RPC is large or performance results show that Streaming RPCs are necessary to give the application more control over the underlying stream.
Use Streaming RPCs for long lived connections and the client is capable of creating multiple streams and providing its own load-balancing so that each Server is appropriately loaded. In future, the client will not longer need to do this ....

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.