gRPC
gRPC介绍
-
gRPC是google开发的高性能、跨语言、跨平台的rpc框架
-
gRPC 基于 HTTP2标准设计,有了性能上的提升
-
二进制传输 - 相比文本更通用、性能更高
-
多路复用 - 同一ip一次连接可以发送多个请求
-
头部压缩 - 新的压缩算法&只发送差异的header
-
推送 - server可以响应多个消息
-
gRPC的使用
gRPC同其他RPC框架思想一样,先定义一个服务,指定可以远端调用的方法以及参数和返回类型、gRPC默认使用protocol buffer作为接口定义语言
然后服务端和客服端根据定义分别编写自己的代码.
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
required string greeting = 1;
}
message HelloResponse {
required string reply = 1;
}
gRPC允许定义的四种服务
1. 单项 RPC
rpc SayHello(HelloRequest) returns (HelloResponse){}
2. 服务端流式 RPC
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){}
3. 客户端流式 RPC
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {}
4. 双向流式 RPC
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){}
protocol buffer介绍
protobuf是google的成熟的开源的数据结构序列化机制、类似于xml和json等
- 语言无关、平台无关。即 ProtoBuf 支持 Java、Go、C++、Python 等多种语言,支持多个平台
- 高效 序列化后的数据非常小、适用于网络传输和持久化
- 扩展性、兼容性好,可以新增数据结构,而不影响和破坏原有的旧程序
protobuf数据结构
syntax = "proto3";
option go_package = "pb;go_pb"
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
Service PersonService {
rpc teach(Person) returns (Person);
}
//required:必传 optional 0-1次 repeated 0-n次
protobuf的高性能
- ProtoBuf序列化后所生成的二进制消息非常紧凑
- ProtoBuf封解包过程非常简单
price=150
xml: 约36byte
<some>
<key>price</key>
<value>150</value>
</some>
json:约11byte
{
"price": "150"
}
protobuf:约3byte
message test {
optional int32 price = 1;
}
[08 96 01]
一个基于protobuf的grpc简单例子
- 定义服务数据结构,使用代码生成器生成对应go语言代码
- 实现服务器代码
- 实现客服端代码
1. protocol buffer编译器安
brew install protobuf //代码生成器
brew install protoc-gen-go //go语言依赖
2. 定义服务(.proto文件)
syntax = "proto3";
option go_package = "pb;go_proto";
package go_proto;
service hello {
rpc getInfo (helloRequest) returns (helloResponse);
}
message helloRequest {
string uId = 1;
}
message helloResponse {
string uId = 1;
string userName = 2;
string email = 3;
}
3. 使用代码生成器生成go代码
protoc --go_out=plugins=grpc:. *.proto
*.pb.go内容
用于序列化和获取我们请求和响应消息类型的 protocol buffer 代码
客户端调用定义的服务的方法的接口类型(或者 存根 )
服务器使用定义的服务的方法去实现的接口类型(或者 存根 )
在服务的实现rpc方法
type testServer struct {
}
func (s *testServer) GetInfo(ctx context.Context,req *go_proto.HelloRequest) (*go_proto.HelloResponse, error) {
log.Printf("request success, uId : %s",req.UId)
return &go_proto.HelloResponse{
UId: req.UId,
UserName: "myName",
Email: "myName123@qq.com",
}, nil
}
const port = ":2333"
func main() {
server:= grpc.NewServer()
go_proto.RegisterHelloServer(server, &testServer{})
listen, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen : %s", err)
}
_ = server.Serve(listen)
}
在客户端调用rpc方法
const address = "localhost:2333"
func main() {
//建立连接
conn, err := grpc.Dial(address,grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := go_proto.NewHelloClient(conn)
response,err := client.GetInfo(context.TODO(), &go_proto.HelloRequest{UId: "12821"})
data,err := json.Marshal(response)
fmt.Print(string(data))
}