【gRPC】Protobuf在gRPC下的应用-快速入门

680 阅读7分钟

在 gRPC 中,Protocol Buffers(简称 Protobuf)扮演了非常关键的角色。它主要用于以下方面:

  1. 接口定义语言(IDL) :Protobuf 作为 gRPC 的接口定义语言,用于定义服务和消息。开发者使用 Protobuf 编写 .proto 文件,描述客户端和服务器需要遵循的通信协议。这包括服务名、RPC 方法、输入参数(请求消息)、输出参数(响应消息)等。这种明确的接口定义有助于不同语言和平台之间的互操作性。
  2. 数据序列化与反序列化:Protobuf 是一种高效的二进制数据序列化格式。在 gRPC 中,Protobuf 被用于将数据序列化成二进制格式,以便在客户端和服务器之间高效地传输数据。生成的代码为每个消息类型提供了序列化(Marshal)和反序列化(Unmarshal)方法,使得将对象转换为字节流或从字节流中恢复对象变得非常简单。与 JSON、XML 等文本格式相比,Protobuf 序列化后的数据更小、更快,且解析开销更低。
  3. 跨语言支持:Protobuf 支持多种编程语言,包括 Go、Python、Java、C++、C# 等。protoc 编译器可以将 .proto 文件编译成各种目标语言的代码,这意味着用不同语言编写的客户端和服务器可以轻松地相互通信。这极大地简化了在复杂的微服务架构中实现多语言服务之间通信的过程。
  4. 代码生成:Protobuf 编译器可以自动生成数据结构、序列化/反序列化方法以及 gRPC 客户端和服务器的基础代码。这可以减少手动编写代码的工作量,提高开发效率,同时降低出错的可能性。通过编译生成的代码,开发者可以专注于实现业务逻辑,而不必担心底层的通信细节。

综上所述,Protobuf 在 gRPC 中发挥了核心作用。它作为接口定义语言,提供了跨语言支持、高效的数据序列化以及自动代码生成等功能,使得在复杂的分布式系统中实现高性能、可扩展的服务通信变得更加简单。下面我们来看看具体怎么使用的。

1.下载工具

proto 工具是 Protobuf 的核心工具,用于生成 protobuf 相关代码和生成 .proto 文件。proto 工具支持多种编程语言,可以帮助开发人员轻松地实现 protobuf 的序列化和反序列化。

简单说,就是用该工具,生成go语言代码,帮助我们实现rpc

github.com/protocolbuf…

mac可以直接使用 homebrew下载

2.下载go的依赖包

直接在goLand终端下,输入下列命令就可以。

	go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
	go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1

3.proto文件

关于proto的写法介绍详见这篇文章:

# 【gRPC】 proto快速入门-基本操作

syntax = "proto3";

option go_package = ".;proto";

service Greeter{
    rpc SayHello(HelloRequest) returns (HelloResponse);
}

message HelloRequest{
    string name = 1;
    repeated int64 nums = 2;
}

message HelloResponse{
    string message = 1;
}

