gRPC 的几种常见模式html
在学习 gRPC 的时候,相信你们对于它的四种模式都有了解,咱们来简单回顾一下:golang
接下来咱们经过一个小例子来看看 gRPC 具体的使用流程。api
假设咱们有一个聊天机器人,现须要增长一个对外提供服务的接口。具体需求为,接口传入参数是一我的名,返回一段内容是“Hello 人名”的音频。若是这个是让你在不使用 gRPC 的状况下,你会怎么作?你们可能会选择使用 restful api 来实现这个功能,传入人名,返回音频二进制数据。跨域
那么若是使用 gRPC,咱们须要怎么来设计呢?数组
第一步,须要定义一个接口文档,也就是 proto 文件。在定义内会定义一个 Service,接下来再在 Service 里定义一个 SayHello 的方法。下面定义传入参数,输入 name 返回 message,须要注意 message 是 bytes 类型,即返回的格式是二进制数据。对于 Golang 底层对应的是一个 bytes 数据,对于其余语言多是字节流或二进制。浏览器
syntax = "proto3"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { bytes message = 1;
定义完成后 ,下一步就是使用 protoc 命令行工具生成代码。下图左侧是初始化的项目,你会发现,有一个单独的目录 protoc,存放了 hello.proto 这个文件,这个文件就是前面定义好的。安全
下图右侧是自动生成代码后的项目结构,生成了一个 pkg/helloworld 的包,里面有一个 hello.pb.go,打开这个文件,你会发现刚才定义的 proto 已经被翻译成了 Go 语言。具体 protoc 命令行工具如何使用,能够自行搜索下,这里再也不过多展开。服务器
定义好了 proto 文件,以及生成了相应的 package 代码,下一步咱们就能够编写业务逻辑了。restful
Hello gRPC - 服务端业务代码数据结构
import ( "google.golang.org/grpc" pb "grpc-hw/pkg/helloworld" ) // server is used to implement helloworld.GreeterServer. type server struct { pb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { log.Printf("Received: %v", in.GetName()) tempFile := "srv.wav" err := exec.Command("flite", "-t", "Hello "+in.GetName(), "-o", tempFile).Run() if err != nil { return nil, fmt.Errorf("make audio failed: %v", err) } data, _ := ioutil.ReadFile(tempFile) return &pb.HelloReply{Message: data}, nil } func main() { lis, _ := net.Listen("tcp", port) s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) s.Serve(lis) }
在服务端侧,须要实现 SayHello 的方法来知足 GreeterServer 接口的要求。SayHello 方法的传入参数,是在 proto 文件中定义的 HelloRequest,传出参数,是在 proto 文件中定义的 HelloReply,以及一个 error。
业务逻辑也比较简单,获取 HelloRequest 中 Name 字段,而后经过命令行行工具转换成对应的音频,将 bytes 数组存在在 HelloReply 中返回。
Hello gRPC - 客户端业务代码
func main() { flag.StringVar(&address, "addr", address, "server address") flag.StringVar(&name, "name", "world", "name") flag.Parse() // Set up a connection to the server. conn, _ := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) defer conn.Close() c := pb.NewGreeterClient(conn) // Contact the server and print out its response. ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) if err != nil { log.Fatalf("could not greet: %v", err) } tempFile := "cli.wav" ioutil.WriteFile(tempFile, r.Message, 0666) exec.Command("afplay", tempFile).Run() }
咱们再来看一下如何实现 Client。首先,创建一个 gRPC 的链接,并初始化 GreeterClient,而后直接调用下 GreeterClient 的 SayHello 的方法,将把返回结果另存为一个文件,经过播放器播放就能够了。
整体而言,整个使用过程很简单,而且很是容易上手,让开发能够更加关注在客户端、服务端业务的实现,不用操心传输层的事情。
gRPC 的使用总结
经过刚刚的小例子,咱们来总结一下 gRPC 的使用:
以上 5 步就是 gRPC 的简单使用方法了。
接下来咱们来聊聊 gRPC 跟 Protobuf 之间的联系,固然在这以前咱们须要先知道 Protobuf 是什么。
Protobuf
Protobuf 是一个语言无关、平台无关的可扩展的结构化数据序列化方案。你们可能会以为它跟 JSON 好像没什么区别,功能上看起来是同样的,但像上文那样去定义 SayHello 的操做,JSON 是作不到的,JSON 只能定义一个请求体或者一个返回体,无法定义一个方法,可是 Protobuf 是能够的。
Protobuf 多用于协议通信、数据存储和其余更多用途。它是一个比较灵活的、高效的、自动化的结构化数据序列机制,可是更小,更快而且更简单。一旦定义好数据如何构造, 就可使用特殊生成的代码来轻易地读写结构化数据,无需关心用什么语言来实现。你甚至能够更新数据结构而不打破已部署的使用"旧有"格式编译的程序。
上图是 Protobuf 与 JSON 以及 JSON stream 三者之间的性能比较,能够明显的看到在解码的时候 Protobuf 比其余两项快了不仅一星半点。
上图中,咱们能够看到 Protobuf 仍是有一些缺点的,好比浏览器的支持没有其余几个支持的好。可是,在数据安全方面,因为传输过程当中采用的是加密压缩后的字节流,通常没法直接查看,安全性很是好。以及在处理速度方面,由于编解码效率很高使得总体吞吐量有了显著提高。还有一点,定义方法,这个是其余两种序列化协议所作不到的。
gRPC 跟 Protobuf 的联系
虽然每次 gRPC 与 Protobuf 都是同时出现的,可是其实二者之间并无很深的联系。只是由于二者都是由 Google 开发的,和 gRPC 自己负载无关,在使用时也能够选择 JSON 等等,可是考虑到 Protobuf 有定义方法的优点,在微服务里仍是很推荐使用的。
上图是 gRPC 与 Restful API 的对比,日常咱们可能更多使用 Restful API。但从图上能够看到,由于 gRPC 用的是 Protobuf,自己就比较小因此很快,不像 JSON 体积比较大、比较慢。另外,gRPC 是加载 HTTP/2 上面的,延迟比较低,也由于 HTTP/2 支持连接复用,这就可让多个 stream 共用一个链接,从而进一步提高速度。对比 Restful 则使用的是 HTTP 1.1,延迟比较高,并且在通常状况下,每次请求都须要建一下新的链接。
gRPC 是双向的。什么是双向呢?好比咱们日常作 Restful,都是从客户端到服务端,可是服务端没办法直接主动向客户端发送信息,gRPC 则能够。gRPC 也支持流,Restful只支持Request/Response 这样的机制。gRPC是面向 API 的,没有限制,也面向增删改查。gRPC 能够经过 Protobuf 直接生成代码,而 Restful 须要依赖第三方。
另外 gRPC 支持 RPC 能够调用服务器上的一些方法,而 Restful 是基于HTTP的语法,不少东西须要本身去定义。这方面相信你们都有感触,好比 REST 定义post/put/delete/get时,由于每一个人都有本身的习惯,因此协做时须要沟通讨论进行指定。可是 gRPC 就不须要了,它支持定义函数式办法,不须要你们去考虑如何设计语法。
以上就是 gRPC 跟 Restful API 的对比。
那么当咱们引入 gRPC 的时候须要考虑什么呢?如下几点确定是不可避免的考虑项:
这个也是咱们引入一项新的东西时,每每须要考虑到的问题。
从选择 gRPC 到整个项目落地,以及如今上线后正常使用。整个过程当中,我对于项目的思考能够包括了过去、如今和将来三个阶段。
对我而言,过去就是要去看我选择的这个东西,用的人多很少,完善程度怎么样了?而如今则是要结合项目,看看合不合适,能不能使用。固然不能思考到能使用就结束,咱们还须要考虑这个项目在将来的 3-5 年的发展,你引入它后在这个时间内需不须要大的变更。这个是很是重要的,虽然咱们如今常说敏捷开发,也常常会进行不少的调整,可是在相似 gRPC 这种底层基础来讲,是固定的。
以上就是我今天的所有分享内容,讲的比较简单,但愿能带给你们一些收获。