一种快速、紧凑、通用的数据格式


原始互联网对象符号是一种快速、紧凑、通用的数据格式。是的,我知道你在想什么:“又是一种数据格式。”这与CSV、XML,JSON,YAML,原型,信息包,CBOR,亚马逊的ION,阿帕奇Avro或ASN.1?等等,我将在本文中解释这一点,但首先我必须给出一些关于RION的背景信息。

一种有效交换和存储数据的数据格式

RION是由Nanosai,一家R&D分布式系统公司(我是该公司的联合创始人之一),作为“开放标准”——这意味着欢迎每个人使用它。RION最初是作为一种高效数据交换的数据格式而设计的。然而,我们已经扩展了目标用例,也包括了结构化数据的高效存储。

我们相信用例之间有足够紧密的联系,这种扩展是有意义的。这两种使用情况之间的主要区别在于,通过网络发送的消息往往具有固定的大小(至少发送一次),而文件可能会随着时间的推移而增长。

我们实际上使用RION作为网络协议的消息编码和数据流存储引擎中的记录格式,因此我们有经过压力测试的RION用于数据交换和数据存储。

一种通用的数据格式

从一开始,我们就想让RION尽可能通用,这意味着它应该能够编码各种各样的结构化数据。希望有了更通用的数据格式,开发人员不必经常在不同的数据格式之间切换。我们越经常能够默认RION,越好。

显然,没有一种数据格式适合所有类型的数据。对于一些用例,如音频、视频、强格式文档等。特定领域的编码,如MP3、MP4或PDF可能更合适。为了适应这种情况,RION被设计成能够嵌入二进制数据和其他结构化数据(例如元数据)。

RION还旨在使您能够在内置数据类型不足的情况下用自定义数据类型扩展它。

你可能还喜欢:Using Apache Spark DataFrames for Processing of Tabular Data

支持的数据结构

要成为真正的多面手,RION必须能够代表各种各样的数据结构。目前,RION使您能够代表:

  • 二进制数据。

  • 类型化数据字段(布尔、整数、浮点、文本、日期时间)。

  • 单一字段。

  • 无限的田野溪流。

  • 字段(数组)的有界列表。

  • 表格数据(如CSV文件,其中列名只包含一次)。

  • 对象和映射(键值对)。

  • 对象图(带有嵌套对象的对象)。

这些数据结构可以组合起来创建更高级的结构。例如,您可以有一个内部嵌套有其他表的表,或者一个内部嵌套有对象图的表,同样也可以有表,等等。

字段类型

RION编码的数据由一个或多个RION字段组成。每个RION字段都有一个类型。RION目前包含以下字段类型:

  • 字节。

  • 布尔型。

  • 内部位置。

  • 内部否定。

  • 浮点(32或64位)。

  • UTF-8。

  • UTF-8肖特。

  • 世界协调时。

  • (参考)。

  • 数组(*)。

  • 桌子。

  • 对象。

  • 钥匙。

  • 短键。

  • 延伸。

让我详细阐述一下这些字段类型。

字节字段用于“非结构化”二进制数据。例如,如果您需要在RION中嵌入音频或视频文件(或任何其他类型的文件或二进制数据),您可以将其嵌入到Bytes字段中。这允许二进制数据的有效传输。

布尔字段可以表示真值和假值。

整数和负数字段代表正整数和负整数。正整数被编码,因此它们只包括有效字节。因此,包含数字127的内部位置字段可以用2字节表示,1024用3字节表示,等等。另一方面,负数更具挑战性。

例如,一个32位负整数需要4个字节,因为所有字节都是有效的。为了更有效地对负数进行编码,我们创建了一个包含负整数-负1的绝对(正)值的负整数字段。这允许我们使用与正整数相同的有效“有效字节”编码。

浮点数可以是32位或64位浮点数。

UTF-8和UTF-8简称是以UTF-8格式存储的文本数据。UTF-8短码可以编码15字节或更少的文本,比UTF-8字段少1字节。在有许多文本字段的数据中,每个字段节省的1字节可能很重要。

世界协调时用于以世界协调时存储数据和时间。通过网络交换日期时间信息是一个常见的用例,所以我们认为RION应该支持这一点。为了避免时区混乱,我们决定“强制”将日期-时间字段表示为世界协调时时间。

到目前为止,参考字段仅处于构思阶段。它旨在表示对RION数据中先前发现的RION字段的“反向引用”。这可以用来表示循环对象图。这也可以用来避免重复冗余信息,例如在关系数据库管理系统结果集中或在微服务查询响应中。将来我们可能会添加其他字段来表示冗余数据的拷贝(例如,拷贝字段)。

