gRPC Simplified
Learn how to create basic gRPC clients and servers in Java
You must be thinking, what on Earth is this gRPC? Why does this exist when we have other modes of communication? How is this newbie technology going to help? Well, there's nothing that "fits all needs perfectly". We have multiple solutions to a single problem, but we should know the tradeoffs for each solution and then choose amongst those. Like we can choose gRPC over REST regarding speed of data transfer problems.
gRPC is a message-passing technique developed by Google. The "g" in gRPC does not mean "google"; it changes with every version. For example, the "g" in gRPC 1.12
stands for "glorious" and for "good" in gRPC 1.1
.
gRPC is a modern open-source, high-performance Remote Procedure Call (RPC) framework that can run in any environment. It is also applicable in the last mile of distributed computing to connect devices, mobile applications, and browsers to backend services.
So, gRPC does not provide guidelines for creating web APIs; it enforces rules. gRPC, in most cases, is faster and more robust, as it defines a specific set of rules each request and response should adhere to.
Requests flow
Let's see the request flow for gRPC:
- The client starts by packing the request and sending all the necessary data to the client stub, which marshalls and sends it to the server.
- RPC Runtime contains run-time routines responsible for transmitting RPC packets between the client and server stubs.
- The server side stub receives the request from the client and unpacks (unmarshalls) the request. The Server stub creates and marshalls the response and sends it to the client.
- This response is received at the client's end. Client stub starts unmarshalling (unpacking) the response.
The basic building block of gRPC is protobuf
. Google's protobuf
or proto
is just a mechanism for serializing structured data. Let's look at an example proto
for message sending service.
syntax = "proto3";
option java_multiple_files = true;
message MessageRequest {
string recipient = 1;
string message = 2;
}
message MessageResponse {
string response = 1;
}
service MessageService {
rpc send(MessageRequest) returns (MessageResponse);
}
In the above code snippet, we have a service and multiple message blocks, which are converted into class and model respectively post compilation. Proto compilation is done in multiple ways:
- Using
protoc
command:
protoc -I -java_out=${OUTPUT_DIR} path/to/proto/file
- Use
maven-plugin
and add it to Maven's compile lifecycle stage for auto-generation. Let's take a look at an example of a gRPC client and server using the messageproto
.
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class Client {
public static void main(String[] args) throws InterruptedException {
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 8080)
.usePlaintext()
.build();
MessageServiceGrpc.MessageServiceBlockingStub stub =
MessageServiceGrpc.newBlockingStub(channel);
org.example.grpc.MessageResponse messageResponse = stub
.send(org.example.grpc.MessageRequest.newBuilder()
.setMessage("Welcome back!!")
.setRecipient("Daniel")
.build());
System.out.println("Response received from server:\n" +
messageResponse);
channel.shutdown();
}
}
In the above code snippet, the client is responsible for creating a plain text channel for communicating with the server. Messaging service stub
is assigned to the created channel and used to invoke messageService.send()
on it.
import io.grpc.ServerBuilder;
import java.io.IOException;
public class Server {
public static void main(String[] args) throws IOException,
InterruptedException {
Server server = ServerBuilder.forPort(8080)
.addService(new MessageServiceImpl()).build();
System.out.println("Starting server...");
server.start();
System.out.println("Server started!");
server.awaitTermination();
}
}
In the above code, we create a server using ServerBuilder
and attach a messaging service by calling addService()
on it. We invoke the start method on this server and wait for incoming client connections.
import io.grpc.stub.StreamObserver;
public class MessageServiceImpl extends MessageServiceImplBase{
@Override
public void send(org.example.grpc.MessageRequest request,
StreamObserver<org.example.grpc.MessageResponse> responseObserver) {
System.out.println("Request received from client:\n" + request);
String greeting = new StringBuilder().append("Hello, ")
.append(request.getRecipient())
.append(" ")
.append(request.getMessage())
.toString();
org.example.grpc.MessageResponse response =
org.example.grpc.MessageResponse.newBuilder()
.setResponse(greeting)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
The MessageServiceImpl
class extends MessageServiceImplBase
, which is auto-generated after proto
file compilation. We need to implement thesend()
method, which will read the request and create a response to be sent to the client.
Advantages
Below are a few advantages of gRPC:
- gRPC uses
protobuff
and http2, which transports data as binary and supports duplex streaming. protoc
helps the auto-generation of client code.- gRPC library is continuously monitored to ensure speed reliability.
- We can have a connection pool through managed channels.
- gRPC library has an inbuilt library for load balancing.
- Language agnostic, where Java client can connect to Python server seamlessly.
Limitations
Although gRPC has advantages, it also has a few limitations:
- There's no browser support, so it can be used only in internal APIs.
- Postman support in the newer version is very limited, but other clients like BloomRpc and Kreya have good support.
Case Uses
These are a few use cases of gRPC:
- For internal microservices.
- For services needing streaming with a huge load of data.
Conclusion
Lastly, for heavily loaded servers, gRPC APIs perform far better, up to seven times faster when receiving data and ten times faster when sending data. This conclusion is a result of testing done on the internal services for an application. But if servers serve only a few requests, REST will suffice.
References
These references will be of help:
- The basics of gRPC are explained at the link.
- gRPC with java repository.
- gRPC client and server example.