In modern microservice architecture, we can categorize microservices into two main groups based on their interaction and communication. The first group of microservices acts as external-facing microservices, which are directly exposed to consumers. They are mainly HTTP-based APIs that use conventional text-based messaging payloads (JSON, XML, etc.) that are optimized for external developers, and use Representational State Transfer (REST) as the de facto communication technology.

REST’s ubiquity and rich ecosystem play a vital role in the success of these external-facing microservices. OpenAPIprovides well-defined specifications for describing, producing, consuming, and visualizing these REST APIs. API management systems work well with these APIs and provide security, rate limiting, caching, and monetizing along with business requirements. GraphQL can be an alternative for the HTTP-based REST APIs but it is out of scope for this article.

The other group of microservices are internal and don’t communicate with external systems or external developers. These microservices interact with each other to complete a given set of tasks. Internal microservices use either synchronous or asynchronous communication. In many cases, we can see the use of REST APIs over HTTP as a synchronous mode but that would not be the best technology to use. In this article, we will take a closer look at how we can leverage a binary protocol such as gRPC which can be an optimized communication protocol for inter-service communication

What is gRPC?

RELATED SPONSORED CONTENT
Architecting for Reactive Microservices - an O’Reilly book pack. Download now.
DevNation: Attend Live and Virtual Events on Kubernetes, Serverless, Java, and More – Save your Seat!
Serving Machine Learning Models: A Guide to Architecture, Stream Processing Engines, and Frameworks
Kubernetes Up & Running – Download the eBook (By O’Reilly)
From Docker to Kubernetes: Container Networking 101 (By O’Reilly)
RELATED SPONSOR

**NGINX Plus is the complete application delivery platform for the modern web. **Start your 30 day free trial.

gRPC is a relatively new Remote Procedure Call (RPC) API paradigm for inter-service communications. Like all other RPCs, it allows directly invoking methods on a server application on a different machine as if it were a local object. Same as other binary protocols like Thrift and Avro, gRPC uses an interface description language (IDL) to define a service contract. gRPC uses HTTP/2, the latest network transport protocol, as the default transport protocol and this makes gRPC fast and robust compared to REST over HTTP/1.1.

You can define the gRPC service contract by using Protocol Buffers where each service definition specifies the number of methods with the expected input and output messages with the data structure of the parameters and return types. Using major programming language provided tools, a server-side skeleton and client-side code (stub) can be generated using the same Protocol Buffers file which defines the service contract.

A Pragmatic Microservices Use Case with gRPC

Figure 1: A segment of an online retail shop microservices architecture

One of the main benefits of microservice architecture is to build different services by using the most appropriate programming language rather than building everything in one language. Figure 1 illustrates a segment of an online retail shop microservice architecture, where four microservices are implemented in Ballerina (referred to as Ballerina in the rest of the article) and Golang working together to provide some functionality of the retail online shop. Since gRPC is supported by many major programming languages, when we define the service contracts, implementation can be carried out with a well-suited programming language.

Let’s define service contracts for each service.

syntax="proto3";

package retail_shop;

service OrderService {
   rpc UpdateOrder(Item) returns (Order);
}  
message Item {
   string itemNumber = 1;
   int32 quantity = 2;
}
message Order {
   string itemNumber = 1;
   int32 totalQuantity = 2;
   float subTotal = 3;

Listing 1: Service contract for Order microservice (order.proto)

The Order microservice will get shopping items and the quantity and return the subtotal. Here I use the Ballerina gRPC tool to generate a gRPC service boilerplate code and the stub/client respectively.

$ ballerina grpc --mode service --input proto/order.proto --output gen_code

This generates the OrderService server boilerplate code.

import ballerina/grpc;
listener grpc:Listener ep = new (9090);

service OrderService on ep {
   resource function UpdateOrder(grpc:Caller caller, Item value) {
       // Implementation goes here.

       // You should return an Order
   }
}
public type Order record {|
   string itemNumber = "";
   int totalQuantity = 0;
   float subTotal = 0.0;

|};
public type Item record {|
   string itemNumber = "";
   int quantity = 0;

|};      

#go language #microservices #grpc #ballerina #development #architecture & design #article

Building Effective Microservices with gRPC, Ballerina, and Go
2.50 GEEK