gRPC Microservice Communication

Damindu Lakmal
3 min readNov 29, 2024

--

gRPC is a modern Remote Procedure Call (RPC) framework that has high performance. It can communicate with services while having load balancing, tracing, health checking and authentication. It is capable of distributed computing to connect devices, mobile applications and browsers to backend services.

RPC behave same as in local function call and remote call so it’s location transparent. RPC has an interface for client and server. RPC code generator tool has ability to create server and client stub. Stub takes care of the implementation.

RPC communication

Here you can see the client communication with server. As a developer, you need to pick appropriate framework for communication. API should be define by using IDL (Interface Description Language).

Why RPC

Let’s discuss benefits of RPC,

  1. Easy communication like a method call
  2. Client and server communication is abstract
  3. Failure return as error or exception depending on the programming language
  4. Suitable for internal communication (backend services)
  5. Define API contract easily by using IDL (protobuf)
  6. Multiple function executions with in single connection

Try gRPC

In here, I’ll describe, how to handle gRPC in golang services.

Protobuf

Let’s define our contract in proobuf,

syntax = "proto3";

package myservice; // Add package declaration

// Add this line to specify the Go package path
option go_package = ".";


service CustomCalculator {
rpc Calculate (Input) returns (Output);
rpc Multiply (Input) returns (Output);
}

message Input {
int32 num_1 = 1;
int32 num_2 = 2;
}

message Output {
int32 result = 1;
}

This has two functions,

  • Calculate : input two integers and output the sum of two values
  • Multiply : input two integers and output the multiply of two values

run below command after installing protoc

protoc --go_out=. --go-grpc_out=. contract.proto

Two files should be generated with .pb.go suffix. Those are auto generated files with unimplemented interfaces.

Server

Server has responsibility to execute above two functions and return the result when client requested. Create server.go file in server directory as below,

package main

import (
"context"
"log"
"net"

pb "github.com/HADLakmal/go-RPC/protobuff"

"google.golang.org/grpc"
)

type server struct {
pb.UnimplementedCustomCalculatorServer
}
// Addition implementation goes here
func (s *server) Calculate(ctx context.Context, req *pb.Input) (*pb.Output, error) {
return &pb.Output{Result: req.Num_1 + req.Num_2}, nil
}
// Multiplication implementation goes here
func (s *server) Multiply(ctx context.Context, req *pb.Input) (*pb.Output, error) {
return &pb.Output{Result: req.Num_1 * req.Num_2}, nil
}

func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

grpcServer := grpc.NewServer()
pb.RegisterCustomCalculatorServer(grpcServer, &server{})
log.Println("Server is running on port 50051")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

execute below cmd to generate go mod files,

go mod tidy

Calculate and Multiply functions implementation are described in here. Below command start the server then listen into 50051 port.

go run server.go

Client

Client connect to the server for execute both functions with in single RPC connection.

note : grpc-server is refers in docker communication. use localhost when you are run code without using docker

Create client.go file in client directory as below,

package main

import (
"context"
"log"
"time"

pb "github.com/HADLakmal/go-RPC/protobuff"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

func main() {
conn, err := grpc.NewClient("grpc-server:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()

client := pb.NewCustomCalculatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

res, err := client.Calculate(ctx, &pb.Input{Num_1: 4, Num_2: 3})
if err != nil {
log.Fatalf("could not calculate: %v", err)
}
log.Printf("calculate result: %d", res.Result)

res, err = client.Multiply(ctx, &pb.Input{Num_1: 4, Num_2: 3})
if err != nil {
log.Fatalf("could not multiply: %v", err)
}
log.Printf("multiply result: %d", res.Result)
}

execute below cmd to generate go mod files,

go mod tidy

Execute following command,

go run client.go

Output should be as follows,

calculate result: 7
multiply result: 12

I have added docker implementations in code base. You can understand that can be easily implement in distributed environments as a micro services.

github : https://github.com/HADLakmal/go-RPC

Summary

gRPC client and server implementation is briefly explain in here. By following the steps outlined in this document, you can understand the fundamental about communication.

--

--

Damindu Lakmal
Damindu Lakmal

No responses yet