这是一个简单的 Protocol Buffers (Protobuf) 定义文件,使用 "proto3" 语法。这个文件定义了一个名为 "Greeter" 的 gRPC 服务,该服务包含一个名为 "SayHello" 的 RPC 方法。此外,这个文件还定义了两个消息类型 "HelloRequest" 和 "HelloResponse"。下面逐个解释这个定义文件的组成部分:

  • syntax = "proto3"; :指定这个 .proto 文件使用的 Protobuf 语法版本为 "proto3"。Protobuf 提供了两个主要版本的语法:"proto2" 和 "proto3"。这里使用的是 "proto3",它具有更简洁的语法和更好的跨语言支持。
  • option go_package = ".;proto"; :为生成的 Go 代码文件指定包名和导入路径。在这里,go_package 的值分为两部分,用分号分隔。第一部分是 ".",表示生成的 Go 代码文件放在当前目录。第二部分是 "proto",表示生成的 Go 代码文件的包名为 "proto"。
  • service Greeter:定义一个名为 "Greeter" 的 gRPC 服务。这个服务包含一些 RPC 方法,它们可以用于实现客户端和服务器之间的远程过程调用。
    • rpc SayHello(HelloRequest) returns (HelloResponse); :定义一个名为 "SayHello" 的 RPC 方法。这个方法接受一个 "HelloRequest" 类型的参数,并返回一个 "HelloResponse" 类型的结果。
  • message HelloRequest:定义一个名为 "HelloRequest" 的消息类型。这个消息类型包含两个字段:
    • string name = 1; :定义一个名为 "name" 的字符串类型字段,其字段编号为 1。
    • repeated int64 nums = 2; :定义一个名为 "nums" 的整数数组字段,其字段编号为 2。"repeated" 关键字表示这个字段可以包含多个值。
  • message HelloResponse:定义一个名为 "HelloResponse" 的消息类型。这个消息类型包含一个字段:
    • string message = 1; :定义一个名为 "message" 的字符串类型字段,其字段编号为 1。

4.生成go文件

这条命令是使用 protoc 编译器来编译一个名为 goods.proto 的 Protocol Buffers(Protobuf)定义文件。该命令生成 Go 语言的代码文件,包括数据结构和 gRPC 服务实现。

请在控制台中输入,可以直接使用goLand中的控制台,需要找到当前文件的所在目录

protoc --go_out=. --go-grpc_out=require_unimplemented_servers=false:. goods.proto
  • protoc: Protocol Buffers 编译器,用于将 .proto 文件编译成目标编程语言的代码文件。
  • --go_out=. : 使用 Go 语言插件编译 .proto 文件,生成 Go 代码。选项中的 . 指定输出目录,这里表示将生成的代码文件输出到当前目录。这个选项主要生成消息(message)和枚举(enum)的数据结构代码。
  • --go-grpc_out=require_unimplemented_servers=false:. : 使用 Go gRPC 插件编译 .proto 文件,生成 gRPC 服务相关的代码。选项中的 require_unimplemented_servers=false 表示生成的服务接口不强制实现所有方法,这样您可以只实现需要的方法。 : 后面的 . 表示将生成的代码文件输出到当前目录。


结果会生成图上两个文件。

使用 protoc 编译器生成的 hello.pb.gohello_grpc.pb.go 文件具有不同的功能和目的。它们分别对应于不同的插件,用于生成与 Protocol Buffers 和 gRPC 服务相关的代码。下面分别解释这两个文件的内容和用途:

  1. hello.pb.go:此文件是使用 protoc-gen-go 插件生成的,主要包含与 Protocol Buffers 相关的代码。这些代码包括:通常情况下,hello.pb.go 文件的代码与 gRPC 服务实现无关,主要用于在客户端和服务器之间传输数据。
    • 消息(Message)的数据结构:为每个在 .proto 文件中定义的消息类型生成相应的 Go 结构体。
    • 序列化和反序列化方法:为每个消息类型生成 MarshalUnmarshal 方法,用于将消息对象序列化为二进制格式,或从二进制格式反序列化为消息对象。
    • 其他辅助方法:例如,为每个枚举类型生成 String 方法,用于将枚举值转换为字符串表示。
  1. hello_grpc.pb.go:此文件是使用 protoc-gen-go-grpc 插件生成的,主要包含与 gRPC 服务相关的代码。这些代码包括:hello_grpc.pb.go 文件的代码主要用于实现 gRPC 服务的客户端和服务器。您需要根据生成的接口编写服务的具体实现,并在客户端中调用相应的方法。
    • 服务接口(Service Interface):为每个在 .proto 文件中定义的 gRPC 服务生成相应的 Go 接口。这些接口包含了服务中定义的所有 RPC 方法。
    • 客户端和服务器代码:为每个 gRPC 服务生成客户端和服务器的基础代码。客户端代码包括用于调用远程方法的函数,服务器代码包括用于注册服务实现的函数。