Golang gRPC overview and getting started example

1. Overview

1.1 what is gRPC

The full name of RPC is Remote Procedure Call. RPC is a kind of protocol. It actually provides a set of mechanisms to enable applications to communicate, and it also complies with the server/client model. When used, the client invokes the interface provided by the server, just like calling a local function.

And what is gRPC? In official terms:

A high-performance, open-source universal RPC framework

gRPC is a high-performance, open source and general RPC framework.

In gRPC, we call the caller client and the callee server. Like other RPC frameworks, gRPC is also based on the idea of "service definition". Simply speaking, we describe a service in a certain way, which is language independent. In the process of "service definition", we describe the service name of the service we provide, which methods can be called, what input parameters these methods have, and what back parameters they have.

In other words, after these services and methods are defined, gRPC will mask the underlying details. Clients only need to call the defined methods directly to get the expected return results. For the server side, we also need to implement the methods we defined. Similarly, gRPC will also help us shield the underlying details. We only need to implement the specific logic of the defined method.

You can find that in the above description, the so-called "service definition" is very close to defining the semantics of the interface. I prefer to understand that this is a "Convention". Both parties agree on the interface, then the server implements the interface, and the client calls the proxy object of the interface. As for other details, let gRPC do it.

In addition, gRPC is language independent. You can use C++ as the server and Golang, Java, etc. as the client. To achieve this, we should be language independent in the process of "defining services" and encoding and decoding.

The following figure shows a typical RPC structure diagram.

From the above figure, you can see that gRPC uses Protocol Buffers. This article will not expand on Protocol Buffers (see: Golang uses Protobuf ), you can think of it as a code generation tool and a serialization tool. This tool can convert our defined methods into language specific code. For example, if you define a type parameter, it will help you convert it into a struct structure in Golang. If you define a method, it will help you convert it into a func function. In addition, when sending a request and receiving a response, the tool will also complete the corresponding encoding and decoding, encode the data you are about to send into a form that gRPC can transmit, or decode the data you are about to receive into a data format that the programming language can understand.

1.2 usage scenarios

  1. Distributed system with low delay and high availability;
  2. Communication between mobile terminal and cloud server;
  3. protobuf, a language independent protocol, supports communication between multiple languages;
  4. It can be extended hierarchically, such as authentication, load balancing, logging, monitoring, etc;

1.3 comparison between grpc and RESTful API

Characteristics gRPC  RESTful API
standard must. proto  Optional OpenAPI
agreement HTTP/2 any version of HTTP protocol
Payload Protobuf (small, binary) JSON (large and easy to read)
Browser support No (grpc web required) yes
Streaming Client, server, bidirectional Client and server
code generation Yes OpenAPI + third party tools

2. Environment configuration

2.1 install and configure protocol buffers and protocol Gen go

Refer to the following steps: Installing and configuring Protocol Buffers on Mac

2.2 get gRPC

go get google.golang.org/grpc

This step installs the core library of gRPC.

2.3 obtain the protocol Gen go grpc

go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Install the protocol Gen go grpc for proto-->***_ grpc. pb. go.

3. Getting started with gRPC example

Before we start development, let's talk about our goals.

In this grpc practice project, I want to implement a function. The client can send messages to the server, and the server will return a response to the client after receiving the message.

The project structure is as follows:

Note: This is the structure of all files of the whole project after they are generated proto and go files are generated in 3.1 and subsequent steps. go The contents of mod are as follows:

module grpc-practice

go 1.17

require (
	google.golang.org/grpc v1.46.2
	google.golang.org/protobuf v1.28.0
)

require (
	github.com/golang/protobuf v1.5.2 // indirect
	golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
	golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
	golang.org/x/text v0.3.3 // indirect
	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
)

3.1 defining services

As mentioned earlier, we need to define services before developing server and client. Here, paste the contents of the sample proto file directly.

# File path grpc practice / PKG / proto / message proto

