Use of gRPC and Protobuf for golang microservices

  • 2020-10-07 18:43:51
  • OfStack

What is RPC?

The so-called RPC(remote procedure call remote Procedure Call) framework actually provides a set of mechanisms that allow applications to communicate with each other and also follows the server/client model. When used, the client calls the interface provided by the server side as if it were calling the local function 1.

What is gRPC?

Like many RPC systems 1, gRPC is based on the idea of defining a service and specifying methods that can be invoked remotely using its parameters and return types. By default, gRPC USES the protocol buffer as the Interface Definition Language (IDL) to describe the structure of the service interface and payload messages.

What are the benefits of gRPC and in what scenarios do you need gRPC

Since it is server/client model, isn't it possible for us to use restful api directly? Why do we need RPC? Here's a look at some of the advantages of RPC

gRPC vs. Restful API

Both gRPC and restful API provide a set of communication mechanisms for server/client model communication, and both use http as the underlying transport protocol (strictly speaking, gRPC USES http2.0, while restful api does not). However, gRPC has some unique advantages, as follows:

gRPC can define interfaces through protobuf, allowing for more stringent interface constraints. For more information about protobuf, see my previous tutorial Google Protobuf
In addition, with protobuf, you can serialize the data to 2-base encoding, which dramatically reduces the amount of data that needs to be transmitted, thus greatly improving performance.
gRPC can easily support streaming communication (in theory by http2. 0 streaming model can be used, but usually web service restful api seems seldom use, so usually streaming data applications such as video streaming, 1 kind is to use special protocol such as HLS RTMP, such as these, it is not we usually web service, but have a dedicated server application.)

Usage scenarios

Strict constraints of the interface, we provides a public service, for example, many people, even outside the company people can access the service, then we hope to have more strict constraint for interface, we don't want the client to send us any data, especially considering the safety factor, we usually need the interface more strict constraints. gRPC can then provide strict interface constraints through protobuf. When there is a higher requirement for performance. Sometimes our service need to pass a large amount of data, and hope does not affect our performance, this time also can consider gRPC service, because by protobuf we can convert data compression coding to 2 hexadecimal format, usually a much smaller amount of data, and through http2 we can realize the asynchronous request, thus greatly improving the efficiency of communication.

However, we usually do not use gRPC alone, but use gRPC as a component, because in a production environment where we face large concurrency, we need to use a distributed system for processing, and gRPC does not provide the necessary components associated with a distributed system. Moreover, a true online service needs to provide the necessary components including load balancing, current limiting fuses, monitoring alarms, service registration and discovery. That's outside the scope of this article, though, so let's move on to looking at how to use gRPC.

The use of gRPC generally consists of the following steps

Use protobuf to define interfaces and data types Write gRPC server terminal code Write gRPC client side code

The installation of protobuf

mac: brew install protobuf

windows: protoc Download: official address, then add the bin path to the path environment variable

linux:

Install the required dependency packages:


[root@localhost ~]# yum -y install autoconf automake libtool curl make g++ unzip 
[root@localhost ~]# unzip protobuf-master.zip 
[root@localhost ~]# cd protobuf-master 

The script file that generates the configure file. If you do not do this, the following actions will fail


[root@localhost protobuf-master]# ./autogen.sh 
[root@localhost protobuf-master]# ./configure 

You can modify the installation directory through the./configure --prefix= command, series 1 is installed under /usr/local/protobuf


[root@localhost protobuf-master]# ./configure --prefix=/usr/local/protobuf 
[root@localhost protobuf-master]# make
[root@localhost protobuf-master]# make check
[root@localhost protobuf-master]# make install 
[root@localhost protobuf-master]# ldconfig # refresh shared library cache. 

Successful installation


[root@localhost protobuf-master]# protoc -I=./ --cpp_out=./ test.proto

Install grpc package


go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u google.golang.org/grpc
protoc --go_out=plugins=grpc:. *.proto

Define interfaces and data types


syntax = "proto3";

package rpc_package;

// define a service
service HelloWorldService {
 // define the interface and data type
 rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// define the data type of request
message HelloRequest {
 string name = 1;
}

// define the data type of response
message HelloReply {
 string message = 1;
}

Use the protobuf generation tool to generate library functions for the corresponding language


protoc --go_out=plugins=grpc:. helloworld.proto

server.go


// server.go
 
import (
 "log"
 "net"
 
 "golang.org/x/net/context"
 "google.golang.org/grpc"
 pb "helloworld/helloworld"
)
 
const (
 port = ":50051"
)
 
type server struct {}
 
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
 return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
 
func main() {
 lis, err := net.Listen("tcp", port)
 if err != nil {
  log.Fatal("failed to listen: %v", err)
 }
 s := grpc.NewServer()
 pb.RegisterGreeterServer(s, &server{})
 s.Serve(lis)
}

client.go


package main
 
//client.go
 
import (
 "log"
 "os"
 
 "golang.org/x/net/context"
 "google.golang.org/grpc"
 pb "helloworld/helloworld"
)
 
const (
 address  = "localhost:50051"
 defaultName = "world"
)
 
func main() {
 conn, err := grpc.Dial(address, grpc.WithInsecure())
 if err != nil {
  log.Fatal("did not connect: %v", err)
 }
 defer conn.Close()
 c := pb.NewGreeterClient(conn)
 
 name := defaultName
 if len(os.Args) >1 {
  name = os.Args[1]
 }
 r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
 if err != nil {
  log.Fatal("could not greet: %v", err)
 }
 log.Printf("Greeting: %s", r.Message)
}

Above is golang micro service gRPC and Protobuf use details, more information about golang gRPC and Protobuf please pay attention to other related articles on this site!


Related articles: