Menu

序列化方案选型对比 - JSON/ProtocolBuffer/FlatBuffer/DIMBIN

Source:adminAuthor:admin Addtime:2019/07/06 Click:181

反序列化性能

JSON和DIMBIN都是自描述的,(弱类型语言中)不需要schema,用户可以动态生成数据结构和数据类型,生产方和消费方之间约定好即可,如果需要类型检查则需要在上层封装。

空间占用

原标题:序列化方案选型对比 - JSON/ProtocolBuffer/FlatBuffer/DIMBIN

原文链接:https://yq.aliyun.com/articles/706790?utm_content=g_1000065434

etc.

二进制方案中存储字符串需要额外的逻辑进行UTF8编解码,性能和体积不如JSON这样的字符串格式。

作为一种简单直白的优化思路,DIMBIN已经成为我们数据传输的标准方案,保持绝对的精简与高效。

Protocolbuffers 和 flatbuffers 须在项目设计的早期阶段加入,并作为工作流中的关键环节。如果出于性能优化目的而加入,会对项目架构造成较大影响。

空间优化原理

JSON基本上所有编程语言都有对应的工具。

测试环境:15' MBP mid 2015,2.2 GHz Intel Core i7,16 GB 1600 MHz DDR3,macOS 10.14.3,Chrome 75

单位:时间 ms,体积 Mb

Protocol 为强类型语言而设计,所支持的类型比JSON要丰富的多,数据结构也可以十分复杂; Flatbuffers 支持 数值/布尔值/字符串 三种基本类型,结构与JSON类似; DIMBIN 支持 数值/布尔值/字符串 三种基本类型,目前只支持多维数组的结构(暂不支持也不鼓励使用键值对),更复杂的结构需要在其上封装。

反序列化

4千字长文预警!!

我们的数据可视化场景中经常涉及百万甚至千万条数据的实时更新,为解决JSON的性能问题,我们使用内存偏移量操作的思路,开发了DIMBIN作为序列化方案,并基于其上设计了许多针对web端数据处理的传输格式。

不需要IDL的使用过程:

首先需要按照proto3语法编写schema

Flat buffers

反序列化

本文作者:meng1900

