我们平时习惯的数据存储格式有Json、XML等形式,但相信很多人都没有听说过ProtocolBuffer(简称protobuf).protobuf是谷歌开源的一种独立于语言和平台的通信协议。其体积小、效率高和友好的兼容性设计使其得到广泛应用。性能比Json和XML强多了!而且,随着微服务架构的流行,RPC框架也成为了服务框架的重要组成部分。在很多RPC设计中,都会用到高性能的codec技术,protobuf就是其中的佼佼者。也就是说,需要学习protobuf的使用和原理,才能深入理解微服务架构中RPC链路的底层实现,设计高效的传输、序列化、编解码功能。protobuf简介protobuf是一个序列化对象框架(或编解码器框架)。它由两个功能组成:结构化数据(数据存储结构)和序列化&反序列化。数据存储结构的作用类似于XML和JSON;序列化和反序列化的作用类似于Java自带的序列化,Facebook的Thrift和JBossMarshalling等。简而言之:protobuf就是通过定义结构化数据,提供序列化和反序列化功能,实现数据存储/RPC数据交换的功能数据。其特点是:语言无关,平台无关,简单高性能(序列化速度快&序列化后数据量小),兼容性好,可以通过数据直观的看到不同框架之间序列化响应时间的对比:可以看出protobuf的性能比其他框架要高很多。protobuf的使用过程上面已经介绍了protobuf的功能,但是仅仅知道这些功能我们并不能知道它是如何使用的。网上看了一大堆文章,要么直接开始写代码,要么直接开始分析报文格式,新手往往一头雾水。那么,我们先梳理一下protobuf的使用步骤。上图中,protobuf的使用分为四步:第一步,搭建环境:使用protobuf定义通信的数据结构,编译生成不同的编程语言代码,需要这样的编译环境。第二步,构建数据:使用protobuf传输数据,那么数据包含什么,有哪些项,整个结构是什么样子的。这里,数据结构是根据protobuf的语法定义的。第三步,项目集成:集成pom依赖(以Java为例),集成编译好的Java类(相对于proto文件);step4,具体使用:使用集成的Java类构建消息,赋值,然后根据protobufsequencereceiver进行反序列化操作;了解了以上步骤后,下面对具体步骤进行实战演示。这里的演示是基于MacOS操作系统和Java编程语言。如果你使用的是其他操作系统和编程语言,基本思路是一样的,具体操作可以在不同的步骤中找到。安装ProtocolBuffers,安装protobuf,定义数据结构,生成相应的编程语言代码。通常有两种方式:本地安装和IDE插件。我们先看看本地安装。protobuf的代码托管在GitHub上,对应地址为:https://github.com/protocolbu...。点击项目右侧的发布链接可以看到对应的版本:https://github.com/protocolbu...。各种编程语言和环境的版本都包含在这里。本文选择protobuf-java-3.17.3.zip版本。Mac操作系统下,编译安装protobuf前需要先安装依赖组件。安装依赖组件://安装ProtocolBuffer依赖//注:ProtocolBuffer依赖autoconf、automake、libtool、curlbrewinstallautoconfautomakelibtoolcurlunzipprotobuf-java-3.17.3.zip,进入根目录,执行以下命令command://运行autogen.sh脚本。/autogen.sh//运行configure.sh脚本。/configure//编译未编译的依赖包make//检查依赖包是否完整makecheck//开始安装ProtocolBuffermakeinstall安装完成后查看Version:$protoc--versionlibprotoc3.14.0输出版本信息,说明安装成功。这里的protoc命令是ProtocolBuffer的编译器,可以将.proto文件编译成对应平台的头文件和源代码文件。另一种方法是安装IDE插件。这里我们以IDEA为例,搜索插件:关于protobuf的插件有很多,选择适合自己的就可以了。那么gRPC官方推荐了一个更优雅的使用姿势,通过maven即可轻松搞定(需要安装上图中的“ProtobufSupport”插件)。即引入grpc的一些组件,然后在maven构建中进行配置,将proto文件编译成Java代码。这个方法暂时不展开,以后可以直接看项目集成部分的源码。构建数据在Java中,如果我们要通过JSON传输一段数据,首先需要定义一个对象,这里以Person为例:publicclassPerson{privateStringname;私有整数id;//...getter/setter}那么,如果使用protobuf来定义Person对象的数据结构是怎样的呢?首先创建一个person.proto文件,然后定义如下结构:syntax="proto3";//声明为protobuf3定义文件打包教程;选项java_package="com.choupangxia.protobuf.message";//声明生成消息类java包路径选项java_outer_classname="Person";//声明生成消息的类名classmessagePersonProto{stringname=1;int32id=2;}上面各个语法的具体描述可以参考评论区。当然Person的结构可以更丰富。这里只是为了演示目的的最简单的例子。更多语法请参考官方文档。编译完protot文件的定义后,我们可以通过两种方式生成目标Java类。这里我们首先使用本机安装的编译器进行操作。在执行protoc命令之前,可以先执行-h命令查看protoc的使用说明:protoc-h进入person.proto文件所在目录,执行如下命令编译:protoc--java_out=。./java./person.proto--java_out参数指定Java类的输出路径,第二个参数要编译执行的文件为当前目录下的person.proto文件。执行命令,会发现在com.choupangxia.protobuf.message下生成了一个名为Person的类。注意proto中定义的消息名不能和Java类名重名,否则命令执行失败。对应的Person类比较复杂,甚至有一些语法错误或改进。如果有必要,相应的改进和优化就足够了。上图展示了生成的Person类的部分结构。比如上面的java.lang.StringgetName()方法的返回值可以在不指定String包的情况下进行优化。项目集成其实就是将上面提到的生成的Person代码放到项目中,这已经是项目集成的一部分了。如果不引入protobuf依赖,上面的代码还是会报错。在Maven项目的pom文件中添加protobuf依赖:
