Introduction to gRPC

Photo by Clark Tibbs on Unsplash

Introduction to gRPC

gRPC with Protocol Buffers, API Lifecycle and Architecture

ยท

5 min read

What is gRPC?

gRPC is an open-source framework for building fast and efficient remote procedure calls. It is widely used to communicate between microservices, client-server applications, and distributed systems.

As in many RPC systems, gRPC is based on the idea of defining a service and specifying the methods that can be called remotely with their parameter and return types.

On the server side, the server implements this interface and runs a gRPC server to handle client calls. On the client side, the client calls the same methods on a stub as it would for a local object.

Concept Diagram

gRPC works in a variety of environments and languages, so I can create a gRPC server in Java with clients in Go, Python, or Ruby.

Protocol Buffers

Protocol Buffers is a method for serializing structured data. It is used for data storage and communication between applications and services. They have many advantages compared to XML or JSON such as fast serialization and deserialization, reduced message size and it is language agnostic.

To work with protocol buffers, the first step is to create a .proto file which contains the data you want to serialize.

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

After this, you can run the protocol buffer compiler protoc with a special gRPC plugin to generate gRPC client and server code, as well as data access classes in the preferred language from this proto file. These classes can then be used in the application to populate, serialize, and retrieve protocol messages. Similarly, you can define services with method parameters and return types specified as protocol buffer messages.

Service Definition

By default, gRPC uses protocol buffers as the Interface Definition Layer (IDL) for describing the service interface and the structure of the payload messages, it is possible to use alternatives, if desired.

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

There are four kinds of service methods:

  • Unary RPCs where the client sends a single request and gets back a single server response, just like a normal function call.

      rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • Server Streaming RPCs where the client sends a single request and gets back a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. The ordering is guaranteed by gRPC within an individual RPC call.

      rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • Client streaming RPCs where the client writes a sequence of messages and sends them to the server. Once the client finishes sending the messages, it waits for the server to read them and send a response back. The message ordering is again guaranteed.

      rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • Bidirectional streaming RPCs where both client and server send a sequence of messages using a read-write stream. The two streams are independent, so the client and server can read and write in any order. For example, the server can wait to receive all the messages from the client or it can alternatively read a message then write a message or some other combination. The order in each stream is preserved.

      rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

RPC Lifecycle

Let's have a closer look at what happens when a gRPC client calls a gRPC server method.

Unary RPC

The client sends a single request and the server gives back a single response. Once the client calls the stub method, the server is notified with the client's metadata, the method name, and the specified deadline. The server then either waits for the client's request message or immediately sends back its own initial metadata. Once the server has the client's request message. it reads and processes it and sends it back to the client via the server response, with status details and optional trailing metadata. If the response status is OK, then the client gets the response and this marks the completion of the call on the client side.

Server streaming RPC

It's similar to the Unary RPC, the difference is just that the server instead of a single response message sends a stream of messages. After sending all the messages, the server sends the status details and optional trailing metadata. This completes processing on the server side. The client-side finishes when it receives all the messages.

Client streaming RPC

It's similar to the Server streaming RPC, but here the client sends a stream of request messages to the server and the server responds with a single message (along with its status details and optional trailing metadata) typically, but not required, after reading all the messages.

Bidirectional streaming RPC

Also similar to the Unary, the call is initiated by the client by invoking the method name and the server receives the client's metadata. Since the streams are independent the developer can choose to work with them however they wish, meaning, the server can either read all the messages from the client and then respond or do something called "ping-pong", each of them sending and receiving one message at a time. They way the streams are handled is application-specific.

Deadlines/Timeouts

gRPC clients can set a deadline (i.e. fixed point in time after which the request is canceled) or a timeout (i.e. duration after which the request is canceled) on the RPC call after which the call is terminated with a DEADLINE_EXCEEDED error. The server can also query if the call is timed out or how much time is left.

Cancelling an RPC

Either client or server can cancel the RPC at any time and it happens immediately so that no extra work is done. The changes made before a cancellation are not rolled back.

Metadata

It's in the form of a list of key-value pairs, where the keys are strings and values are typically strings but can be binary. They can contain authentication details or some User-defined information.

Channels

A gRPC channel provides a connection to the gRPC server on a specified host and port. Clients can configure the default behavior such as setting compression on or off. A channel has a state, including connected and idle. Closing and querying the channels is language-dependent.

That's all about the important gRPC concepts and theory. In the next article, we will build client and server applications in Golang that will communicate over gRPC.

I am sure you all are as excited as I am, see you at the next one! ๐Ÿš€

Follow me on Twitter: https://twitter.com/prakhar_a_1
Follow me on Linkedin: https://www.linkedin.com/in/prakhar-agarwal-byte/

ย