gRPC Learning Notes
1. Introduction to gRPC
gRPC It is a high performance, universal open source RPC framework designed by Google for mobile application development based on HTTP/2 protocol standards, based on ProtoBuf(Protocol Buffers) serialization protocol, and supports many development languages.
[External chain picture transfer failed, source may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-ErO385KK-16406221958) (C:Usersv_rwsnowguoDesktopGallerypic112Snipaste_2021-12-03_16-09-45.png)]
1.1 gRPC vs. Restful API
Both gRPC and restful APIs 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, whereas restful API does not). However, gRPC has some unique advantages, as follows:
- gRPC can define interfaces through protobuf, which allows stricter interface constraints.
- With protobuf, data can be serialized into binary encoding, which greatly reduces the amount of data that needs to be transmitted, thereby greatly improving performance.
- gRPC can easily support streaming communication (streaming mode is theoretically available through http2.0, but restful api for web services seems to be rarely used. Usually streaming data applications, such as video streaming, use special protocols such as HLS, RTMP, etc. These are not our usual web services, but have special server applications.)
1.2 Four types of service methods
-
A single RPC, in which the client sends a request to the server and gets a response from the server, is like a normal function call.
rpc SayHello(HelloRequest) returns (HelloResponse);
-
Server-side streaming RPC, where a client sends a request to a server to get a stream of data to read a series of messages. Clients read from the returned stream until no more messages are available.
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
-
Client-side streaming RPC, in which the client writes and sends a series of messages to the server using one of the data streams provided. Once the client finishes writing messages, it waits for the server to read them and return a reply.
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
-
Two-way streaming RPC, where both sides can send a series of messages through a read-write data stream. The two data flow operations are independent, so the client and the server can read and write in any order they want.
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
2. Protobuf
Protobuf is an open source serialization protocol framework developed by google, similar to XML,JSON, which uses protocol serialization for data storage and reading. Compared with XML, it is simpler to define data format, data access interface can be generated automatically, and developer development speed is accelerated
2.1 Installation
win Installation
pip install grpcio-tools reach https://github.com/protocolbuffers/protobuf/releases Download the corresponding installation package and protoc.exe placed under PATH
ubuntu installation
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest reach https://github.com/protocolbuffers/protobuf/releases Download the corresponding installation package and place the protoc under PATH
2.2 Generating code using protoc
# python protoc --python_out=. api.proto # go protoc --go_out=plugins=grpc:. api.proto
2.2 protobuf syntax
Using Message Definition (class), the field format is as follows
[rules][data_type] [data_name] = [number] [default = obj]
Rules: Rules that define the variable
- Required: required
- Optional: optional. If no optional field value is set, default is used
- Repeated: can be repeated any number of times, including zero times, similar to an array.
DataType: Data type
Common data types are int32, int64, float, double, bool, string, bytes
DataName: Field name
Number: Unique numeric identifier
Protobuf is a key-value format that maps member names to number s so that data can be serialized. Each data field has a unique numeric identifier. These identifiers are used to identify the binary format of the field in the message and the type in use should not be arbitrarily changed. It is important to note that identities within [1-15] take up only one byte of encoding, including identifiers and field types. Identifiers between [16-2047] take up two bytes.
Example
syntax = "proto2"; message Person { required int32 age = 1; required string name = 2; } message Family { repeated Person person = 1; }
3. grpc Project
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-2lagTcg3-16406221959) (C:\Usersv_rwsnowguo\DesktopGallerypic\112Snipa_2021-12-16_10-26-38.png)]
3.1 go.mod
module go-study go 1.17 require ( google.golang.org/grpc v1.42.0 google.golang.org/protobuf v1.27.1 ) require ( github.com/golang/protobuf v1.5.2 // indirect golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect golang.org/x/text v0.3.0 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect )
3.2 proto
shop.proto
syntax = "proto3";// Protocol is proto3 package proto; option go_package = "./"; // Define Send Request Information message ProdRequest { int32 prod_id = 1; // Commodity ID } // Define response information message ProdResponse { optional int32 prod_id = 1; repeated string prod_name = 2 ; // Commodity Name } // Define Services service ProdService { rpc GetProd(ProdRequest) returns(ProdResponse); }
Generate go file from proto file
protoc --go_out=plugins=grpc:./proto ./proto/shop.proto
3.3 service
ProdService.go
package service import ( "context" "fmt" ) import . "go-study/proto" type ProdService struct { } func (this *ProdService) GetProd(ctx context.Context, req *ProdRequest) (*ProdResponse, error) { prodId := req.GetProdId() fmt.Println("get--", prodId) prodNames := []string{"Tea with milk", "cola"} return &ProdResponse{ProdId: &prodId, ProdName: prodNames}, nil }
3.4 server
server.go
package main import ( db "go-study/proto" svr "go-study/service" "google.golang.org/grpc" "log" "net" ) const ( // Address listening address ADDRESS string = ":8081" // Network Work Network Communication Protocol NETWORK string = "tcp" ) func main() { // Listen on local ports lis, err := net.Listen(NETWORK, ADDRESS) if err != nil { log.Fatal("Net.Listen err: %v", err) } // New gRPC Server Instance server := grpc.NewServer() // Registration Services db.RegisterProdServiceServer(server, new(svr.ProdService)) err = server.Serve(lis) if err != nil { return } }
3.5 client
client.go
package main import ( ctx "context" "fmt" db "go-study/proto" "google.golang.org/grpc" "log" ) const ( // Address Connection Address Address string = "127.0.0.1:8081" ) func main() { conn, err := grpc.Dial(Address, grpc.WithInsecure()) //grpc.WithInsecure() Prohibit Secure Authentication Transport if err != nil { log.Fatalf("net.Connect err: %v", err) } defer conn.Close() // Establish gRPC connection client := db.NewProdServiceClient(conn) res, err := client.GetProd(ctx.Background(), &db.ProdRequest{ProdId: 12}) if err != nil { log.Fatal(err) } fmt.Println(res) }