背景
序列化与反序列化是我们日常数据持久化和网络传输中常常利用的技能,但是目前各种序列化框架让人眼花缭乱,不清楚什么场景到底采取哪种序列化框架。本文会将选举支持跨措辞、跨平台的Google Protobuf 和 Apache avro 两款进行比拟。
Google protobuf
先容
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的稠浊措辞数据标准,Protocol Buffers 是一种轻便高效的构造化数据存储格式,可以用于构造化数据串行化,或者说序列化。它很适宜做数据存储或 RPC 数据交流格式。可用于通讯协议、数据存储等领域的措辞无关、平台无关、可扩展的序列化构造数据格式。目前供应了 C++、Java、Python 三种措辞的 API。

特点
优点
二进制,性能好/效率高(空间和韶光效率都很不错)proto文件天生目标代码,大略易用序列化反序列化直接对应程序中的数据类,不须要解析后在进行映射(XML,JSON都是这种办法)支持向前兼容(新加字段采取默认值)和向后兼容(忽略新加字段),简化升级支持多种措辞(可以把proto文件看做IDL文件)Netty等一些框架集成缺陷
官方只支持C++,JAVA和Python措辞绑定二进制可读性差(貌似供应了Text_Fromat功能)二进制不具有自描述特性默认不具备动态特性(可以通过动态定义天生类型或者动态编译支持)只涉及序列化和反序列化技能,不涉及RPC功能(类似XML或者JSON的解析器)数据类型
ProtoBuf 有两个措辞版本:v2 与 v3,须要在 .proto 文件首行中明文标识 syntax="proto3",v3 与 v2 在语法上有一些差异例如:v3 去除了 optional、required 等,在语法上更为的简洁,我们这里紧张先容 v3,以是对 v2 就不做过多先容了。protobuf属于轻量级的,因此不能支持太多的数据类型,下面是protobuf支持的基本类型列表并与c++类型比拟,一样平常都能知足需求。N 表示打包的字节并不是固定。而是根据数据的大小或者长度。
protobuf 数据类型
描述
打包(字节)
C++措辞映射
bool
布尔类型
1
bool
double
64位浮点数
N
double
float
32为浮点数
N
float
int32
32位整数、
N
int
uin32
无符号32位整数
N
unsigned int
int64
64位整数
N
__int64
uint64
64为无符号整
N
unsigned __int64
sint32
32位整数,处理负数效率更高
N
int32
sing64
64位整数 处理负数效率更高
N
__int64
fixed32
32位无符号整数
4
unsigned int32
fixed64
64位无符号整数
8
unsigned __int64
sfixed32
32位整数、能以更高的效率处理负数
4
unsigned int32
sfixed64
64为整数
8
unsigned __int64
string
只能处理 ASCII字符
N
std::string
bytes
用于处理多字节的措辞字符、如中文
N
std::string
enum
可以包含一个用户自定义的列举类型uint32
N(uint32)
enum
message
可以包含一个用户自定义的类型
N
object of class
分外类型
类型
描述
enum类型
列举用来表示一定范围内具有相同属性的值
map类型
一组k-v格式的数据凑集
凑集类型
利用repeated标示字段,被 repeated 标识的字段可以理解为是一个数组
自定义工具
利用message 在定义过程中是可以声明自己定义的 message 类型,Protocol Buffers 定义 message 许可嵌套组合成更加繁芜的。
要利用利用protobuf,首先须要定义一个.proto格式的文件,格式类似下面这样
syntax="proto3";package exmple; //每个 .proto 文件可以指定 package 作为天生措辞的 namespacemessage Person { int64 id = 1; string name = 2; enum Skills { GOLANG = 0; PYTHON = 1; JAVA = 2; RUST = 3; CPP = 4; } repeated Skills skill = 3; // 这里表示 skills 可以接管多个 string 类型的值 map<string, hobby> hobbys = 4; //message 定义时可以利用 map 类型}message hobby{ string hobby=1;}
编码方面
protocol buffers 自带代码天生工具,可以天生友好的数据访问存储接口。从而开拓职员利用它来编码更加方便。例如上面的例子,如果用 C++ 的办法去读取用户的名字和 email,直接调用对应的 get 方法即可(所有属性地get 和 set 方法的代码都自动天生好了,只须要调用即可),Protobuf 语义更清晰,无需类似 XML 解析器的东西(由于 Protobuf 编译器会将 .proto 文件编译天生对应的数据访问类以对 Protobuf 数据进行序列化、反序列化操作)。
利用 Protobuf 无需学习繁芜的文档工具模型,Protobuf 的编程模式比较友好,大略易学,同时它拥有良好的文档和示例,对付喜好大略事物的人们而言,Protobuf 比其他的技能更加有吸引力。protocol buffers 末了一个非常棒的特性是,即“向后”兼容性好,人们不必毁坏已支配的、依赖“老”数据格式的程序就可以对数据构造进行升级。这样您的程序就可以不必担心由于构造的改变而造成的大规模的代码重构或者迁移的问题。由于添加新的中的 field 并不会引起已经发布的程序的任何改变(由于存储办法本来便是无序的,k-v 形式)。
Apache Avro
先容
Avro是Hadoop中的一个子项目,也是Apache中一个独立的项目,Avro是一个基于二进制数据传输高性能的中间件。在Hadoop的其他项目中例如HBase(Ref)和Hive(Ref)的Client端与做事真个数据传输也采取了这个工具。Avro是一个数据序列化的系统。Avro 可以将数据构造或工具转化成便于存储或传输的格式。Avro设计之初就用来支持数据密集型运用,适宜于远程或本地大规模数据的存储和交流
特点
优点
二进制,性能好/效率高利用JSON描述模式模式和数据统一存储,自描述,不须要天生stub代码(支持天生IDL)RPC调用在握手阶段交流模式定义包含完全的客户端/做事端堆栈,可快速实现RPC支持同步和异步通信支持动态模式定义许可定义数据的排序(序列化时会遵照这个顺序)供应了基于Jetty内核的做事基于Netty的做事缺陷
只支持Avro自己的序列化格式措辞绑定不丰富数据类型
Apache avro 的 Schema 通过 JSON 工具表示也可以利用IDL。Schema 定义了大略数据类型和繁芜数据类型,个中繁芜数据类型包含不同属性。通过各种数据类型用户可以自定义丰富的数据构造。
基本类型有:
类型
解释
null
no value
boolean
a binary value
int
32-bit signed integer
long
64-bit signed integer
float
single precision (32-bit) IEEE 754 floating-point number
double
double precision (64-bit) IEEE 754 floating-point number
bytes
sequence of 8-bit unsigned bytes
string
unicode character sequence
Avro定义了六种繁芜数据类型:
类型
解释
Record
任意类型的一个命名字段凑集
Enum
列举类型
Array
数组类型
Map
Map是一种定义keys和values列表的方法
Union
组合类型,表示各种类型的组合,利用数组进行组合
Fixed
fixed 类型,一组固天命量的8位无符号字节
要利用利用Apache avro ,首先须要定义一个Schema,格式类似下面这样
JSON格式:
{ "namespace": "avro", #namespace是包名 "type": "record", "name": "User", "fields": [ {"name": "name", "type": "string"}, {"name": "id", "type": "int"}, {"name": "salary", "type": "int"}, {"name": "age", "type": "int"}, {"name": "address", "type": "string"} ]}
namespace:定义了根据 schema 文件天生的类的包名type:固定写法name:天生的类的名称fields:定义了天生的类中的属性的名称和类型,个中"type": ["int", "null"]的意思是,favorite_number 这个属性是int类型,但可以为null
或者IDL格式:
record User { string name; int id; int salary; int age; string address;}
编码办法
Avro支持两种序列化编码办法:二进制编码和JSON编码。利用二进制编码会高效序列化,并且序列化后得到的结果会比较小;而JSON一样平常用于调试系统或是基于WEB的运用。对Avro数据序列化/反序列化时都须要对模式以深度优先(Depth-First),从左到右(Left-to-Right)的遍历顺序来实行。基本类型的序列化随意马虎办理,稠浊类型的序列化会有很多不同规则。对付基本类型和稠浊类型的二进制编码在文档中规定,按照模式的解析顺序依次排列字节。对付JSON编码,联合类型(Union Type)就与其它稠浊类型表现不一致。 Avro为了便于MapReduce的处理定义了一种容器文件格式(Container File Format)。这样的文件中只能有一种模式,所有须要存入这个文件的工具都须要按照这种模式以二进制编码的形式写入。工具在文件中以块(Block)来组织,并且这些工具都是可以被压缩的。块和块之间会存在同步标记符(Synchronization Marker),以便MapReduce方便地切割文件用于处理
总结
Protobuf具有跨平台、解析速率快、序列化数据体积小、扩展性高、利用大略的特点,但是内嵌并没有供应RPC的通讯。Avro显式schema设计以及动态模式(不用天生代码,而且性能很好)使它更适用于搭建数据交流及存储的通用工具和平台,特殊是在后台。
protobuf适宜场景, 须要和其它系统做交流的,对大小很敏感的。那么protobuf适宜了,它措辞无关,空间相对xml和json等节省很多 小数据的场合。如果你是大数据,用它并不适宜。 项目措辞是c++,java,python的,由于它们可以利用google的源生类库,序列化和反序列化的效率非常高。其它的措辞须要第三方或者自己写,序列化和反序列化的效率不担保。 总体而言,protobuf还是非常好用的,被很多开源系统用于数据通信的工具,在google也是核心的根本库。
Avro适宜场景场景,avro与Hadoop生态系统结合最好,Hive表定义可以直接用avro schema来声明,Hive里用它来序列化日志文件,优点是可以直接用avro schema替代Hive本身表构造定义,这样能比较方便的办理schema evolution问题,在kafka和Flume 中也有很多利用avro的. flume紧张的RPC source便是Avro source, 与 Avro sink, FlumeSDK等构成Flume内部通信。
Protobuf
avro
开源协议
BSD-style
Apache
schema
IDL
JSON ,也支持IDL
是否须要代码动态天生
须要
可选
是否动态天生rpc接口
是
是
是否天生rpc实现
否
是