grpc 客户端启动及调用流程简单分析

grpc分层设计

在这里插入图片描述
按照grpc的分层设计,结合源码,分析grpc客户端启动和调用流程。

grpc的ManagedChannel创建

ManagedChannel 是对 Transport 层 SocketChannel 的抽象,Transport 层负责协议消息的序列化和反序列化,以及协议消息的发送和读取。

ManagedChannel 将处理后的请求和响应传递给与之相关联的 ClientCall 进行上层处理,同时,ManagedChannel 提供了对 Channel 的生命周期管理(链路创建、空闲、关闭等)。
创建代码如下:

ManagedChannel channel = ManagedChannelBuilder
               .forAddress(server.getHost(), server.getPort())
               .defaultLoadBalancingPolicy("round_robin")
               .nameResolverFactory(new DnsNameResolverProvider())
               .idleTimeout(30, TimeUnit.SECONDS)
               .usePlaintext().build();

a、 forAddress()
这个方法中主要是设置默认的provider和绑定服务端,这里并没有去连接服务端,只是根据host和port拼接String字符串,并返回NettyChannelBuilder 对象
b、 usePlaintext()
不会再去尝试升级http1
a、 build()
channel是利用反射进行创建的,默认基于epoll,如果没有找到对应的类,则创建nio对应的channel
buildTransportFactory(): 新建NettyChannelBuilder.NettyTransportFactory对象,NettyTransportFactory主要用来创建NettyClientTransport对象。

ManagedChannelBuilder NettyChannelBuilder NettyTransportFactory ManagedChannelImpl forAddress 创建NettyTransportFactory实例 创建ManagedChannelImpl对象 ManagedChannelBuilder NettyChannelBuilder NettyTransportFactory ManagedChannelImpl

stub

定义的.proto文件中生成的代码中会生成对应的stub
根据build()中返回的channel和需要创建对应的stub,生成的代码中默认提供了newStub(channel),newBlockingStub(channel),newFutureStub(channel) 三种stub。
newStub(channel): 创建异步stub支持所有类型的service调用
newBlockingStub(channel): 创建一个阻塞的stub,支持一元的和输出流的service调用
newFutureStub(channel): 创建一个listener future的stub,支持一元的和输出流的service调用

简单demo进行测试,分别使用50,100,200并发。持续5分钟,
测试机器为4核8g的windows系统
50线程并发5分钟测试结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

100线程并发5分钟测试结果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

200线程并发5分钟测试结果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

ClientCall

客户端直接调用.proto生成的代码

   @java.lang.Override
    public io.grpc.stub.StreamObserver<com.why.grpc.OptionServiceOuterClass.OrdersQuery> query(
        io.grpc.stub.StreamObserver<com.why.grpc.OptionServiceOuterClass.OrdersAck> responseObserver) {
      return asyncBidiStreamingCall(
          getChannel().newCall(METHOD_QUERY, getCallOptions()), responseObserver);
    }

getChannel(): 这里会获取创建stub时传入的channel,上面build()创建的channel类型为ManagedChannelOrphanWrapper( extends ForwardingManagedChannel --> extends ManagedChannel -->> extends Channel)
newCall:根据channel的类型,调用ForwardingManagedChannel 中的方法,interceptorChannel的类型为ClientInterceptors类型,下面就会进入ClientInterceptors的newCall方法

ForwardingManagedChannel ------------------->
 this.interceptorChannel = ClientInterceptors.intercept(channel, interceptors);
  @Override
  public <RequestT, ResponseT> ClientCall<RequestT, ResponseT> newCall(
      MethodDescriptor<RequestT, ResponseT> methodDescriptor, CallOptions callOptions) {
    return delegate.newCall(methodDescriptor, callOptions);
  }

在build创建ManagedChannelOrphanWrapper时的代码如下,可知delegate时ManagedChannelImpl的类型,代码会进入到ManagedChannelImpl的方法中

AbstractManagedChannelImplBuilder ---->>
  @Override
  public ManagedChannel build() {
    return new ManagedChannelOrphanWrapper(new ManagedChannelImpl(
        this,
        buildTransportFactory(),
        // TODO(carl-mastrangelo): Allow clients to pass this in
        new ExponentialBackoffPolicy.Provider(),
        SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),
        GrpcUtil.STOPWATCH_SUPPLIER,
        getEffectiveInterceptors(),
        TimeProvider.SYSTEM_TIME_PROVIDER));
  }