测试方式:运行10次取平均值,GZip使用默认配置 gzip ./*

序列化

我们生成两个版本的测试数据:非扁平化(多层键值对结构)数据和等效的扁平化(多维数组)数据

性能指标

在处理字符串数据时,JSON的性能总是最好的,序列化性能 JSON > DIMBIN > flatbuffers > proto,反序列化 JSON > proto > DIMBIN > flatbuffers

序列化性能

使用数值类型而非字面量来保存数值,本身就能节约一笔十分可观的空间。 protocol buffer为了实现更高的压缩率,使用varint去压缩数值。(不过下面的测试表明,可以使用gzip的环境中,这种方案没有帮助)

使用字符串与数值混合结构或者纯数值时,protocol < DIMBIN < flat < JSON 使用纯字符串时,JSON最小,二进制方案都比较大

但是如果离开了这套工程结构,则显得相对繁杂。

DIMBIN目前仅支持多维数组,不能处理树状数据结构,这里不做对比。

所有的二进制方案处理字符串的过程都是类似的:需要将js中的utf16先解码成unicode,再编码成utf8,写入buffer,并记录每个字符串的数据地址。该过程性能消耗较大,而且如果不使用varint(protocol buffers)的话,体积也没有任何优势。

针对Web/JS环境中的使用,我们选择 JSON、protocol buffers、flat buffers、DIMBIN 四种方案,从七个方面进行对比。

序列化

schema

DIMBIN针对JS/TS开发和优化,目前提供c#版本,c 、wasm、java和python的支持在计划中。

JSON/XML 和 DIMBIN 是中立的,不需要IDL,不对工程化方案和技术选型作假设或限制。可以只通过文档规范接口,也可以自行添加schema约束。

DIMBIN只需要安装一个软件包,但是需要数据结构扁平化,如果数据结构无法被扁平化,将无法从中受益。

Protocol官网声称性能高于JSON,该测试数据显然不是JS端的,我们的测试表明其JS端性相对于JSON更差(数据量大的时候差的多)。

Protocolbuffers 和 flatbuffers 必须在编码前先写好IDL并生成对应的代码,接口修改则需修改IDL并重新生成代码、部署到生产端和消费端、再基于其上进行编码。

对于扁平化数值数据的序列化性能 DIMBIN > flatbuffers > JSON > proto,

序列化

Flatbuffers 对字符串的解析性能较差,当数据中的字符串占比较高时,其整体序列化性能、解析性能和体积都不如JSON,对于纯数值数据,相对于JSON优势明显。其状态机一般的接口设计对于复杂数据结构的构建比较繁琐。

JSON/XML不好吗?

JSON基本是所有平台的基础设施,无部署成本。

好,再没有一种序列化方案能像JSON和XML一样流行,自由、方便,拥有强大的表达力和跨平台能力。是通用数据传输格式的默认首选。不过随着数据量的增加和性能要求的提升,这种自由与通用带来的性能问题也不容忽视。

处理数值数据时 Flatbuffers 和 DIMBIN 性能优势明显,

反序列化

我们生成一份典型的数据,使用扁平化和非扁平化两种结构,使用JSON、DIMBIN、protocol和flat buffers来实现相同的功能,对比各种方案的性能、体积以及便捷程度。

在可以进行内存直接操作的环境中(包括JS),还可以通过内存偏移量直接读取数据,而避免进行复制操作,也避免开辟额外的内存空间。DIMBIN和flatbuffers都使用了这种理念来优化数据存储性能。在JS环境中,通过建立DataView或者TypedArray来从内存段中提取数据的耗时基本上可以忽略不计。

首先需要按照proto3语法编写schema

本文为云栖社区原创内容,未经允许不得转载。

展开全文

Protocolbuffers 和 flatbuffers 代表Google所倡导的完整的workflow。严格、规范、统一、面向IDL,为多端协作所设计,针对python/java/c 。通过IDL生成代码,多平台/多语言使用一致的开发流程。如果团队采用这种工作流,那么这种方案更便于管理,多端协作和接口更迭都更可控。

----------------------------------------

考虑到字符串处理的特殊性,在测试时我们分开测试了 字符串/数值混合数据、纯字符串数据,和纯数值数据

需要IDL的使用过程:

使用 protoc 编译器将schema编译成JS模块

编译成js

在面对海量数据时,这种格式本身就能够成为整个系统的IO与计算瓶颈,甚至直接overflow。

在JS中使用时:

Protocolbuffers 和 flatbuffers 服务端与客户端语言支持都非常完整。两者优先针对C /Java(android)/Python开发,JS端缺少一部分高级功能,无完整文档,需要自己研究example和生成的代码,不过代码不长,注释覆盖完整。

众多的序列化方案中,按照存储方案,可分为字符串存储和二进制存储,字符串存储是可读的,但是由于以上问题,这里只考虑二进制存储。二进制存储中可分为需要IDL和不需要IDL,或分为自描述与非自描述(反序列化是否需要IDL)。

测试数据:上面例子中的数据,200,000条,字符串使用 UUID*2

反序列化

我们刚刚将DIMBIN开源,贡献给社区,希望能为大家带来一个比 JSON/protocol/flatbuffers 更轻、更快、对Web更友好的解决方案。

二进制格式用通过特定位置来记录数据结构以及每个节点数据的偏移量,省去了从字符串中解析数据结构所耗费的时间,避免了长字符串带来的性能问题,在GC语言中,也大大减少了中间垃圾的产生。

schema

选型建议

编译成js

反序列化 DIMBIN > flatbuffers >十万倍> JSON > proto

Protocol Buffers

时间优化原理

DIMBIN是什么?

Gzip之后,DIMBIN和flat的体积最小且基本一致,protocol反而没有优势,猜测可能是varint的副作用。

序列化

JSON/XML之外还有什么?

JSON和XML使用字符串表示所有的数据,对于非字符数据来说,字面量表达会占用很多额外的存储空间,并且会严重受到数值大小和精度的影响。 一个32位浮点数 1234.5678 在内存中占用 4 bytes 空间,如果存储为 utf8 ,则需要占用 9 bytes空间,在JS这样使用utf16表达字符串的环境中,需要占用 18 bytes空间。 使用正则表达式进行数据解析,在面对非字符数据时显得十分低效,不仅要耗费大量的运算解析数据结构,还要将字面量转换成对应的数据类型。