arrowBACK
1/5/2022Python

Why you should consider gRPC

Michał SipaMichał Sipa
8 min read
Why you should consider gRPC
gRPCBackendMicroservices
facebooktwitterlinkedin
Why you should consider gRPC
As a developer, you may start a small project with a monolith architecture using one of the many well-known frameworks. That’s a good start because it allows you to prototype fast and quickly respond to business needs. It sounds like a startup, doesn’t it?

You work on the project with your colleagues and it grows. The business is happy and has great plans for the project.

The problem with that is businesses don’t usually know anything about architecture. They shouldn’t necessarily need to — that’s your job!

Adding more and more functionalities doesn’t help the whole monolith architecture. You can try your best to keep the code neat and tidy but by adding new features to the project, it eventually becomes too much for the supposed-to-be small project.

Going forward, the decision has to be made to split the monolith into microservices. And that’s fine, everyone is trending towards microservices these days.

What is gRPC?

gRPC is an open-source 👍 , modern 👍 , high performance 👍 framework that was designed by Google to connect its data centers over a decade ago.

It’s okay if you don’t have data centers — you can use them to communicate with any services. Not only microservices, but also mobile, web, IoT, or even libraries.

By design, it is fast, compact, and scalable. It is language-agnostic, which means you can easily connect services written in different languages. All you need are defined procedures and messages for services. The rest, like implementations of clients, servers, and serialized data you get for free. They are generated by the gRPC scripts for your languages of choice. You just need to utilize them and implement what they are doing.

So, are we making contracts between clients and servers like in GraphQL, and no other communications are allowed? Pretty much! We are defining beforehand exactly what your services are offering and the exact messages for the communications. You don’t have to construct many REST endpoints, we just call a direct method on the client side. Sounds great, right?

Let me show you some other cool stuff.

Things you may like

Service definitions

So, as mentioned before, a Remote Procedure Call looks like a standard method to a developer, but underneath it’s calling a different service to do something and return the response. Code examples are best to illustrate the basic concepts — a basic example could look like this:
syntax = "proto3

service UserStore {
  rpc GetUserDataByEmail(UserEmailRequest) returns (UserResponse);
}

message User {
  string email = 1;
  string firstname = 2;
  string lastname = 3;
}

message UserEmailRequest {
  string email = 1;
}

message UserResponse {
  User user = 1;
  string error = 2;
}

Let me explain step by step what we are doing here.

As you can see from the first line, this is a proto3 file. This format is used for defining methods and serializing messages. More on that subject later.

Next, we have the service definition UserStore. Let’s assume this is the service that holds all the information of our users. For now, we have only one unary (request -> response) RPC method which is called GetUserDataByEmail. It expects a request message UserEmailRequest and will return the message UserResponse.

Ok, so far so good. You can also see that we can build more complex messages with it. Like the UserResponse is defining one of the fields as a User message. That’s correct, this is a feature of a protobuf which is quite powerful and is a whole other topic.

So we have definitions. What next?

Now we need to somehow access this RPC method in our application. To do that, we use a protocol buffer compiler to generate code for clients and servers. It might look like this:

python -m grpc_tools.protoc -I../../protos — python_out=. — grpc_python_out=. ../../protos/user_store.proto

As I said before, gRPC is language agnostic and offers tools for almost every popular language. This one is for Python. You will need to generate this for each language that you use.

This compiler will generate two files for python:

  • user_store_pb2.py — which contains generated classes for request and response messages
  • user_store_pb2_grpc.py — which contains generated client and server classes.

All you need to do now is import and use them — like this:

Client:

import grpc
from protos.user_store_pb2 import User, UserResponse, UserEmailRequest,
from protos.user_store_pb2_grpc import UserStoreStub


def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = _pb2_grpc.UserStoreStub(channel)
        response = stub.GetUserDataByEmail(
            UserEmailRequest(email="user@example.com")
        )
        print(f"response user: {response.user}")

if __name__ == '__main__':
    logging.basicConfig()
    run()

Server:

import grpc

from protos.user_store_pb2 import User, UserResponse, UserEmailRequest,
from protos.user_store_pb2_grpc import UserStoreServicer


class UserStoreServicer(UserStoreServicer):
    def GetUserDataByEmail(self, request: UserEmailRequest, context):
        user = … # your code for fetching the user data
        return UserResponse(
            user=User(
                email=user.email,
                firstname=user.firstname,
                lastname=user.lastname
            )
        )

