gRPC Microservice Communication
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.
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,
- Easy communication like a method call
- Client and server communication is abstract
- Failure return as error or exception depending on the programming language
- Suitable for internal communication (backend services)
- Define API contract easily by using IDL (protobuf)
- 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.