syntax = "proto3";
// The content of this section is about the directory and package in which the last generated go file is located/ pb represents the generation in the pb directory at the upper level of the current directory, and message represents the package name of the generated go file is message.
option go_package = "../pb;pb";

message MessageResponse {
  string responseSomething = 1;
}

message MessageRequest {
  string saySomething = 1;
}

service MessageSender {
  rpc Send(MessageRequest) returns (MessageResponse) {}
}

It is easy to see that we have defined a service called MessageSender, which has an rpc method named Send. This method will Send a MessageRequest and then return a MessageResponse.

Then execute the following command in the grpc practice / PKG / proto Directory:

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

These two commands will generate message pb. go,message_grpc.pb.go these two files. These two files contain the go language implementation of the methods we define, as well as the requests we define and the corresponding go language implementation.

In short, the protocol Gen go has defined the language independent message Proto is converted to go code for direct use by server and client.

Note: in some online tutorials, there are such generation methods:

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

This generation method uses the github version of the protocol Gen go, and the project has been taken over by Google. In addition, if this generation method is used, the XXX in the above figure will not be generated_ grpc. pb. Go and xxx pb. Go two files, only generate xxx pb. Go this file.

3.2 server

3.2.1 method of realizing service definition

# File path grpc practice / PKG / serviceimpl / messagesenderserverimpl go

package serviceImpl

import (
	"context"
	"grpc-practice/pkg/pb"
	"log"
)

type MessageSenderServerImpl struct {
	*pb.UnimplementedMessageSenderServer
}

func (MessageSenderServerImpl) Send(context context.Context, request *pb.MessageRequest) (*pb.MessageResponse, error) {
	log.Println("receive message:", request.GetSaySomething())
	resp := &pb.MessageResponse{}
	resp.ResponseSomething = "roger that!"
	return resp, nil
}

It is easy to see that MessageSenderServerImpl implements the MessageSenderServer interface and implements the definition. In other words, this part requires us to implement the send method on the Server side.

Note that "implement defined method" does not mean that we need to create a method with the same name, but that we need to create a method with the same function signature. In other words, the same input and output parameters are required.

3.2.2 gRPC server registers defined services and listens

# File path grpc practice / PKG / service / main go

package main

import (
	"google.golang.org/grpc"
	"grpc-practice/pkg/pb"
	"grpc-practice/pkg/serviceImpl"
	"log"
	"net"
)

func main() {
	srv := grpc.NewServer()
	pb.RegisterMessageSenderServer(srv,serviceImpl.MessageSenderServerImpl{})
	listener, err := net.Listen("tcp", ":8002")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	err = srv.Serve(listener)
	if err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

It is easy to see that we created a grpcServer in this part and registered our Service. In the second parameter of the registration function, we passed in a MessageSenderServerImpl instance.

The listening process is very similar to the web server of golang. It also creates a Handler, listens to the port, listens to the TCP connection of port 8002, and then starts the server.

So far, the server has been developed.

3.3 client

In the client side, we should establish a connection with the server side before we can call various methods.

# File path grpc practice / PKG / client / main go

package main

import (
	"context"
	"google.golang.org/grpc"
	"grpc-practice/pkg/pb"
	"log"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:8002",grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewMessageSenderClient(conn)
	resp, err := client.Send(context.Background(), &pb.MessageRequest{SaySomething: "hello world!"})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Println("receive message:", resp.GetResponseSomething())
}

The above code is to establish a connection with the local 8002 port. Then, create a client locally, and directly call the Send method we defined before to realize the logic we need. Calling the method of the server section is as convenient as calling the local method.

Simply put, we are in * The method is defined in the proto file, and then the specific logic of the defined rpc method is implemented on the server side and called on the client side.

For other parts, the proto buffer is responsible for converting the data structure stored in Golang to the data in rpc transmission, and grpc is responsible for encapsulating all logic.

When both the server and client are running, you will see this picture:

 

So far, the gRPC example is successful.

reference resources: https://zhuanlan.zhihu.com/p/258879142

Tags: Go

Posted by scorphus on Wed, 01 Jun 2022 22:00:38 +0530