Search code examples
grpcnettyokhttp

Can I use okhttp of grpc in non-android case because it have better performance?


I check the grpc issue 8002 and find okhttp have better performance. So why don't we just use okhttp instead of netty in all java applications?

BTW,as we know, netty use nio to get high performance, and okhttp use block I/O. It is strange that how okhttp can get better performance than netty.


Solution

  • OkHttp is not encouraged for all applications. In one specific metric it is significantly faster (issue 6696; very many tiny messages back-to-back in a single stream), but that doesn't mean it is faster in other metrics.

    "performance" also doesn't just mean "faster." Since OkHttp uses blocking I/O, it will use significantly more memory for Thread stacks. If your workload is low-scale in terms of number of connections, then OkHttp is a fine choice. But as your system scales to creating 100s or 1000s of connections, Netty becomes a significantly better choice.

    There are generally few streaming RPC services, and generally they don't send tons of very small messages. Instead of changing to OkHttp for everything because of a small number of cases, it is generally better to stay with Netty and, if impacted:

    1. Reduce the number of tiny messages by combining multiple messages together using a repeated field, or
    2. Use the workaround mentioned in the issue:
    // If client is receiving many small messages (This will not work for the blocking iterator stub)
    public class MorePipeliningClientInterceptor implements ClientInterceptor {
      @Override
      public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
          CallOptions callOptions, Channel next) {
        return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
          @Override
          public void start(Listener<RespT> responseListener, Metadata headers) {
            super.start(responseListener, headers);
            super.request(5);
          }
        };
      }
    }
    
    stub = stub.withInterceptors(new MorePipeliningClientInterceptor());
    
    // If server is receiving many small messages
    public StreamObserver<Request> someMethod(StreamObserver<Response> observer) {
      ServerCallStreamObserver<Response> serverCallObserver = (ServerCallStreamObserver<Response>) observer;
      serverCallObserver.request(5);
      ...
    }