gRPC
ServiceTalk gRPC support is an active work-in-progress and is not yet peformance tested. |
Motivation
A design philosophy for ServiceTalk is cross protocol API symmetry which means that all protocols supported by ServiceTalk should have same constructs and follow the same design principles. We acknowledge that grpc-java implements the gRPC wire protocol for the JVM and is used extensively. However, our design philosophies are different than grpc-java and ServiceTalk also provides HTTP/2 directly for users. The grpc-java team and the ServiceTalk team collaborated to bring HTTP/2 support to Netty, and both share the same underlying protocol implementation. Once you have HTTP/2 support the investment to support the gRPC wire protocol is relatively small but it enables ServiceTalk users to benefit from our design philosophy consistently across all protocols.
Overview
gRPC support in ServiceTalk implements the gRPC wire protocol and provides ServiceTalk APIs for that protocol. It provides all the different Programming Paradigms for client and server. Here is a quick start example of the blocking and aggregated paradigm:
Blocking Client
try (BlockingGreeterClient client = GrpcClients.forAddress("localhost", 8080)
.buildBlocking(new ClientFactory())) {
HelloReply reply = client.sayHello(HelloRequest.newBuilder().setName("Foo").build());
// use the response
}
Blocking Server
GrpcServers.forPort(8080)
.listenAndAwait(new ServiceFactory((BlockingGreeterService) (ctx, request) ->
HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()))
.awaitShutdown();
Extensibility and Filters
The design of this protocol involves configuring builders for core protocol concerns, and then appending Filters
for
extensibility. Filters
are described in more detail below but in general they facilitate user code to
filter/intercept/modify the request/response processing. Filters
can be used for
cross-cutting concerns such as authentication, authorization, logging, metrics, tracing, etc…
Server
The server side is built around the concept of Service
. A Service
is where your business logic lives. Interface for
user service is generated from a provided protocol buffers
service definition. Users implement this interface and provide it to the ServiceTalk gRPC server.
ServiceTalk internally uses the existing HTTP module as the
transport for gRPC. The flow of data from the socket to the gRPC Service
is visualized as follows:
+--------+ request +---------+ +----------+ request +---------+ +----------+ | |--------->| HTTP |------>| HTTP |--------->| gRPC |------>| gRPC | | Socket | | Decoder | | Service | | Decoder | | Service | | |<---------| Encoder |<------|(for gRPC)|<---------| Encoder |<------| | +--------+ response +---------+ +----------+ response +---------+ +----------+
Each Service
has access to a
GrpcServiceContext
which provides additional context
(via ConnectionContext)
into the Connection
/transport details for each request/response. This means that a GrpcService
method may be invoked
for multiple connections, from different threads, and even concurrently.
HTTP Filters
As gRPC module is built on top of HTTP module, one can use the HTTP service filters if required to intercept the HTTP layer.
gRPC Filters
In addition to HTTP filters, gRPC users can also add gRPC filters which follow the same interface definition as the service and can be composed using the generated GrpcServiceFactory for a particular service definition.
Client
A Client
is created via the
GrpcClients static
factory. It manages multiple Connections
via a
LoadBalancer.
The control flow of a request/response can be visualized in the below diagram:
+--------------+ +----------------------+ +--------+ /--->| Connection 1 |<--->| HTTP Decoder/Encoder |<--->| Socket | | +--------------+ +----------------------+ +--------+ +--------+ request +---------+ +--------+ request +--------------+ | | gRPC |--------->| gRPC |------>| HTTP |--------->| | | +--------------+ +----------------------+ +--------+ | Client | | Decoder | | Client | | LoadBalancer |<---+--->| Connection 2 |<--->| HTTP Decoder/Encoder |<--->| Socket | | |<---------| Encoder |<------| |<---------| | | +--------------+ +----------------------+ +--------+ +--------+ response +---------+ +--------+ response +--------------+ | | +--------------+ +----------------------+ +--------+ \--->| Connection x |<--->| HTTP Decoder/Encoder |<--->| Socket | +--------------+ +----------------------+ +--------+
The LoadBalancer is
consulted for each request to determine which connection should be used. The LoadBalancer
interface is extensible and
the reference implementation provides a
Round Robin algorithm.
HTTP Filters
As gRPC module is built on top of HTTP module, one can use the HTTP client filters if required to intercept the HTTP layer.
gRPC Filters
In addition to HTTP filters, gRPC users can also add gRPC filters which follow the same interface definition as the service and can be composed using the generated GrpcClientFactory for a particular service definition.
Connection Filters
gRPC clients support adding connection filters similar to the HTTP module.
Service Discovery
gRPC clients uses Service discovery to discover instances of the target service similar to the HTTP module.