gRPC Simplified

Shivali Pawar
Globant
Published in
4 min readDec 21, 2022

Learn how to create basic gRPC clients and servers in Java

Photo by Mathew Schwartz on Unsplash

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:

RPC Mechanism. The client and server are internal services, and the client cannot be a browser.
  1. 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.
  2. RPC Runtime contains run-time routines responsible for transmitting RPC packets between the client and server stubs.
  3. 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.
  4. 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 message proto.
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 ServerBuilderand 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:

--

--