GRPC

INTRODUCTION

Grpc is a modern, high-performance RPC platform that can run in any environment. The project was created under an open-source license by Google. It is part of the Cloud Native Computation Foundation (CNCF). With gRPC, a client application can directly call a method in the server application on another machine as if it were a local object. Like many RPC systems, gRPC is about defining services, specifying methods that can be called remotely, along with request parameters and return types. The gRPC client and server can run and communicate with each other in different environments. An additional advantage is the independence of the language. The server and client code can be implemented in any programming language supported by gRPC, e.g. we can write server code using Java and client code e.g. in Go, Python or other gRPC supported languages.

WHY USE GRPC

Currently, IT systems are designed in the architecture of microservices. Microservices most often communicate with the use of REST-based on the HTTP/1.1 protocol, exchanging data in the JSON format. REST is easy, convenient and widely used to exchange information between microservices. However, it has the following problems:

  • uses the HTTP/1.1 text protocol, information exchange based on large JSON payloads
  • HTTP is a stateless protocol, additional information is provided in uncompressed headers
  • based on the HTTP/1.1 protocol. we send the request and then await a response. Until we receive a reply, we cannot send another request

All these problems may result in a significant decrease in the performance of our systems. REST is very good for communication between the browser and the server, while for communication between microservices we need something more efficient. gRPC is faster than REST. We achieve an increase in efficiency thanks to the built-in tools that gRPC uses internally:

  • Protocol Buffers
  • HTTP/2

PROTOCOL BUFFERS

Getting started with gRPC, and thus defining the content of request and response objects, requires reading Protocol Buffers. It is a language-independent, extensible mechanism for serializing structured data between services. Using Protocol Buffers, we define a communication contract between two systems in the form of a file with the .proto extension, based on which we can generate code in the selected programming language supported by gRPC. Advantages of using Protocol Buffers:

  • ease of API development
  • implementation-independent API definition
  • large amounts of code that can be generated for many programming languages supported by gRPC
  • data is sent in binary form, which gives high efficiency in sending and receiving data
  • low CPU intensity when parsing and unparsing data

HTTP/2

GRPC uses the HTTP/2 protocol as the communication backbone, which is the new standard for communication on the Internet. With the use of HTTP/2, the client and the server can send messages in parallel using the same TCP connection as opposed to HTTP/1.1 which creates a new connection for each request to the server, which effectively reduces transmission latency. HTTP/2 introduces a binary communication format and advanced header compression.

HTTP/1.1 vs HTTP/2

HTTP/1.1HTTP/2
Text formatBinary format
Headers sent as plain textCompressed headers
Request and response in one TCP connectionThe same TCP connection can be reused by sending several requests

GRPC API DEFINITION TYPES

Using gRPC we can define 4 types of API:

  • Unary – the classic model of request -> response communication
  • Server Streaming – The client sends a request to the server and can then receive the response stream
  • Client Streaming – the client opens a stream of requests and sends several messages, and the server returns a response upon completion
  • Bi-Directional Streaming – server and client can send multiple requests, replies asynchronously

EXAMPLE OF IMPLEMENTATION

The implementation was made in the Java programming language using the SpringBoot framework. The project has been divided into the following modules:

1. proto-module

Contains the file calculator.proto which defines the calculator API – adding two numbers.

Protocol Buffers
syntax = „proto3”;

package calculator;
option java_package = „com.proto.calculator”;
option java_multiple_files = <strong>true</strong>;

message <strong>SumRequest</strong> {
  int64 first_number = 1;
  int64 second_number = 2;
}

message <strong>SumResponse</strong> {
  int64 result = 1;
}

service <strong>CalculatorService</strong> {
  rpc Sum(SumRequest) returns (SumResponse) {};
}

Defined objects:

  • SumRequest – the request object, accepts two long numbers
  • SumResponse – the response object, contains the result of the addition
  • CalculatorService – defines a Sum method which takes SumRequest and returns a SumRespone object

2. service-module

The server application defines the calculator logic. On the server-side, the sum method should be implemented, extending the specific class and overwriting the implementation of the selected method.

Java
@GrpcService
public class <strong>CalculatorService</strong> extends <strong>CalculatorServiceGrpc</strong>.CalculatorServiceImplBase {

  @Override
  public void <strong>sum</strong>(SumRequest request, StreamObserver responseObserver) {
    long firstNumber = request.getFirstNumber();
    long secondNumber = request.getSecondNumber();

    SumResponse response = SumResponse.newBuilder()
    .setResult(firstNumber + secondNumber)
    .build();

    responseObserver.onNext(response);
    responseObserver.onCompleted();
  }
}

Additionally, the server port should be defined in the application.properties file:

grpc.server.port=6565

3. client-module

The last step is to define the client application. The generated code provides the Builder pattern, with the use of which we can create the SumRequest object, and then pass it as a parameter of the method call.

Java
@Service 
public class <strong>CalculatorService</strong> { 

  @GrpcClient(„calculator-service”) 
  private CalculatorServiceGrpc.CalculatorServiceBlockingStub blockingStub; 

  public long <strong>sum</strong>(long firstNumber, long secondNumber) { 
    SumRequest sumRequest = SumRequest.newBuilder() 
    .setFirstNumber(firstNumber) 
    .setSecondNumber(secondNumber) 
    .build(); 
    SumResponse sum = blockingStub.sum(sumRequest); 
    return sum.getResult(); 
  } 
}

The application.yaml file defines the access details of the gRPC server referenced by the client application.

YAML
server:
  port: 8080
grpc:
  client:
    calculator-service:
      address: static://localhost:6565
      negotiationType: plaintext

SUMMARY

The article presents a new way of communication between microservices – gRPC. API models that can be created with its use are presented. The example implementation shows a typical request-response communication model (unary API), but nothing prevents you from similarly implementing other API models. Complete source code is available here.