Google Protobuf vs. Apache Avro
liebian365 2024-10-24 14:38 15 浏览 0 评论
背景
序列化与反序列化是我们日常数据持久化和网络传输中经常使用的技术,但是目前各种序列化框架让人眼花缭乱,不清楚什么场景到底采用哪种序列化框架。本文会将选举支持跨语言、跨平台的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 作为生成语言的 namespace
message 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实现 | 否 | 是 |
相关推荐
- 快递查询教程,批量查询物流,一键管理快递
-
作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...
- 一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递
-
对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...
- 快递查询单号查询,怎么查物流到哪了
-
输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...
- 3分钟查询物流,教你一键批量查询全部物流信息
-
很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...
- 快递单号查询,一次性查询全部物流信息
-
现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...
- 快递查询工具,批量查询多个快递快递单号的物流状态、签收时间
-
最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...
- 快递查询软件,自动识别查询快递单号查询方法
-
当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...
- 教你怎样查询快递查询单号并保存物流信息
-
商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...
- 简单几步骤查询所有快递物流信息
-
在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...
- 物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号
-
最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...
- 连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息
-
快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...
- 快递查询教程,快递单号查询,筛选更新量为1的单号
-
最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...
- 掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析
-
在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...
- 从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息
-
在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...
- 物流单号查询,在哪里查询快递
-
如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)