在ManagedChannelImpl类中会继续调用ClientInterceptors.InterceptorChannel中的方法

ManagedChannelImpl----->>
 this.interceptorChannel = ClientInterceptors.intercept(channel, interceptors);
  /*
   * Creates a new outgoing call on the channel.
   */
  @Override
  public <ReqT, RespT> ClientCall<ReqT, RespT> newCall(MethodDescriptor<ReqT, RespT> method,
      CallOptions callOptions) {
    return interceptorChannel.newCall(method, callOptions);
  }

ClientInterceptors.InterceptorChannel中的newCall根据类型,在build()方法中的getEffectiveInterceptors()默认会设置StatsClientInterceptor和TracingClientInterceptor两个拦截器,在ClientInterceptors.intercept(channel, interceptors)方法调用时,会把这两个拦截器分别创建InterceptorChannel并返回,返回的channel包装了两层连接器,所以调用时先

ClientInterceptors.InterceptorChannel------------------->
private final ClientInterceptor interceptor;

    private InterceptorChannel(Channel channel, ClientInterceptor interceptor) {
      this.channel = channel;
      this.interceptor = Preconditions.checkNotNull(interceptor, "interceptor");
    }

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> newCall(
        MethodDescriptor<ReqT, RespT> method, CallOptions callOptions) {
      return interceptor.interceptCall(method, callOptions, channel);
    }

在build()中新建ManagedChannelImpl中,创建的channel中channel使用了ServiceConfigInterceptor拦截器,在ServiceConfigInterceptor中调用next.newCall(method, callOptions),build()方法中Channel channel = new RealChannel(nameResolver.getServiceAuthority());是创建的RealChannel对象接下来会进入RealChannel的newCall方法,最后创建ClientCallImpl对象。在CensusTracingModule中,创建SimpleForwardingClientCall(call)对象,在CensusStatsModule中创建SimpleForwardingClientCall(call)对象,最后返回到有.proto文件生成的代码getChannel().newCall中。

ClientCall newCall() 创建流程

OptionServiceStub CensusStatsModule CensusTracingModule ServiceConfigInterceptor ManagedChannelImpl.RealChannel interceptCall interceptCall interceptCall newCall ClientCallImpl SimpleForwardingClientCall SimpleForwardingClientCall SimpleForwardingClientCall OptionServiceStub CensusStatsModule CensusTracingModule ServiceConfigInterceptor ManagedChannelImpl.RealChannel

clientcall组装好之后,在asyncBidiStreamingCall(clientcall,oberserver)中创建连接和stream并启动,
ManagedChannelImpl.ChannelTransportProvider: get 方法第一次调用时,异步进行域名解析和负载均衡,并返回DelayedClientTransport对象
DelayedStream:在transport可用之前的stream,当transport可用的时候会委托给真实的stream
这里的DelayedClientTransport和DelayedStream是把dns解析和发送消息等线程放入syncContext中进行异步执行,在异步执行ManagedChannelImpl的requestConnection方法时调用 InternalSubchannel的obtainActiveTransport方法判断是否存在activeTransport,若没有会新建NettyClientTransport并进行连接,在创建stream时会建立连接,在连接成功后更新InternalSubchannel的activeTransport的值和ManagedChannelImpl的subchannelPicker,下次直接从该transport创建stream。

ClientCalls ClientCallImpl ManagedChannelImpl.ChannelTransportProvider DelayedClientTransport DelayedStream start startInternal get DelayedClientTransport newStream createPendingStream PendingStream,并放入syncContext中,异步执行 start ClientCalls ClientCallImpl ManagedChannelImpl.ChannelTransportProvider DelayedClientTransport DelayedStream

grpc客户端创建连接和发送消息流程

Created with Raphaël 2.2.0 ClientCallImpl.start() getTransport (可能会返回 DelayedClientTransport和NettyClientTransport) NettyClientTransport? 创建NettyClientStream 同步创建stream,发送消息直接调用NettyClientStream的write方法,向channel中写入消息。 等待返回 创建PendingStream 要执行的任务放入队列中,异步执行 异步执行dns解析和创建netty客户端并连接, 连接成功后更新InternalSubchannel中的activeTransport等信息, 下次getTransport 时会返回NettyClientTransport yes no
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值