gRPC 是什么? 在 gRPC 里客户端 应用可以像调用本地对象一样直接调用另一台不同的机器上服务端 应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务 ,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根 能够像服务端一样的方法。
gRPC特性
使用Protocal Buffers这个强大的结构数据序列化工具
grpc可以跨语言使用
安装简单,扩展方便(用该框架每秒可达到百万个RPC)
基于HTTP2协议
gRPC使用流程 gprc的使用流程一般是这样的:
定义标准的proto文件
生成标准代码
服务端使用生成的代码提供服务
客户端使用生成的代码调用服务
Protocol Buffers是什么? 谷歌开源的一种结构数据序列化的工具,比方说JSON、XML也是结构数据序列化的工具,不同的是,
Protocol Buffers序列化后的数据是不可读的,因为是二进制流
使用Protocol Buffer需要事先定义数据的格式(.proto 协议文件 ),还原一个序列化之后的数据需要使用到这个数据格式
Protocol Buffer 比 XML、JSON快很多,因为是基于二进制流,比字符串更省带宽,传输速度快
proto
文件,用于定义请求 Request 和 响应 Response 的格式
Protocol Buffers示例 定义了一个健身房(Gym),提供一个叫健身(Bodybuilding)的远程方法。使用该服务,需要指定人(Person),人有名字(name)和训练动作(actions)两个属性。
对应的协议文件gym.proto文件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 syntax = "proto3" ; package lightweight;service Gym { rpc BodyBuilding (Person) returns (Reply) { } } message Person { string name = 1 ; repeated string actions = 2 ; } message Reply { int32 code = 1 ; string msg = 2 ; }
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport ( "app/lightweight" "context" "fmt" "google.golang.org/grpc" "log" "net" ) const ( port = ":50051" ) type server struct { lightweight.UnimplementedGymServer } func (s *server) BodyBuilding (ctx context.Context, in *lightweight.Person) (*lightweight.Reply, error) { fmt.Printf("%s正在健身, 动作: %s\n" , in.Name, in.Actions) return &lightweight.Reply{Code: 0 , Msg: "ok" ,}, nil } func main () { lis, err := net.Listen("tcp" , port) if err != nil { log.Fatalf("failed to listen: %v" , err) } s := grpc.NewServer() lightweight.RegisterGymServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v" , err) } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport ( "app/lightweight" "context" "fmt" "google.golang.org/grpc" "log" "time" ) const ( address = "localhost:50051" ) func main () { conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatalf("did not connect: %v" , err) } defer conn.Close() c := lightweight.NewGymClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.BodyBuilding(ctx, &lightweight.Person{ Name: "chenqionghe" , Actions: []string {"深蹲" , "卧推" , "硬拉" }, }) if err != nil { log.Fatalf("error: %v" , err) } fmt.Printf("code: %d, msg: %s" , r.Code, r.Msg) }