介绍
我尝试了有关gRPC的Java教程,并对它的工作方式感到好奇,所以我研究了各种东西。
- 本教程中介绍了如何使用gRPC-Java,因此我将不对其进行详细说明。
- 这是我对如何进行通信以及详细的内部实现方式了解的一种安排。
确认版本
发行版:gRPC-Java v1.16.1
- 本教程中使用了routeguide软件包的源代码。
- 单击此处进行gradle设置
1 2 3 | compile 'io.grpc:grpc-netty-shaded:1.16.1' compile 'io.grpc:grpc-protobuf:1.16.1' compile 'io.grpc:grpc-stub:1.16.1' |
关于gRPC
首先,从官方文档中提取有关gRPC的要点。
-
使用协议缓冲区序列化要发送和接收的数据,并定义RPC接口
- 协议缓冲区定义文件仅定义数据的序列化,但gRPC对其进行了扩展以定义RPC接口。
- 用于序列化的数据和接口的大多数代码是自动生成的,因此您可以专注于业务逻辑。
-
通讯使用HTTP / 2
- HTTP / 2格式,用于建立通信以及发送/接收头和数据
- 一个TCP连接可以进行双向流通信,并且可以定义以下四种rpc方法。
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tr>
tbody>
table>
关于gRPC-Java
gRPC-Java实现点。
- 在服务器端,通信控制部分使用Netty
-
客户端将OkHttp用于Android和Netty,否则
- 这次,对客户端的处理没有进行太多研究。
-
是否为
Android是通过在ServiceProviders#loadAll中使用
ClassLoader 来确定的。 -
如果不是Android,请使用java.util.ServiceLoader#在ServiceProviders中加载#getCandidatesViaServiceLoader以获得用META-INF / services / io.grpc.ServerProvider编写的类
-
我首先了解了java.util.ServiceLoader#加载。 ..
-
关于Netty
Java中使用的gRPC-Netty是一个框架,允许您在Java中创建非阻塞I / O(NIO)应用程序。 (请勿使用Java Servlet)
gRPC中显示的线程,NIO的事件名称以及Netty的处理均如下所示。
-
在凸台线程中检测
OP_ACCEPT 并注册OP_READ 事件 -
工作线程执行
OP_READ 和OP_WRITE 的处理 - 当需要gRPC方法调用时,辅助线程读取客户端的请求并创建执行程序线程以执行该过程。
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tbody>
table>
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tbody>
table>
补品376??9113
关于Netty," JJUG CCC 2018 Spring --I-7(I)我的第一个Netty"非常有帮助。
关于HTTP / 2
摘录自Google的HTTP / 2简介,以了解gRPC。
在HTTP / 1.x中,以换行符分隔的纯文本被视为一个请求(或响应),但是在HTTP / 2中,它被表示为一条消息,并且该消息以以下帧为单位。
- HEADERS框架(HTTP / 1.x标题)
- 数据帧(HTTP / 1.x主体)
可以使用一个TCP连接并行和双向交换帧。
换句话说,不必为每个请求建立TCP连接,并且可以针对一个请求进行多个响应和服务器推送。
gRPC-Java处理概述
从这一点开始,它将类似于"代码的哪一部分以及什么样的处理?",因此在此之前,我将总结一下我对一系列处理的解释。
在服务器端读取代码
待办事项我正在为备忘录编写它,因此以后将添加它。 (很难跟踪创建各种线程以及使用回调创建新线程的过程,因此,如果您能告诉我是否犯了错误,我将非常高兴。)
开始
- 运行RouteGuideServer#main
-
使用ServerBuilder#forPort获取ServerBuilder的实例
- 查看ServiceProviders中的ClassLoader#loadAll以确定它是否是Android应用程序
- 如果您不是Android用户,则使用java.util包的ServiceLoader#加载机制从META-INF / services / io.grpc.ServerProvider获取NettyServerProvider.java的实例。
-
在NettyServerBuilder#addService中,传递继承自动生成的xxxGrpc.xxxImplBase的类。
- 此处绑定了协议缓冲区中定义的方法
-
因为调用了由AbstractServerImplBuilder.java#L146自动生成的代码的bindService。
-
NettyServerBuilder#构建
- 创建并返回一个ServerImpl实例
- 这时,AbstractServerImplBuilder#buildTransportServer创建NettyServer的实例,将其作为参数传递,并转到ServerImpl具有的称为InternalServer transportServer的字段。
-
执行NettyServer#在ServerImpl中启动#从Builder获得的start
- 使用NettyServer创建Netty所需的父级(老板)和子级(工人)的NioEventLoopGroup实例#allocateSharedGroups
- 新服务器引导程序启动Netty服务器
- 实现ChannelInitializer并将其传递给ServerBootstrap#childHandler
- io.netty.bootstrap.AbstractBootstrap#bind
-
使用initAndRegister启动老板线程
-
io.netty.channel.nio.NioEventLoop.run开始侦听
OP_ACCEPT 事件
-
io.netty.channel.nio.NioEventLoop.run开始侦听
-
将带有ThreadFactory(ThreadFactoryBuilder $ ThreadFactory)的ThreadPoolExecutor传递给执行者,该线程创建名为
grpc-default-executor-%d 的线程- 每次调用gRPC方法时,都会从此处生成并执行线程
- 启动NettyServer时,主线程使用Runtime.getRuntime()。AddShutdownHook()在最后定义处理。
- 另外,主线程调用RouteGuideServer.blockUntilShutdown进入WAIT状态。
收到请求
- 当工作线程接受gRPC方法调用请求时,NettyServerHandler将执行ServerImpl $ ServerTransportListenerImpl#streamCreated
- ServerImpl $ ServerTransportListenerImpl#streamCreated将继承ContextRunnable的StreamCreated实例传递给包装ThreadPoolExecutor的SerializingExecutor。
-
该执行程序在ThreadFactoryBuilder $ ThreadFactory中以线程名称
grpc-default-executor-%d 执行以下Runnable任务。-
StreamCreated#运行
-
StreamCreated#运行