数组字段用于表示RION字段的数组(列表)。因此,一个RION数组可以包含嵌套在其内部的其他RION字段。因此,数组字段是一个复合字段。请注意,我们已经意识到,您可以将一个数组表示为具有单个列的表,因此我们可能实际上删除了“数组”字段,只保留了用于数组和表格数据的“表”字段。

“表”字段用于表示列和行的表格数据,如CSV文件或针对关系数据库的SQL查询结果。为了有效地编码表格数据,表格只包含一次行的列名(关键字段)。列名后面跟随列值的行。这类似于CSV文件,其中第一行是列标题,后续行是每行的列值。一个只有一列的表可以用来表示一个数组,所以我们可以删除前面提到的数组字段。表可以包含嵌套在其中的其他RION字段。因此,您也可以使用带有嵌套表的表来更有效地表示树结构。

对象字段用于表示键值对的对象或映射(字典)。通常,键值对将被编码为一个键字段,然后是一些其他字段,但是如果您愿意,您可以省略键(或者值也可以——如果这在您的用例中有意义的话)。您可以在对象中嵌套其他RION字段,包括数组或表字段,以表示您需要的对象图。到目前为止,您只能表示非循环对象图,但是一旦我们完成了引用字段的规范,您也可以表示循环对象图。

扩展字段类型旨在使您能够指定自己的字段类型,因此您可以使用RION核心字段类型嵌入其他类型的数据。

紧凑

为了高效地交换和存储,紧凑性对RION至关重要。因此,我们竭尽全力使RION编码尽可能紧凑。有时,我们不得不做出一些妥协,以实现其他设计目标,如高读取速度,但在大多数情况下,RION是相当紧凑的。

速度

我们对RION的另一个目标是让它读和写更快。每当必须在读取速度和写入速度之间进行权衡时,我们都倾向于读取速度,因为我们希望数据的读取频率高于写入频率。例如,一个RION文件可能被写入一次,然后读取多次。网络信息也是如此。它们被写入一次,然后在传输和处理过程中被读取一次或多次。

RION使用紧凑的二进制编码。这本身就使得它的读写速度比像XML、JSON和YAML这样的文本编码要快,并且与MessagePack、CBOR和亚马逊的ION不相上下。

此外,RION被设计成以二进制形式直接使用。当以二进制形式直接读取而不是首先反序列化为Java对象时,我们已经看到简单用例的速度提高了10倍。对于更高级的用例,加速可以更大也可以更小。

此外,RION的设计允许部分解析和任意层次导航。通常,在特定情况下,服务返回的数据可能超过给定客户端的需求。RION不需要解析所有返回的数据,而是让您能够高效地浏览您不需要的部分,找到您需要的部分。您可以通过导航二进制形式的RION数据,解析出您需要的字段,跳过其余的。

二进制编码

为了实现紧凑性和速度,RION使用了二进制编码。与文本编码相比,二进制编码能够对数字、日期和二进制数据进行更紧凑的编码。

反对二进制编码的一个常见理由是,在开发、调试、监控等过程中,二进制编码很难被人读懂。为了解决这个问题,我们目前正在研究RION的文本编码(目前称为TION),因此您可以将RION转换为TION,然后在文本编辑器中轻松阅读和编辑。行动还没有100%准备好,但我预计它将在2020年的某个时候。我们还实现了一个RION到“格式化十六进制符号”的转换器,使得在文本编辑器中检查原始字节值成为可能。

自我描述

RION使用自描述编码,这意味着您不需要一个模式来理解RION数据块。让数据格式具有自描述性使其更容易使用,因为您可以在不知道其模式的情况下浏览数据以查看其结构。这也使得为不知道消息模式的中间节点路由消息变得更加容易。

即使数据格式是自描述的,将它与模式结合起来仍然是有意义的。这就是XML + XML模式和JSON +斯瓦格/RAML的情况。该模式可以对给定字段允许什么值、期望什么字段等提供额外的限制。RION目前没有任何模式机制,但正在考虑中,

更多设计目标

为了让RION的这篇介绍性文章简短,我为RION留下了一些“不太重要”的设计目标。您可以在这里看到RION设计目标的完整列表:

http://tutorials.jenkov.com/rion/rion-design-goals.html

RION与其他数据格式的比较

在这一节中,我将尝试给你一个快速的概述,看看RION是如何不同于今天使用的许多其他流行的数据格式的。但是请记住,完整的概述需要对数据格式有深入的了解。因此,我在这篇文章中所能涉及的细节的深度是有限的。

首先,二进制数据格式使RION区别于CSV、XML、JSON和YAML。二进制意味着RION通常比这些格式更紧凑,读写速度更快。平均而言,RION比JSON紧凑10%到33%,如果用于表格数据,差异可能超过50%。这种紧凑性差异也转化为类似的读/写速度差异。

