gRPC客户端创建和调用原理解析

1. gRPC客户端创建流程 1.1. 背景

gRPC是在HTTP/2之上实现的RPC框架,HTTP/2是第7层(应用层)协议,它运行在TCP(第4层 - 传输层)协议之上,相比于传统的REST/JSON机制有诸多的优点:

基于HTTP/2之上的二进制协议(Protobuf序列化机制)

一个连接上可以多路复用,并发处理多个请求和响应

多种语言的类库实现

服务定义文件和自动代码生成(.proto文件和Protobuf编译工具)

此外,gRPC还提供了很多扩展点,用于对框架进行功能定制和扩展,例如,通过开放负载均衡接口可以无缝的与第三方组件进行集成对接(Zookeeper、域名解析服务、SLB服务等)。

一个完整的RPC调用流程示例如下:

(点击放大图像)

gRPC客户端创建和调用原理解析

图1-1 通用RPC调用流程

gRPC的RPC调用与上述流程相似,下面我们一起学习下gRPC的客户端创建和服务调用流程。

1.2. 业务代码示例

以gRPC入门级的helloworld Demo为例,客户端发起RPC调用的代码主要包括如下几部分:

1) 根据hostname和port创建ManagedChannelImpl

2) 根据helloworld.proto文件生成的GreeterGrpc创建客户端Stub,用来发起RPC调用

3) 使用客户端Stub(GreeterBlockingStub)发起RPC调用,获取响应。

相关示例代码如下所示:

(点击放大图像)

gRPC客户端创建和调用原理解析

1.3. RPC调用流程

gRPC的客户端调用主要包括基于Netty的HTTP/2客户端创建、客户端负载均衡、请求消息的发送和响应接收处理四个流程。

1.3.1. 客户端调用总体流程

gRPC的客户端调用总体流程如下图所示:

(点击放大图像)

gRPC客户端创建和调用原理解析

图1-2 gRPC总体调用流程

gRPC的客户端调用流程如下:

1) 客户端Stub(GreeterBlockingStub)调用sayHello(request),发起RPC调用

2) 通过DnsNameResolver进行域名解析,获取服务端的地址信息(列表),随后使用默认的LoadBalancer策略,选择一个具体的gRPC服务端实例

3) 如果与路由选中的服务端之间没有可用的连接,则创建NettyClientTransport和NettyClientHandler,发起HTTP/2连接

4) 对请求消息使用PB(Protobuf)做序列化,通过HTTP/2 Stream发送给gRPC服务端

5) 接收到服务端响应之后,使用PB(Protobuf)做反序列化

6) 回调GrpcFuture的set(Response)方法,唤醒阻塞的客户端调用线程,获取RPC响应

需要指出的是,客户端同步阻塞RPC调用阻塞的是调用方线程(通常是业务线程),底层Transport的I/O线程(Netty的NioEventLoop)仍然是非阻塞的。

1.3.2. ManagedChannel创建流程

ManagedChannel是对Transport层SocketChannel的抽象,Transport层负责协议消息的序列化和反序列化,以及协议消息的发送和读取。ManagedChannel将处理后的请求和响应传递给与之相关联的ClientCall进行上层处理,同时,ManagedChannel提供了对Channel的生命周期管理(链路创建、空闲、关闭等)。

ManagedChannel提供了接口式的切面ClientInterceptor,它可以拦截RPC客户端调用,注入扩展点,以及功能定制,方便框架的使用者对gRPC进行功能扩展。

ManagedChannel的主要实现类ManagedChannelImpl创建流程如下:

(点击放大图像)

gRPC客户端创建和调用原理解析

图1-3 ManagedChannelImpl创建流程

流程关键技术点解读:

使用builder模式创建ManagedChannelBuilder实现类NettyChannelBuilder,NettyChannelBuilder提供了buildTransportFactory工厂方法创建NettyTransportFactory,最终用于创建NettyClientTransport。

初始化HTTP/2连接方式:采用plaintext协商模式还是默认的TLS模式,HTTP/2的连接有两种模式:h2(基于TLS之上构建的HTTP/2)和h2c(直接在TCP之上构建的HTTP/2)。

创建NameResolver.Factory工厂类,用于服务端URI的解析,gRPC默认采用DNS域名解析方式。

ManagedChannel实例构造完成之后,即可创建ClientCall,发起RPC调用。

1.3.3. ClientCall创建流程

完成ManagedChannelImpl创建之后,由ManagedChannelImpl发起创建一个新的ClientCall实例。ClientCall的用途是业务应用层的消息调度和处理,它的典型用法如下:

call = channel.newCall(unaryMethod, callOptions); call.start(listener, headers); call.sendMessage(message); call.halfClose(); call.request(1); // wait for listener.onMessage()

ClientCall实例的创建流程如下所示:

(点击放大图像)

gRPC客户端创建和调用原理解析

图1-4 ClientCallImpl创建流程

流程关键技术点解读:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13469.html