1. RPC
1.1 what & why need?
In a nutshell, RPC is the cornerstone of distributed systems .
RPC (Remote Procedure Call), the Chinese name is remote procedure call. It was first proposed by Xerox and defined as:
"RPC is a language-level communication protocol that allows a program running on a computer to call another address space using a certain channel as a communication medium ."
- In terms of type , RPC is a communication protocol;
- Functionally speaking , the function implemented by RPC is to call the address space of another machine on one machine, which may correspond to functions, variables, etc.;
- In terms of implementation means , RPC needs to use the transport layer in the computer network to realize pipeline communication. The pipeline communication at the transport layer can be understood as determining the two ends of the communication pipeline through IP addresses and port numbers.
With the development of the Internet, the "client-server-database" monolithic architecture (Monolithic Architecture) can no longer meet the increasingly complex business logic and increasing business access, so it is necessary to turn to the Microservices Architecture (Microservices Architecture). The following is the definition of microservices in Google Cloud Platform:
Microservice architecture (often shortened to microservices) refers to a form of architecture used to develop applications. Microservices allow a large application to be decomposed into independent components , each with its own area of responsibility. When processing a user request, a microservice-based application may call many internal microservices to collectively generate its response.
According to the above definition, for a request in the microservice architecture, each service needs to call each other to finally generate a corresponding response, so the call between services becomes a key issue. And RPC can just solve this problem, so some people say "If you want to understand microservices, you must first get RPC" . Adding a suitable RPC framework to the microservice architecture can not only reduce the development cost of the microservice architecture, but also improve the call efficiency between services.
2. gRPC
2.1 A general open source framework
The Chinese version of gRPC official documentation: Open Source China . It seems that it has not been updated for a long time, please refer to docs for the latest English documents .
gRPC, originally developed by Google , is a language-neutral, platform-neutral, open source remote procedure call (RPC) system. gRPC is designed based on the HTTP/2 standard , bringing features such as bidirectional flow, flow control, header compression, and multiplexing requests on a single TCP connection. These features make it perform better on mobile devices , saving power and space. According to grpc.io , the framework currently supports multiple languages, including Java, C#, Go, C++, Dart, Python, Kotlin, PHP, Ruby, Objective-C, and Node.
2.2 Configure the gRPC environment
- Configure the gRPC core library in go.mod (will be placed
$GOPATH/pkg
in )
$ go get google.golang.org/grpc
- Download the code generation plugin for the corresponding language (will be placed
$GOPATH/bin
in )
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
3. Golang realizes simple RPC service
3.1 Write proto file and generate corresponding Go code
Partial syntax of proto file
service
service name {rpc
rpc method name (request message)returns
(response message) { } }message
message name { variable type variable name = position in the message; }
Write the server.proto file, the declaration syntax proto3
is service
similar to that in Go func
, message
similar to that in Go struct
. rpc
Indicates that ShakeHands is an RPC method that accepts requests ShakeReq
and returns results ShakeRes
.
syntax = "proto3";
option go_package = ".;service"; // 生成的.go文件在哪个目录的哪个包下(用;隔开 目录;包名)
service ShakeHands {
rpc ShakeHands(ShakeReq) returns (ShakeRes) {
}
}
message ShakeReq {
string requestName = 1; // 这是在定义变量在 message 中的位置
}
message ShakeRes {
string responseMsg = 1;
}
Then enter the directory where the proto file is located and execute the protoc command.
$ cd path/to/proto/file
$ protoc --go_out=. server.proto
$ protoc --go-grpc_out=. server.proto
The generated files are as follows, –go_out indicates .pb.go
the directory location of the file output, and –go-grpc_out indicates _grpc.pb.go
the directory location of the file output.
3.2 Realize the server code
The main process is as follows:
- Implement
_grpc.pb.go
the services (or RPC methods) defined in the file. - Open the TCP port.
- Create a gRPC service and register the implemented service in the gRPC service.
- Start the gRPC service.
package main
import (
"context"
"fmt"
"net"
"google.golang.org/grpc"
pb "gRPC/server/proto"
)
type server struct {
pb.UnimplementedShakeHandsServer
}
func (s *server) ShakeHands(ctx context.Context, req *pb.ShakeReq) (res *pb.ShakeRes, err error) {
return &pb.ShakeRes{
ResponseMsg: "res: hello!" + req.RequestName}, nil
}
func main() {
listen, _ := net.Listen("tcp", "127.0.0.1:9999") // 开启tcp端口
grpcServer := grpc.NewServer() // 创建grpc服务
pb.RegisterShakeHandsServer(grpcServer, &server{
}) // 在grpc服务中注册我们的服务
err := grpcServer.Serve(listen) // 启动服务
if err != nil {
fmt.Println("server error!")
return
}
}
3.3 Client without security authentication
The logic of the client is very simple, which is to establish a connection with the server:
- Dial and initiate a connection.
grpc.Dial()
IP address and port of the server; _grpc.pb.go
Create a client instance through the method provided by the file;- Call the RPC method to initiate the request.
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "gRPC/server/proto"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:9999", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Println("connection error!")
}
defer conn.Close()
client := pb.NewShakeHandsClient(conn) // 建立连接
resp, err := client.ShakeHands(context.Background(), &pb.ShakeReq{
RequestName: "test"})
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(resp.GetResponseMsg())
}