Volume 34 Number 10
Using gRPC in a Microservice Architecture
By Dino Esposito | October 2019
The microservice architecture style has been taking the software industry by storm in the recent past and with some good arguments. It objectively delivers key benefits that make the resulting system resilient to failure and scalable at the desired level of granularity. In an enterprise scenario, a microservice architecture enables the use of heterogeneous technologies and different architectural patterns. It also dramatically simplifies deployment and allows the engineering department to more easily shape up a bespoke project that reflects the internal organization.
All that said, what’s the concrete result of designing and deploying a microservice-based architecture? The commonly accepted answer to this question is the trigger for this month’s article, and the logical background for introducing the gRPC framework in a microservice architecture.
Breaking Up the Monolith
Although no official definition of microservices probably exists, nearly everybody agrees on a definition that goes along the lines of organizing the entire logic of a single software application in a collection of smaller services. Each constituent service ends up being considerably smaller in size and complexity than the single application in its entirety. These (micro) services are treated as independent units of the application and are implemented and deployed autonomously. Also important, is each microservice be fully responsible for its own data.
In a nutshell, the microservice architecture breaks up a single software monolith into a myriad of independent and distributed components. Note that in this context the term myriad is a bit of a hyperbole, with the number of microservices usually measured on the order of tens. A smart (if relative and non-quantitative) definition of the ideal microservice size is that it should never be larger than a problem’s subdomain and never smaller than a cluster of related domain objects.
In a microservice application, the individual components form a distributed architecture in which each component runs its own process and communicates with others over possibly lightweight protocols. There are many ways in which two distinct microservices can communicate over the network. Most of the time, they do it using REST interfaces and JSON for data serialization. The whole Web services world was devised to use SOAP as the underlying protocol for communication and XML as the data serialization format. SOAP wasn’t necessarily ideal, but it was the best the industry could work out 20 years ago. Later came REST and RESTful interfaces, which offered important advantages over SOAP with its well-defined and standardized messaging patterns (like the WS-XXX family).
REST arrived as an antidote to the perceived complexity of SOAP, performing direct access to the data and defined in the form of resources. Access to resources occurs using the verbs (and the rules) of the underlying HTTP protocol. In other words, a RESTful interface has no need to define interfaces and constraints, other than those set by the underlying HTTP protocol itself. In this picture, JSON is only a serialization format, less verbose and more flexible than XML. Today REST and JSON together represent the lion’s share of microservices communications, but there are other, and possibly better, communication technologies to consider. The most enticing is the gRPC framework.
Bringing gRPC to the Table of Microservices
At first, using the gRPC framework to connect distributed components may look like a step backward. After celebrating the advent of REST as the triumph of flexibility and decoupling, the industry is now carefully considering an approach centered on the concept of remote procedure calls (RPC). By design, an RPC requires some level of coupling between the caller and receiver.
In addition, the gRPC framework pushes well-defined messages, versioning and contracted endpoints. The framework runs over the newer HTTP/2 protocol and exchanges data in a binary format. Under the hood, a number of other, subtler differences exist that make gRPC worth a closer look. But is gRPC a better REST, or is it just particularly suited to a microservices scenario?
The point is that REST in itself is only the formalization of an ideal uniform interface to connect components. Inspired in 2000 by the way the Web was developing, REST never really achieved the goal of enabling any RESTful client to talk to any RESTful server regardless of knowing much of the details. How many RESTful Web APIs return 200 OK to report an error? And how many use the same POST verb to add, delete and update resources? REST definitely works, but beyond hype and fanfare it’s nothing more than a plain API exposed over HTTP that just requires an HTTP call to return a response. Each developer calling any endpoint of any declared REST API needs to know all of its details and, often, he is free to place calls in a different way than is documented and still get a valid response. As brutal as it may sound, there’s no (concretely applied) standard around REST.
As implemented in most real-world applications today, REST is basically a simplified, unstructured and improvable form of RPC in which HTTP elements (headers, query string, payloads, status codes) form the syntax of each call, and every call in every service may feature different characteristics.
So where does gRPC come from? It was originally developed by Google as a framework to better connect its large internal network of standalone services. That framework was open sourced in 2015 under the name gRPC, and is now owned by the Cloud Native Computing Foundation. The gRPC framework addressed precisely the scenario of most of today’s microservice-style architectures.
In which way is gRPC preferable over a REST-inspired HTTP API? Let’s take a look.
Contrasting gRPC and HTTP API
At its core, the gRPC framework is designed for any scenario where communication efficiency is critical. This marks a first crucial difference from the HTTP API. Two microservices are not like two communicating Web sites. For example, the ASP.NET application that consumes the API exposed by another Web site evolves independently from the site. While there’s still no realistic guarantee that the HTTP API will evolve, preserving backward compatibility toward all of its callers, the link between API owner and callers remains quite loose.
The gRPC framework instead enforces a binding between client and service. In this regard, it represents a viable option in circumstances where client and service are managed by the same team and follow the same development cycle. In other words, tight coupling is ideal in a tightly coupled network of components like a microservice-oriented application. Once it’s determined that the tight-coupling argument isn’t an architectural shortcoming, then the benefits of bindings between client and service can be further analyzed.
The major benefit of gRPC over a plain HTTP API is performance. As mentioned, the gRPC framework uses HTTP/2 as the transportation layer, which is the newest version of HTTP with some specific improvements in the area of binary framing, compression and multiplexing over a single connection. As a result, HTTP/2 is more efficient and also flexible both in sending and receiving packets. Beyond the transportation protocol, the framework itself takes care of serializing and deserializing data using the Protobuf binary format. This contributes to making the traffic generated by each gRPC call more compact.
Beyond performance, the gRPC framework provides benefits also in the application development space. Each service is based on a .proto file that acts as the contract of the service. The contract can be used to generate the service and client. The framework takes care of the dirty job of generating client, service base class and messages for every major computer language, with all of them using the same contract standard. Messages in particular are crucial as any method is designed to receive a message and return a message, and the contract of both is fixed. This means that the call fails if anything is sent or received outside the boundaries of the contract. Anybody who ever experienced the burden of receiving incorrect or inconsistent JSON or weird status codes knows very well what I mean here. The gRPC framework is type-safe and consistent across all supported platforms and implementations.
In a nutshell, the gRPC framework was somehow to avoid the shortcomings of a RESTful, HTTP-based API in the context of a (very) large organization and myriads of distributed components.
In past installments of this column, I covered the basics of gRPC and discussed some examples of its capabilities. In particular, last month I wrote about the streaming API. Leveraging the low-level capabilities of HTTP/2, the gRPC framework allows the client to send, and the service to return, multiple packets per connection. The interesting thing is that both the client and the service can be sending and returning multiple packets per connection, thus turning a gRPC communication into a sort of superfast chat.
One of the most talked about anti-patterns of SOAP and REST, and distributed architecture in general, was the “chatty” style of an API in which the client needs to place multiple calls in order to receive all the data it logically needs. While the “chatty” style remains an anti-pattern to avoid, the advanced streaming capabilities of the framework make it possible to arrange a bi-directional channel between two endpoints so messages can be exchanged in real time without polling.
Think, for example, of a monitoring scenario in which the service receives data constantly from a connected device, does some work on it and then passes data to a real-time Web dashboard. In an architecture in which the aggregator and the real-time data provider microservice communicate directly, the use of the gRPC protocol for bi-directional communication can realistically increase the performance of every single call by at least a few milliseconds.
Doesn’t it sound like a huge gain? Well, that’s probably why gRPC isn’t (or not yet) a good fit for the Web UI. But for back-end microservice-to-microservice communication, especially in applications with heavy loads where every bit counts, it could really make a difference.
When Using gRPC between microservices the front end is connected to a microservice (that is, the gateway to the microservice cluster) via a plain HTTP API consumed over the Web. As mentioned, at the current stage of both gRPC and the browser technology, no gRPC services can be invoked directly from any browser. Most modern browsers support HTTP/2, but only in a sort of transparent way and only after negotiating the protocol to use during the initial connection to the server. Because of this, browsers don’t allow clients to dictate the protocol to use and therefore can’t directly invoke the gRPC service. Microservice-to-microservice communication or, more broadly, server-to-server communication, is a good scenario for gRPC, but mobile and desktop applications can use gRPC, as well.
Until recently, the word REST has been used to label nearly any public endpoints exposed over the Web through the HTTP protocol. REST came with the promise that once resources are defined the entire public API results from the combination of resource names and HTTP verbs. As more verbs and resources are added, new and existing clients can just connect and place calls. This flexibility comes at an obvious cost—the lack of strict rules and contracts. This is just what gRPC brings to the table.
Dino Esposito has authored more than 20 books and 1,000-plus articles in his 25-year career. Author of “The Sabbatical Break,” a theatrical-style show, Esposito is busy writing software for a greener world as the digital strategist at BaxEnergy. Follow him on Twitter: @despos.