文本数据格式确实具有在文本编辑器中更容易阅读和编辑的优势,但是我们打算通过拥有RION (TION)的文本表示来解决这个问题,您可以将它转换成RION或从RION转换过来。这将减少人的可见性/可编辑性问题。

RION可以在文件的根级别包含多个字段。这使RION区别于只能在文件的根级别包含单个元素的XML和JSON。这使得RION更容易用于流数据结构,如日志文件和连续追加的数据文件。

RION使用了一种自我描述的二进制编码,类似于MessagePack、CBOR和亚马逊的ION。然而,RION在一些微妙但重要的方面有所不同。首先,RION是这些数据格式中唯一指定表格数据有效编码的格式。其次,RION在导航复合数据结构(如对象图)时,以二进制形式任意导航稍微容易一些。第三,RION将很快能够表示循环对象图。MessagePack、CBOR和亚马逊的ION目前都无法做到这一点。

除此之外,RION与MessagePack、CBOR和亚马逊的ION一样紧凑,读写速度也差不多,表格数据是RION的一大优势。

ProtoBuf、ASN.1和Avro都使用需要模式才能解析的数据编码。换句话说,它们不是自我描述的。在某些情况下,非自描述数据格式可以比自描述数据格式稍微紧凑一些,但是差别很小。然而,需要模式的数据格式可能更难处理,所以这是一个折衷。

有关更详细的概述,您可以查看我们自己的比较页面,我们会不时更新该页面。缺少一些数据格式,比如亚马逊的ION、YAML和XML,但我们最终会添加它们:

http://tutorials.jenkov.com/rion/rion-vs-other-formats.html

就性能而言,我们的测量结果显示,RION能够与MessagePack和CBOR的速度相匹配,同时接近ProtoBuf的速度。然而,我们所有的基准测试都是基于对象的序列化和反序列化。如果你以二进制形式直接使用RION,和/或只解析它的一部分,你可以大大提高速度。我们的基准有点旧了,所以我们需要尽快重新制定。但到目前为止,他们在那里:

http://tutorials.jenkov.com/rion/rion-performance-benchmarks.html

摘要和更多详细信息

总之,我们相信RION是当今最好的全方位数据格式之一。它提供了快速、高效的二进制编码,一组通用且灵活的字段类型,并且设计为可以直接以二进制形式读写(以提高速度),也可以序列化为对象或从对象反序列化。就速度而言,它将匹配最流行的数据格式,甚至可以超过表格数据格式,或者直接以二进制形式读取RION。

我们(Nanosai)花了相当多的时间分析RION并将其与其他数据格式进行比较,但是我们相信当前的编码提供了一个很好的扩展基础。我们还有几个角落需要处理(比如参考资料),但我们希望在2020年解决其中的大部分问题。随着RION变得越来越完整,我们将再次发布。

我们正在使用RION作为我们的网络协议IAP的消息编码,IAP是在应用层进行高效灵活的网络通信的超文本传输协议的替代方案。IAP仍在进行中,但是基础已经定义好了。

我们还使用RION作为记录格式,在我们的嵌入式数据流引擎Java的流操作中。《激流回旋》就像一盏“卡夫卡灯”。流操作目前处于概念验证阶段,但我们预计将在2020年对其进行改进。

因为流操作使用RION,我们可以达到一些相当好的记录处理吞吐速度。目前,我们已经能够在开发人员的笔记本电脑上将其压缩到每秒1950万条记录(小记录)。我们希望看到更多数据中心级硬件。从长远来看,我们实际上是在以每秒10亿张的速度拍摄,你可以在我们的1BRS challenge

目前,我们的RION开源工具包是用Java实现的,但是一旦它们稳定下来,我们也计划扩展到其他语言。可能首先是性能语言,比如C#,C/C++,然后可能是Python,因为它被大量用于数据科学。但这仍有待决定。

因此,如果您正在寻找一种快速、紧凑、通用的全方位数据格式,无论您是在进行高性能微服务、数据科学、卡夫卡、脉冲星、黑兹尔卡等事件驱动架构,让RION看一看都是值得的。


关于RION的更多信息

原始互联网对象符号(RION)是我们目前对这种数据格式的工作名称。我们以ION这个名字开始,但是一年后亚马逊发布了一个内部使用的名为ION的数据格式,所以我们转而使用RION。我们将来可能会再次更改名称,但是数据格式本身到现在已经相当稳定了。

对于对RION的所有细节感兴趣的人,请查看RION教程:

http://tutorials.jenkov.com/rion/index.html

我们还在开发一个开源工具包,用于在Java中与Rion一起工作,名为“面向Java的RION操作”。您可以在这里找到针对Java的RION操作:

https://github.com/nanosai/rion-ops-java


进一步阅读