背景
在移动互联网时代,手机流量、电量是最为有限的资源,而移动端的即时通讯应用无疑必须得直面这两点。
解决流量过大的基本方法就是使用高度压缩的通信协议,而数据压缩后流量减小带来的自然结果也就是省电:因为大数据量的传输必然需要更久的网络操作、数据序列化及反序列化操作,这些都是电量消耗过快的根源。
当前即时通讯应用中最热门的通信协议无疑就是Google的Protobuf了,基于它的优秀表现,微信和手机QQ这样的主流IM应用也早已在使用它。本文将详细介绍Protobuf的使用、原理等。
Protobuf 介绍
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API(即时通讯网注:Protobuf官方工程主页上显示的已支持的开发语言多达10种,分别有:C++、Java、Python、Objective-C、C#、JavaNano、JavaScript、Ruby、Go、PHP,基本上主流的语言都已支持,详见工程主页:https://github.com/52im/protobuf)。
或许您和我一样,在第一次看完这些介绍后还是不明白 Protobuf 究竟是什么,那么我想一个简单的例子应该比较有助于理解它。
Protobuf 安装
安装 Protobuf
编译安装 protobuf 的编译器 protoc
wget https://github.com/google/protobuf/releases/download/v3.6.1/protobuf-all-3.6.1.tar.gz
tar zxvf protobuf-all-3.6.1.tar.gz
cd protobuf-3.6.1
// /usr/local/ 为安装路径
./configure --prefix=/usr/local/
# 要编译很久
sudo make -j`nproc`
sudo make check
sudo make install
// 检查安装结果
protoc --version
安装结果:
注:protobuf 的静态库被安装到了 /usr/local/lib 中,如果在执行 protoc --version 时,报错:protoc: error while loading shared libraries: libprotoc.so.17: cannot open shared object file: No such file or directory;则只需将 /usr/local/lib 添加到环境变量即可!
添加命令如下:
// 该添加只在当前窗口有效
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
安装 protoc-gen-go 插件
使用 Go 的包管理工具 go install 来安装 protobuf 的 Go 插件。这个插件现在是作为一个独立的模块发布的,而不是 google.golang.org/protobuf 包的一部分,因此需单独安装。
从 Go 1.11 开始,Go 引入了模块作为官方的依赖管理工具,并逐渐替代了 GOPATH 模式。在 Go 模块模式下,Go 项目可以有自己独立的依赖管理,不再严格依赖于全局的 GOPATH。
在 Go 模块模式下,可能不会直接操作 $GOBIN 环境变量,因为 go install 命令会自动处理二进制文件的安装位置。但是,如果想要自定义安装位置,可以设置 $GOBIN 环境变量。例如:
// 指定 protoc-gen-go 的安装位置
export GOBIN=/usr/local/go/bin
// 安装 protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
注:把 .proto 文件编译成 .go 文件依赖 protoc-gen-go;
Protobuf 使用
创建 .proto 文件
创建 metadata.proto 文件
syntax = "proto3";
package message;
option go_package = "/data/etcd_test/src/message";
message Metadata {
string Name = 1;
string DBName = 2;
string Type = 3;
int64 ShardMethod = 4;
string ShardKey = 5;
int64 ShardCount = 6;
string Groups = 7;
string RangeInfo = 8;
}
注:
- go_package 用于指定生成的GO代码应该使用哪个包名,并且(可选地)指定生成代码的输出目录
- 字段后面的数字在序列化过程中唯一标识字段,这些标识符在消息定义中是唯一的,并且在整个.proto文件中应该是唯一的
编译.proto 文件
protoc --go_out=. --go_opt=paths=source_relative ./src/message/metadata.proto
注:
- --go_out=. 告诉 protoc 编译器生成 Go 代码,并将输出放在当前目录(.表示当前目录)
- --go_opt=paths=source_relative 是一个选项,它告诉 protoc-gen-go 生成代码时使用相对于 .proto 文件的路径,这在 Go 模块中特别有用,因为它可以确保生成的代码与你的模块结构保持一致
编译结果:
Json 和 Protobuf 的对比
在当今的软件开发中,数据交换是必不可少的环节。Protobuf和JSON是两种广泛使用的数据交换格式,它们各自具有独特的优势和适用场景。下面将从多个方面对Protobuf和JSON进行对比分析。
1)性能
Protobuf是一种高效的二进制序列化格式,它在数据传输和存储方面的性能优于JSON。由于Protobuf采用二进制编码,因此在相同数据量的情况下,序列化和反序列化的速度更快,且数据体积更小。相比之下,JSON是一种文本格式,其编码较为冗长,且解析速度相对较慢。因此,在处理大量数据或对性能要求较高的场景下,Protobuf更具优势。
2)可读性
JSON的优点在于其易于阅读和编写。JSON数据的结构清晰,语法简单,使得开发人员能够轻松地读写和理解数据。而Protobuf的二进制编码方式则较为复杂,不易于直接阅读。因此,在需要易于阅读和调试的场景下,JSON更为合适。
3)可扩展性
Protobuf具有更好的可扩展性。它支持自定义消息类型和字段标签,允许用户根据需要定义复杂的数据结构。此外,Protobuf还支持多种编程语言的实现,使得在不同语言间进行数据交换更加方便。相比之下,JSON虽然也可以表示复杂的数据结构,但其扩展性相对较差,且不支持自定义标签等高级功能。因此,在需要定义复杂数据结构或跨语言数据交换的场景下,Protobuf更具优势。
4)安全
Protobuf和JSON在安全性方面各有千秋。Protobuf采用加密传输的方式保证数据的安全性,而JSON则可以通过适当的加密算法对数据进行加密处理。另外,由于Protobuf采用二进制编码,相对于JSON的文本格式更难以被直接查看和修改,从而提高了数据的安全性。然而,在实际应用中,为了确保数据的安全性,无论使用Protobuf还是JSON都需要采取相应的安全措施,如加密传输、校验数据完整性等。因此,在安全性方面没有绝对的优劣之分。
5)流行度与生态系统
JSON在互联网领域的应用非常广泛,已经成为RESTful API的标准数据格式之一。许多常用的编程语言和框架都支持JSON的处理和解析,这使得JSON在开发社区中拥有庞大的生态系统。而Protobuf虽然也得到了许多公司和项目的采用,但其流行度和生态系统相对较小。因此,在选择数据交换格式时,需要考虑项目需求和开发团队的技能背景。
综上所述,Protobuf和JSON各有千秋,需要根据实际需求选择合适的数据交换格式。在处理大量数据或对性能要求较高的场景下,Protobuf更具优势;而在需要易于阅读和调试的场景下,JSON更为合适。另外,如果项目需要定义复杂的数据结构或跨语言数据交换,应优先考虑使用Protobuf;如果项目主要应用于互联网领域,则JSON可能更适合。在选择数据交换格式时,还需要综合考虑安全性、流行度以及生态系统等方面的因素。