序列化:Protobuf 与 JSON、XML 的对比
Protobuf 、JSON、XML 的对比
XML | JSON | PB | |
数据结构支持 | 复杂结构 | 简单结构 | 较复杂结构 |
数据保存方式 | 文本 | 文本 | 二进制 |
数据保存大小 | 大 | 一般 | 小 |
解析效率 | 慢 | 一般 | 快 |
语言支持程度 | 非常多 | 多 | C++/Java/Python |
开发难度 | 繁琐 | 简单 | 简单 |
学习成本 | 低 | 低 | 低 |
使用范围 | 数据交换 | 数据交换 | 数据交换 |
序列化与反序列化
我们在进行网络通信调用的时候,总是需要将内存的数据块经过序列化,转换成为一种可以通过网络流进行传输的格式。而这种格式在经过了传输之后再经过反序列化,能还原成我们预想中的数据结构。
那么我们对于这种用于中间网络传输的数据格式就有一定的要求。首先它可以准确地描述数据内容,在此基础上我们则希望它尽量的小。
最开始流行起来的是XML,可扩展标记语言。由于它可以用来标记数据、定义数据类型,所以用户可以自己定义数据自己的语言,从而让对不同的数据结构化成统一的格式称为了可能。
而另外一个我们熟知的则是JSON(JavaScript Object Notation, JS 对象简谱)。尽管JSON中缺少了XML中的标签属性等描述方式,但是足够简介和清晰的层次结构使得其成为了比XML更受欢迎的数据交换格式。
同一份数据显然JSON的数据量比XML所使用的空间更少。那么空间省略在哪里呢?一方面是json使用更简单的字符来定义数据间的关联关系;另一方面是JSON减少了对数据类型的描述。但是缺少的数据类型在哪里呢?
以Java中的 OpenFeign 举例,JSON中缺少的类型定义被定义到程序中的接口中了。当进行序列化与反序列化时,JSON格式并不记录数据的类型,具体的数据类型在序列化方与反序列化方通过事先约定的接口来进行定义。这样就减少了信息传输过程中的信息量,从而让数据得以压缩。
但是JSON由于没有定义数据类型,所以在传输的过程中实际上就都是文本流,那么这种方法还可以进一步压缩吗?
结合上文的讨论,我们先说结论:方法是有的,并写当前的实现方式是ProtoBuf。但在此之前我们先来了解一下ProtoBuf。
我们可以先看看官方给出的定义与描述:
protocol buffers 是一种与语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。 Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。 你可以定义数据的结构,然后使用特殊生成的源代码轻松地在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
同样的,ProtoBuf也是一种支持序列化反序列化的方法,并且他具有很多优点:
- 多语言
- 多平台
- 体积小
- 扩展性好
实际上,ProtoBuf提供了一种通用的数据描述方式,这种定义数据的方式是通用的,就如同JSON或者XML一样。
针对JSON来说,ProtoBuf是如何将体积变得更小的呢?答案很简单,就是为数据序列化反序列化提供更多的先验知识。
本文暂不过度深入ProtoBuf原理,但是可以通过一张图来进行简要说明:
ProtoBuf中的数据是按顺序进行排列,而整体的结构为若干个field,每一个field中由Tag-[Length]-Value组成。Length是可选的,而是否存在Length是通过Tag的类型来决定的。也就是说如果是指定的类型,比如int64,那我们就可以知道Value的长度,也就不用在依靠Length来对其空间进行描述(redis中的压缩列表也是这个思想)。
那么field应该对应的是什么字段呢?这个则是在序列化与反序列化时在ProtoBuf的服务端与客户端之间进行预先定义的。而因为提前定义了field的类型、排序,所以field本身可以不用对字段名、字段位置进行描述,只需要根据字段类型选用合适的二进制序列化方法,将字段本身的value值进行序列化传输即可。
稍微总结一下:
ProtoBuf通过对传输字段的名称、顺序进行预定义,从而在传输结构中只需要顺序的记录每个字段的类型标签和二进制值。
二进制序列化
尽管上文和官方中都是以XML或者JSON来对ProtoBuf进行对比。但是因为ProtoBuf本身就是二进制序列化方式,所以从压缩比上比较感觉有点欺负人。
对应的在Java中二进制常用的序列化器有Kryo和Hessian。但事实上,由于Kryo和Hessian中都需要对Java类名和字段信息进行存储。而ProtoBuf则只有Tag-Length-Value的数据对,且Value更是有针对性的特殊编码,所以空间占用小的很多。
Kryo是专门针对Java进行优化了的。所以在使用的便捷性上来说Kryo则更加方便。但ProtoBuf是跨平台的,且由于进行了字段的顺序定义,所以似的ProtoBuf定义后的接口是可以向前兼容的(只向后追加字段),而这种优势是Kryo所没有的。
使用ProtoBuf
ProtoBuf是跨语言的,使用ProtoBuf的第一步是先定一个proto 文件,而由于ProtoBuf 2和3语言版本的不同,其定义格式会有所不同,具体的细节参考官方文档:https://developers.google.cn/protocol-buffers/docs/proto3
对于ProtoBuf 3 的定义文档我们可以按如下方法定义:
syntax = "proto3";//指定版本为proto3,默认为proto2
message SearchRequest { string query = 1; int32 page_number = 2; repeated int32 result = 3;}
其中 message 关键字是定义的文件名,而 string、int32则是预定的字段类型,repeated则是描述字段为可重复任意多次的字段。
ProtoBuf通过这种形式的文件定义了传输信息的文件结构。
我们知道了ProtoBuf是通过Tag-[Length]-Value组成的数据组来进行信息传输的,那么proto文件中定义的内容如何转换为实际传输的对象呢?
ProtoBuf的做法是,为每一种语言提供一个生成器protoc。比如通过使用protoc则可以根据.proto文件生成为一组java文件。对应的官方语法演示样例为:
protoc --proto_path=src --java_out=build/gen src/foo.proto
官方的生成参考为:https://developers.google.com/protocol-buffers/docs/reference/java-generated
生成后的java文件将提供对应的实体以及数据的构造方法等文件,从而支持后续的使用。
序列化:Protobuf 与 JSON、XML 的对比相关推荐
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)
我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为json,xml等),但是如果Controller的自动序列化后的结果不是我们想要的该 ...
- 计算机程序的思维逻辑 (63) - 实用序列化: JSON/XML/MessagePack
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>(马俊昌著),由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买:京东自营链接 ...
- 【java】序列化:ProtoBuf 与 JSON 的比较
1.概述 转载:序列化:ProtoBuf 与 JSON 的比较! 介绍 ProtoBuf 是google团队开发的用于高效存储和读取结构化数据的工具.什么是结构化数据呢,正如字面上表达的,就是带有一定 ...
- JSON与XML优缺点对比分析
1. 定义介绍 1.1 XML定义 扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种 ...
- Atitit.json xml 序列化循环引用解决方案json
Atitit.json xml 序列化循环引用解决方案json 1. 循环引用1 2. 序列化循环引用解决方法1 2.1. 自定义序列化器1 2.2. 排除策略1 2.3. 设置序列化层次,一般3级别 ...
- 二进制序列化器、XML序列化器、Json序列化器
二进制序列化器.XML序列化器.Json序列化器 序列化是将对象的状态信息转换未可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区读取或反序列化 ...
- 绝了,几款主流的 JSON 库性能对比!
本篇通过JMH(Oracle官方测试框架)来测试一下Java中几种常见的JSON解析库的性能.每次都在网上看到别人说什么某某库性能是如何如何的好,碾压其他的库.但是百闻不如一见,只有自己亲手测试过的才 ...
- 一种简易网络传输数据格式【替代json/xml】
网络传输数据格式可有多种选择,主要可分为三种: 1.自定义二进制: 2.提供序列化和反序列化库的开源协议[如protocol buffers,json,Thrift]: 3.文本化协议[如json,x ...
- php msgpack 性能,php implode/explode, serialize, json, msgpack 性能对比
php implode/explode, serialize, json, msgpack 性能对比由于implode/explode不适合使用复杂的结构,因此常用的为serialize,json,m ...
最新文章
- F5 云应用服务促进公共云、私有云及混合云应用部署
- 我该拿什么拯救你,我的CSDN
- 总结了24个C++的大坑,看你能躲过几个?
- 如何删除空文件夹Java_JAVA实现将磁盘中所有空文件夹进行删除的代码
- 信号回勾产生的原因_燃气减压阀振动的原因及处理方案
- 修改 Mac 版 Safari、Chrome、FireFox、Opera 的 User-Agent
- 如何更改电脑IP地址 哪个IP转换器比较好用
- Mac最好用的RSS阅读器Reeder使用方法
- Java基础 - 替罪羊树(Scapegoat Tree)
- rc时间常数定义_rc电路时间常数的定义及计算
- 【认证】JNCIE-SP备战心得
- mysql报No Database Selected
- 中班科学计算机,中班科学活动《蜗牛吃什么》
- Baidu Expressive TTS《Multi-reference Tacotron by Intercross Training for Style Disentangling...》
- 在网站页面标题显示小图片
- 富勒烯|Fullerene C60 富勒石 CAS:131159-39-2 |瑞禧
- 《如何阅读一本书》做一名“棒球赛中的捕手”
- java-模拟自动挡汽车
- Java 定义一个人类Person
- 喜提豪车已经out了,亚马逊Prime会员喜提邮轮之旅了解一下
热门文章
- Opencv配置VS2010,配置成功后如何成功使用完成vs调用opencv库
- C# TCP通讯客户端源码
- 挂耳式运动耳机哪个品牌好?挂耳式骨传导运动耳机推荐
- docker视频学习总结
- Vue使用高德地图api实现热力图动态缩放
- pytorch图像分类篇:6. ResNet网络结构详解与迁移学习简介
- C/C++最大的祸害是什么?内存错误,舍它其谁!
- 【FME实战教程】003:FME读取地理空间数据(矢量、栅格、点云、三维模型、数据库、地理服务)大全
- php识别人脸并提取特征值,C#人脸识别入门篇--提取人脸特征值及人脸识别
- 自开发的一个日志模板