The Guide to rump up on gRPC in Java
GRPC is an acronym for Google Remote Procedure Call. In this article, you are going to understand gRPC in Java pure. Once you control it, applying gRPC over SpringBoot, Quarkus or other framework technology will be easy. Bonus round for Python and JavaScript.
1. Architecture
To explain the architecture, the diagram below from wallarm.com beautifully describes the gRPC architecture
2. Why gRPC?
gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services. (), from grpc.io.
Microservices → It is designed for low latency and high throughput communication and also is great for lightweight microservices where efficiency is critical, from Microsoft.
Point-to-Point real-time communication → Has excellent support for bidirectional streaming. gRPC services can push messages in real-time without polling, from Microsoft.
Polyglot environment → gRPC tooling supports all popular development languages, making gRPC a good choice for multi-language environments, from Microsoft.
Network-constrained environments → Messages are serialized with Protobuf, a lightweight message format. A gRPC message is always smaller than an equivalent JSON message, from Microsoft.
Inter-process communication (IPC) → IPC transports such as Unix domain sockets and named pipes can be used with gRPC to communicate between apps on the same machine, from Microsoft.
3. gRPC disadvantages
Yes, gRPC has some downsides.
- gRPC requires special software on both the client and the server, from Cloud Google
- If you work with resource-constrained devices or environments, there may be better choices than gRPC. gRPC requires more processing power and memory than some other communication protocols, which can be a problem if you’re working with limited resources, from LinkedIn
- While gRPC supports multiple programming languages, it may not be the best choice for projects that require specific language features or libraries that are not supported by gRPC, from LinkedIn
- If your development team is not familiar with gRPC, it may not be the best choice for your project, from LinkedIn
- Since gRPC heavily relies on HTTP/2, you can’t call a gRPC service from a web browser directly, because no modern browsers can access HTTP/2 frames. So, you need to use a proxy, which has its limitations, from AltexSoft
- Messages are encoded with Protobuf by default. While Protobuf efficiently sends and receives, its binary format isn’t human-readable. Protobuf requires the message’s interface description specified in the
.proto
file to properly deserialize. Additional tooling is required to analyze Protobuf payloads on the wire and to compose requests by hand, from Microsoft.
4. Should I adopt gRPC?
Looking for the sections above requires a deeper analysis than jumping on the bandwagon. My opinion is no unless your team has experience and expertise on it. The adoption of REST is easy, and you can ship faster to production.
But looking at the scenario between gRPC and REST, an AWS may help you to choose or at least create a POC (Proof Of Concept) before the final decision.
5. Hands-on
Talk about the pros/cons, and it is always a great discussion, but let’s implement a simple service to see the gRPC in action.
5.1. Tech stack
- Java 17
- IntelliJ Ultimate
- Gradle 8
- gRPC
- JUnit5
- k6
- Postman
- Python
- JavaScript
5.1. Key concepts
All the references for the key concepts are from the Cloud Native website.
- Channel → A gRPC channel provides a connection to a gRPC server on a given host and port. Channels are used to create client stubs. The same channel can be used to connect to multiple services running on the same gRPC server.
- Client stub → gRPC supports two types of client stubs. Blocking/ synchronous stubs and asynchronous stubs. newBlockingStub() is used to make blocking calls while newStub() is used for non blocking calls
- StreamObserver → Service implementations and clients use StreamObservers with onNext(), onError() and onCompleted() methods to receive and publish message using gRPC framework. All service implementations extend <service name>Grpc.<service name>ImplBase classes that provide method signature to override
The expected time has arrived 🔥. To make it simple, let’s create a famous greeting service.
The service should demonstrate the simple use of gRPC receiving nothing as a parameter, receiving one type of parameter, and returning a single or a list of results. The filegreeting.proto
has this contract.
5.1. How our service should work?
- Create a file named
greeting.proto
declaring our service and methods. - Then, compile the
proto
to generate the skeleton - The consumer requires the
proto
file - Communication between the Consumer (client) and the Service is made using the
Protocolo Buffer Over HTTP/2
6. Projects
All the projects mentioned here are available on GitHub.
7. Files to create the gRPC service
7.1. greeting.proto
This is the most important file, where the contract is declared and all the work is surrounded.
Pay attention, this file will be shared among the projects.
7.2. build.gradle
7.3. GreetingMessageService
This class represents the implementation of the service. In order to make it easy, there is no database or any kind of integration outside this class.
7.4. Server (SimpleServer)
We have another version of the server, a fancy server. If you want to use it, visit the GitHub for more details.
The picture below shows the gRPC service running.
8. gRCP Clients
In this section you're going to see some flavors of clients, starting with Java, Python, and JavaScript (straightforward) implementation.
8.1. Proto file
You only need the contract, i.e., the proto file. In this article, we're going to create it using Java, Python, and JavaScript.
8.2. Java
The folder client has the gRPC client implementation. The build.gradle is configured to generate the client based on the proto file.
8.2.1. build.gradle
8.2.2. Java client
8.3. Python
8.3.1. requirements.txt
Required file to download the dependencies
8.3.2. Required step
The commands below are required to generate the client for Python. For more details, go to the GitHub.
pip install -r requirements.txt
pip install grpcio
pip install grpcio-tools
python3 -m grpc_tools.protoc -I./proto --python_out=./src --pyi_out=./src --grpc_python_out=./src greeting.proto