gRPC (13 Part Series)
Hello and welcome to TECH SCHOOL. In this course, we're going to learn about gRPC and how to use it with protocol buffer to develop an application in Go and Java.
Let’s start with this simple question: what is the motivation of gRPC? Or what’s the problem that gRPC is trying to solve?
Well, the answer is communication.
Applications are written using different programming languages.
For example, the back-end can be written in Go, while the front-end, like, android app is written in Java, iOS app is written in Swift.
So how do they talk to each other?
Today’s trend is using Microservices architecture. So even on the backend side, we might have many services written in different languages (like Go, Python or Rust), depending on the business needs and technical constraints.
So, in order to communicate with each other, they must all agree on a set of API contracts. For instance: the communication channel, the authentication mechanism, the payload format, the data model and how to handle errors.
There are so many things that needs to be considered, and that’s why building APIs is really hard.
More than that, we want the communication to be efficient, by which I mean, fast and light-weight. You know, the number of exchange messages between microservices are huge. So, the faster communication the better.
Also, in some environments, like mobile app, where the network speed and bandwidth is limited, it’s very important to have a light-weight communication protocol to interact with the server.
Last but not least, we want the communication to be simple. Let’s imagine that we’re building a system that have hundreds or maybe thousands of microservices. We definitely don’t want to spend most of the time writing codes only to enable them to talk to each other, right?
What we would like to have is some kind of framework that allows developers to focus on implementing the core logic of their services. And leave everything else to the framework to handle.
And that framework is nothing else but gRPC.
gRPC is a high-performance, open-source, feature-rich RPC framework, originally developed by Google, and now is a part of the cloud native computing foundation (or CNCF), just like Kubernetes or Prometheus.
OK, so what
g in gRPC stands for? At first I thought it’s Google (yeah, you know why). But in fact, it stands for different things in each gRPC release, such as “good”, “green”, “glorious”, and even “gRPC” itself.
You can check out the full list in this link.
How about RPC? RPC stands for Remote Procedure Calls. It is a protocol that allows a program to execute a procedure of another program located in other computer.
And what’s awesome about it is that developers don’t have to explicitly coding the details of the network interaction. It’s automatically handled by the underlying framework.
So, in the client code, it looks like we’re just calling a function of the server code directly. And it works even if the codes on client and server are written in different programming languages. Like in this example, the client code is written in Go, and the server code is written in Rust.
So how can gRPC do that? Basically, the client has a stub that provides the same method (or function) as the server. That stub is automatically generated for you by gRPC.
The stub will call gRPC framework under the hood to exchange information with the server over the network.
And voila, magically everything just works. Thanks to the stubs, the client and server now only need to care about implementing their core service logic.
Next, we will see how the gRPC stubs are generated with the help of protocol buffer.
Code generation is one of the most important features of gRPC.
In order to generate stubs for the server and client, we first need to write the API contract, which includes a description of the services and their payload messages in a protocol buffer file that looks something like this:
In this file, a Hello method is defined, which takes a HelloRequest as input and returns a HelloResponse. The HelloRequest only contains a string name, and the HelloResponse has a string greet.
Very simple, right? We will learn much more detail about this later in the hands-on with protobuf lectures.
From this proto file, the server and client stub codes are generated by the protocol buffer compiler (or protoc). Depending on the programming language, we will have to tell the compiler to use the correct gRPC plugin for it.
The generated codes for Rust and Go will look something like this:
OK, so you may wonder why gRPC uses protocol buffer? Well, there are many reasons.
First, it’s super easy to read and understand.
Second, it’s language interoperable with automatic code generation for many languages
Third, It represents data in binary format, which is smaller size, faster to transport, and more efficient to serialize than some text-based format like JSON or XML.
It provides a strongly typed API contract between client and server, which is super safe to work with.
And it has a great set of rules for API evolution to ensure backward and forward compatibility.
Sounds pretty amazing, right? But is protocol-buffer required to work with gRPC?
The answer is NO. You can use Google flatbuffers or Microsoft bond instead. But in my opinion, protocol buffer is already a great choice.
It supports a lot of popular programming languages, with 10 officially supported, where Go, Java, NodeJS are purely implemented, and 7 others are wrappers of the gRPC core C, namely, C++, C#, Objective-C, Python, Ruby, Dart, and PHP.
Besides, there are many other unofficial libraries for other languages such as Swift, Rust, TypeScript, Haskell and so on.
Alright, now we know how gRPC generates codes for us. I hope you find it interesting.
In the next lecture, we will explore another secret weapon of gRPC: HTTP/2. See you then.