RPC:即远程过程调用,能像调用本地一样调用远程方法。相比传统的http请求,rpc请求报文体积更小、传输效率更高,使用了HTTP2协议,跨平台等优点。rpc更侧重于内部调用,http主要侧重于对外、接口、第三方调用等。 Protocol Buffers:一种开源的、跨平台的二进制结构的协议。rpc调用过程中的传输协议,用于解析、传输、生成远程调用中的数据结构的字节流。相比json、xml等文本格式,protocol buffers由于是二进制流文件,会更加高效。
目前主流的rpc框架对比:
简单模式 (Simple RPC):就是简单模式,类似于常规的 http 请求,客户端发送请求,服务端响应请求。 流程图:
服务端流式(Server-side streaming RPC):客户端发送一个请求到服务端,服务源源不断的返回数据流给客户端,直到服务端关闭。 流程图:
客户端流式(Client-side streaming RPC):与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。 流程图:
双向流式(Bidirectional streaming RPC):双方使用读写流去发送一个消息序列,两个流独立操作,双方可以同时发送和同时接收。 应用场景: 流程图:
go install google.golang.org/grpc@latest
下载地址:https://github.com/protocolbuffers/protobuf/releases/tag/v21.5
安装protoc-gen-go插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
安装protoc-gen-go-grpc插件:
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
检测protoc
❯ protoc --version
libprotoc 3.21.5
检测protoc-gen-go-grpc:
❯ protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.2.0
调用流程图:
syntax = "proto3";//声明proto版本
option go_package = "../pb";//声明生成的pb文件路径
package main;
message UserRequest{
// 定义请求参数
string name = 1;
int64 id = 2;
}
message UserResponse{
// 定义响应参数
int64 id = 1;//表示一个字段唯一的数字标识符,每一个结构体里面不可重复,定义后不能修改
string name = 2;
int64 age = 3;
// 字段修饰符
// repeated 表示可变数组,类似于切片类型
repeated string hobby = 4;
}
service UserInfo{
// 接口内的方法
// 定义请求参数为UserRequest,响应参数为UserResponse
rpc GetUserInfo (UserRequest) returns (UserResponse){
}
}
枚举的第一个常量映射为0:每个枚举类型必须将其第一个类型映射为0:
生成命令 protoc --go_out=plugins=grpc:../pb user.proto
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"grpc/m/pb"
"net"
)
type UserInfoService struct {
}
const (
Address = "127.0.0.1:50052"
)
var u = UserInfoService{}
func (s *UserInfoService) GetUserInfo(ctx context.Context, req *pb.UserRequest) (resp *pb.UserResponse, err error) {
// 模拟在数据库查询用户信息
if req.Name == "test" {
resp = &pb.UserResponse{
Id: req.Id,
Name: req.Name,
Age: 19,
// 切片字段
Hobby: []string{"FanOne", "FanOneTwo"},
}
}
err = nil
return
}
func main() {
listen, err := net.Listen("tcp", Address)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterUserInfoServer(s, &u)
_ = s.Serve(listen)
}
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"grpc/m/pb"
)
const (
address = "127.0.0.1:50052"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
panic("grpc链接失败" + err.Error())
}
defer conn.Close()
client := pb.NewUserInfoClient(conn)
req := new(pb.UserRequest)
req.Name = "test"
req.Id = 123
resp, err := client.GetUserInfo(context.Background(), req)
if err != nil {
fmt.Println("响应异常", err)
}
fmt.Println("响应结果", resp)
}
grpc.WithInsecure():表示跳过了对服务器证书的验证,新版本已经废弃,使用grpc.WithTransportCredentials(insecure.NewCredentials()),认证后面会讲到
生成公钥
openssl ecparam -genkey -name secp384r1 -out server.key
自签公钥
openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650
Go 版本 1.15 开始,不推荐使用 GODEBUG=x509ignoreCN=0来处理,而是使用SAN证书,兼容处理方式:环境变量 GODEBUG 为 x509ignoreCN=0
推荐采用新版本SAN认证,基于Ca的认证方式 创建证书步骤:
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
[req_distinguished_name]
countryName = CN
countryName_default = CN
stateOrProvinceName = HuBei
stateOrProvinceName_default = WuHan
localityName = WuHan
localityName_default = WuHan
organizationName = WangXu
organizationName_default = WangXu
commonName = carter
commonName_max = 64
commonName_default = localhost
生成ca
openssl genrsa -out ca.key 4096
生成csr
openssl req -new -sha256 -out ca.csr -key ca.key -config ca.conf
生成crt
openssl x509 \
-req \
-days 365 \
-in ca.csr \
-signkey ca.key \
-out ca.crt
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
[req_distinguished_name]
countryName = CN
countryName_default = CN
stateOrProvinceName = HuBei
stateOrProvinceName_default = WuHan
localityName = WuHan
localityName_default = WuHan
organizationName = WangXu
organizationName_default = WangXu
commonName = carter
commonName_max = 64
commonName_default = localhost
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP = 127.0.0.1
生成server.key
openssl genrsa -out server.key 2048
生成server.csr
openssl req \
-new \
-sha256 \
-out server.csr \
-key server.key \
-config server.conf
生成server.crt/pem
openssl x509 -req -sha256 -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 \
-in server.csr -out server.crt -extensions req_ext -extfile server.conf
生成client.key
openssl ecparam -genkey -name secp384r1 -out client.key
生成client.csr
openssl req -new -key client.key -out client.csr -config server.conf
生成client.crt
openssl x509 -req -sha256 -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 \
-in client.csr -out client.crt
最终会生成这些:
gRPC的重试策略分为两类 需要设置 GRPC_GO_RETRY=on
"retryPolicy":{
"maxAttempts": 4,//最大重试次数
"initialBackoff": "0.1s",
"maxBackoff": "1s",
"backoffMutiplier": 2,
"retryableStatusCodes": [
"UNAVAILABLE"
]
}
config说明:
gRPC 调用最多发送 4 次请求,每次间隔 0.5s,如果没有指定 hedgingDelay 或者为 “0s" 的话,就同时发送四个 请求
"hedgingPolicy":{
"maxAttempts": 4,//重试次数
"hedgingDelay": "0.5s",//时间间隔
"nonFatalStatusCodes":[
"UNAVAILABLE",
"INTERNAL",
"ABORTED"
]
}
如果您喜欢我的文章,请点击下面按钮随意打赏,您的支持是我最大的动力。
最新评论