Protobufs

So far, this looks fairly easy — but why do we use protobufs? (here’s the next great thing) you don’t have to!

gRPC was designed to be not only language agnostic, but also encoding! gRPC is not a monolithic framework. You can swap out some things if you want. You can use JSON or XML for messaging if you prefer. Meanwhile, let me inform you of the benefits of using protobufs.

They are compact. Especially in comparison to JSON or XML, they’re really compact. Let’s compare how many bytes will be needed for the same information for those three data types.

Invalid url, please try another

If you are sending IDs only, this makes a huge difference.

But size is not the only thing. Protobufs have many features that are beneficial. To name a few:

  • Protobuf fields may be marked as deprecated. This will greatly improve the way of working with multiple teams or services.
int32 old_field = 6 [deprecated = true];
  • You can define enums and use them as possible values for fields. Or even map all messages to the JSON if you need.
  • Built-in serialization
  • Typing

And many more.

One important thing to remember! In Protobuf3 (the latest one), every field in the message is optional. This means you don’t always have to populate all defined fields. They will receive default values set to them like empty strings, e.g., 0, False, or so.

This is important considering the older version, Protobuf2, was the exact opposite. You needed to mark each field as ‘optional’ if needed.

You can find more on protobufs here.

Synchronous or Asynchronous

All this sounds fine, but our example, GetUserDataByEmail, looks like a synchronous call. We send a request and we wait for a response. This is correct. But it doesn’t mean that it is synchronous only. It can be used asynchronously if you want. This is closely connected to the language you are using but is possible.

Life cycles

Are there other possible communication types other than unary request -> response?

In short, yes. We have everything you might need.

Unary

This one we already know. The client sends a request and waits for a response. Basic stuff.

Server streaming

This is more complex but also well known. The client sends a request and in return gets a stream of messages. Useful if you are writing an application and want some progress bars for actions, e.g., streaming music or video.

Client streaming

Same as before but from the client side. The client sends a stream of messages to the server.

Bidirectional streaming

This is new — you can now define the bidirectional communication of streams. They are independent of each other so the client and server can send messages in any order.

Timeouts and canceling

Like any other communication system, you can define a timeout for responses. This is also independent of clients and servers. You can define it according to your needs. You can even cancel and RPC at any time. Keep in mind that this will not roll back anything and this feature needs to be implemented by you in the application itself.

But how is that possible, I hear you ask? What kind of sorcery is that?

Well, it’s not sorcery for sure!

Underneath, gRPC is using the newer HTTP2 transfer protocol instead of using the previous HTTP1.1. Thanks to HTTP2, we can send binaries instead of text (HTTP1.1) to support the handling of multiple requests at the same time. This standard is still new and you can find more on that here.

Things you may not like

Everything comes at a cost and we were waiting for that!

Unfortunately, as with many solutions, this also has some cons that you should be aware of.

It’s still fairly young

gRPC is widely used by many large companies such as Netflix, Spotify, and Cisco but is still quite new for most developers. You may spend some time looking for best practices, learning about protobufs, or searching for examples or workarounds. However, this is changing and more and more information is becoming available.

Tools are still emerging

Early-stage tech normally means that the tools for it are even younger. Although a lot has been done already, you don’t really need them, but here is an awesome gRPC list on GitHub anyway.

Binaries

Its biggest advantage is also its biggest flaw. It’s hard to debug a message when you need to decode it first. There are tools for that, but you need to learn how to use them first.

Browser support

It is coming, but not there yet.

Learning stuff

Your team and you will need to learn new technology. Unfortunately, there is no workaround for that.

Conclusion

So, should you use gRPC in your project? Well, in truth, the answer is not that simple. If you have streaming services, big data centers, or if you want easy asynchronous communication with your microservices, then probably yes. You should take a closer look at gRPC and try to adopt it into your project. The benefits are there and have solid grounds. If your project is not that demanding, then I still think you should be aware of it or even maybe try to use it in some parts. This tech may be the next ‘big’ thing!

Mirumee guides clients through their digital transformation by providing a wide range of services from design and architecture, through business process automation to machine learning. We tailor services to the needs of organizations as diverse as governments and disruptive innovators on the ‘Forbes 30 Under 30’ list.

Learn more about who we are and what we do. Have a look through the open positions here and become a part of our team.

Let’s engineer great products and systems together

Have a particular project in mind? Contact us to help you transform your ideas into a unique end-to-end product.
Let's talk