I tried gRPC Java Tutorial and was curious about how it works, so I researched various things.
--GRPC-How to use Java is described in the tutorial, so I will not explain it in detail. ――It is a summary of what I understood about how to communicate and what the detailed internal implementation is.
releases: gRPC-Java v1.16.1
--The tutorial used the routeguide package source --Click here for gradle settings
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'
First of all, about gRPC, the points are excerpted from Official Document.
-Use Protocol Buffers to serialize the data to be sent and received and define the RPC interface. --The Protocol Buffers definition file only defines data serialization, but gRPC extends it to define the RPC interface as well. --Most of the code for the data and interfaces to be serialized is automatically generated, so you can concentrate on your business logic. --Communication uses HTTP / 2 --HTTP / 2 format for establishing communication and sending / receiving headers and data --Bidirectional streaming communication is possible with one TCP connection, and the following 4 types of rpc methods can be defined.
type | Overview |
---|---|
A simple RPC | Returns 1 response for 1 request |
A server-side streaming RPC | Returns multiple responses for one request |
A client-side streaming RPC | Returns one response for multiple requests |
A bidirectional streaming RPC | Exchange multiple requests and multiple responses in both directions |
gRPC-Java implementation points.
--On the server side, the communication control part uses Netty. --The client side uses OkHttp for Android, and Netty otherwise. --This time, the processing on the client side has not been investigated much.
--Whether it is Android or not is in ServiceProviders # loadAll Determine using ClassLoader
are doing.
--For non-Android, ServiceProviders # getCandidatesViaServiceLoader Use java.util.ServiceLoader # load in META-INF / services / io.grpc.ServerProvider I'm getting the written class
--I first learned about java.util.ServiceLoader # load. ..
Netty used in gRPC-Java is a framework that allows you to create non-blocking I / O (NIO) applications in Java. (Do not use Java Servlet)
The thread that appears in gRPC, the event name of NIO, and the processing of Netty are like this.
--Detect ʻOP_ACCEPT in boss thread and register ʻOP_READ
event
--The worker thread executes the processing of ʻOP_READ and ʻOP_WRITE
--The worker thread reads the client request and creates an executor thread to execute the process when the gRPC method call is needed.
Character | role |
---|---|
boss thread (ServerBootstrap parentGroup) |
I of the network used by Netty/A thread that detects O. One is generated by default at startup. |
worker thread (ServerBootstrap childGroup) |
I used by Netty/O A thread that processes each event. The default isNumber of processors x 2。 |
executor thread | A thread that executes the methods defined in gRPC. Generated for each method call. |
I/O event name | Overview |
---|---|
OP_ACCEPT | Connection from client |
OP_READ | Network I/Read O |
OP_WRITE | Network I/Export O |
For Netty, "JJUG CCC 2018 Spring --I-7 (I) First Netty" is very helpful. Became.
Excerpts from google's Introduction to HTTP / 2 to help you understand gRPC.
In HTTP / 1.x, plain text separated by line breaks is regarded as one request (or response), but in HTTP / 2, this is expressed as one message, and the message is further divided into the following frame units.
--HEADERS frame (HTTP / 1.x header) --DATA frame (HTTP / 1.x body)
In addition, frames can be exchanged in parallel and in both directions with a single TCP connection. In other words, it is not necessary to establish a TCP connection for each request, and multiple responses and server pushes can be made for one request.
From this point onward, it will be a story like "what part of the code and what process ~", so before that, I will summarize what I interpreted about the series of processes.
, it creates a Netty worker thread (or gets it from the pool) and delegates the processing of ʻOP_READ
/ ʻOP_WRITE`.5. ~ 7.
can be executed many times in parallel.TODO I'm writing it for my own memo, so I'll add it later and organize it. (It was difficult to keep track of creating various threads and creating new threads with callbacks, so I'd be happy if you could tell me if I made a mistake.)
--Run RouteGuideServer # main --Get an instance of ServerBuilder with ServerBuilder # forPort --In ServiceProviders # loadAll, look at the ClassLoader to determine if it's an Android app or not. --For non-Android, use the ServiceLoader # load mechanism in the java.util package to META-INF / services / io.grpc.ServerProvider From .16.1 / netty / src / main / resources / META-INF / services / io.grpc.ServerProvider) to [NettyServerProvider.java](https://github.com/grpc/grpc-java/blob/v1.16.1/ I'm getting an instance of netty / src / main / java / io / grpc / netty / NettyServerProvider.java) --In NettyServerBuilder # addService, pass the class that inherits the automatically generated xxxGrpc.xxxImplBase --Here, the methods defined in Protocol Buffers are bound. -AbstractServerImplBuilder.java # L146 Because the automatically generated code bindService is called
event in io.netty.channel.nio.NioEventLoop.run --Pass the executor a ThreadPoolExecutor with a ThreadFactory (ThreadFactoryBuilder $ ThreadFactory) that creates a thread with the name
grpc-default-executor-% d`
--GRPC methods spawn and execute threads from here each time they are called
--When NettyServer is started, the main thread uses Runtime.getRuntime (). AddShutdownHook () to define the processing at the end.
--Furthermore, the main thread calls RouteGuideServer.blockUntilShutdown to enter the WAIT state.--When the worker thread accepts a gRPC method call request, NettyServerHandler is ServerImpl $ ServerTransportListenerImpl # streamCreated /io/grpc/netty/NettyServerHandler.java#L437)
--ServerImpl $ ServerTransportListenerImpl # streamCreated [pass an instance of StreamCreated that inherits ContextRunnable to the SerializingExecutor that wraps ThreadPoolExecutor](https://github.com/grpc/grpc-java/blob/v1.16.1/core/src/ main / java / io / grpc / internal / ServerImpl.java # L495)
--This executor runs the following Runnable task in ThreadFactoryBuilder $ ThreadFactory with the thread name grpc-default-executor-% d
--StreamCreated # run-> StreamCreated # runInContext is executed
--And ServerImpl # JumpToApplicationThreadServerStreamListener $ MessagesAvailable # runInContext is called
--Furthermore, ServerImpl \ $ JumpToApplicationThreadServerStreamListener $ 1HalfClosed # runInContextHalfClosedgRPC method is executed.
--When the getFeature
defined in gRPC is called, it looks like this
getFeature:130, RouteGuideServer$RouteGuideService (grpc.routeguide)
invoke:462, RouteGuideGrpc$MethodHandlers (grpc.routeguide)
onHalfClose:171, ServerCalls$UnaryServerCallHandler$UnaryServerCallListener (io.grpc.stub)
halfClosed:283, ServerCallImpl$ServerStreamListenerImpl (io.grpc.internal)
runInContext:710, ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed (io.grpc.internal)
run:37, ContextRunnable (io.grpc.internal)
run:123, SerializingExecutor (io.grpc.internal)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)
Recommended Posts