1.概述

CBOR 是一种相对较新的 IETF 草案标准可扩展二进制数据格式。与 MessagePack 和 BSON 等类似格式相比,CBOR 是从头开始开发的,具有明确的目标:

  • 互联网标准中最常见数据格式的明确编码
  • 编码器和解码器的代码紧凑性
  • 不需要模式描述
  • 合理紧凑的序列化
  • 适用于受约束和不受约束的应用程序
  • 良好的 JSON 转换
  • 可扩展性

在数据存储和消息传递的上下文中,大多数开发人员可以将 CBOR 作为 JSON 的二进制替代品。虽然 CBOR 不具备 JSON 的人类可读性,但它可以有效且明确地对 JSON 难以处理的数据类型进行编码。CBOR 也可以使用标签进行扩展,以优化其标准原语之外的序列化。

2.编码二进制数据

JSON 是一种普遍存在于网络及其他领域的数据格式,原因有很多,但二进制数据的 blob 编码是 JSON 蹒跚的一个领域。例如,如果您正在设计一个 JSON 协议来包装任意对象的存储或传输,您的选择是:

  • 要求所有输入数据都可以表示为 JSON。如果可能,这可能是一个合理的解决方案,但会限制可以编码的数据类型。值得注意的例外包括最流行的图像编码,不包括 SVG。
  • Base64 将任何二进制数据值编码为字符串。这可以对任何二进制数据进行编码,但至少会增加 1/3 的数据大小,会产生编码和解码成本,并且需要使用魔法来指示字符串是 Base64 编码的。
  • 将字节编码为数字数组或十六进制字符串。这些可能不是您应该做的事情,但似乎值得一提的是,这些技术将数据的大小从 2 倍增加到 5 倍,并且还需要魔术来表明数据确实是二进制的。

使用 CBOR,开箱即用支持任意长度的二进制 blob,并以 1:1 编码。CBOR 字节字符串的编码和解码速度非常快,即使在高级语言中也是如此。在 JavaScript 的情况下,CBOR 字节字符串可以在非常快速和高效的Uint8Array 转码。

例如,让我们尝试用两个字段编码一个简单的对象:“名称”和“数据”。此对象的抽象视图:

name: "Strawberry Pie"
data: <00 01 02 03 04 05 06 07 08 09>

此原始数据的 AC 结构绝对最小为 24 个字节。 如果您将数据 Base64 转换为 JSON,您的输出可能如下所示:

{"name":"Strawberry Pie","data":"AAECAwQFBgcICQ=="}

这说明了在 JSON 中使用 Base64 编码二进制数据的“神奇”问题。除非您有 JSON 模式或特殊协议字段,否则解码器不会指示此对象中的数据需要进行 Base64 解码,因为它看起来像一个字符串。它不是自我描述的。

相同输入数据的 CBOR 表示,作为十六进制字符串:

a2646e616d656e5374726177626572727920506965696a7065675f646174614a00010203040506070809

哇,那里。所有这些数字和字母是什么意思?我想念我的 JSON!Node cbor包有一个方便的cbor2comment工具来为我们注释这个十六进制字符串。

  a2                -- Map, 2 pairs
    64              -- String, length: 4
      6e616d65      -- {Key:0}, "name"
    6e              -- String, length: 14
      5374726177626572727920506965 -- {Val:0}, "Strawberry Pie"
    64              -- String, length: 4
      64617461 -- {Key:1}, "data"
    4a              -- Bytes, length: 10
      00010203040506070809 -- {Val:1}, 00010203040506070809

长度:35 个字节。

现在让我们使用真实的 JPEG 数据针对 CBOR 对 JSON 进行基准测试。对于这个测试,我使用了cbor-js 的修改版本,这是一个兼容 Node 和浏览器的库,并编码了一个 910,226 字节的草莓大黄派 JPEG。

|                           | JSON      | CBOR    |
| :------------------------ | --------: | ------: |
| Median encoding time (ms) | 3.983     | 0.538   |
| Median decoding time (ms) | 3.151     | 0.006   |
| Encoded size (bytes)      | 1,213,676 | 910,262 |

正如数字所示,CBOR 对于这些特定数据来说更快、更简洁。此外,CBOR派的味道更好。 

3.使用标签优化 CBOR

在编码同构数值数组的情况下,CBOR 编码器可能难以优化数据的打包。例如,如果您有一个使用 Python 或 JavaScript 等高级语言的浮点数数组,则 CBOR 编码器实现不一定确定对数字进行编码所需的位数,默认为可用的最大位数。此外,数组中的每个值都将单独描述为浮点数。这大大增加了数据的成本和大小。

CBOR 对这个问题有一个答案。类型化数组标签草案规范包括指定类型化数组的标签,这些类型恰好与 JavaScriptTypedArray风格相匹配。

例如,假设您有一个Float32Array带有几个值的 a:

const floats = new Float32Array([1.234567, 2.345678, 3.456789]);

JSON 有一种非常有趣的编码 a 的方式Float32Array,看看所有这些字节:

{"0":1.2345670461654663,"1":2.3456780910491943,"2":3.456789016723633}

长度:69 字节。

如果我们通过发送常规来帮助编码器,Array它仍然会非常冗长,但是我们没有使用的精度会被截断,所以总长度会根据 中的值而有很大差异Array:

[1.234567,2.345678,3.456789]

长度:28 字节。

善意的 Node cbor 库可以Float32Array直接编码,但不会尝试优化大小:

 83                -- Array, 3 items
    fb              -- Float, next 8 bytes
      3ff3c0c960000000 -- [0], 1.2345670461654663
    fb              -- Float, next 8 bytes
      4002c3f2e0000000 -- [1], 2.3456780910491943
    fb              -- Float, next 8 bytes
      400ba78100000000 -- [2], 3.456789016723633

长度:28 字节。

看看所有浪费的精度,每个 32 位浮点数 64 位,这是行不通的!CBOR 规范允许您“标记”数据以进行特殊处理。根据已注册的 CBOR 标签列表,“IEEE 754 binary32, little endian, Typed Array”为标签 85。三个数字的连续字节紧随其后。

  d8                --  next 1 byte
    55              -- Tag #85
      4c            -- Bytes, length: 12
        4b069e3f971f1640083c5d40 -- 4b069e3f971f1640083c5d40

长度:15 个字节。

包含的 12 字节字符串等价于 Float32Array 下的 ArrayBuffer 中的值。

CBOR 解码器将在其关联的 blob 旁边吐出标签,因此我们的优化是自我描述的。现在我们需要确保带有此标记的字节字符串正确转换为类型化数组,注意字节顺序。在成熟的 JavaScript 实现中,这既简单又快速。ArrayBuffer因为我们对a 下面的值进行了编码Float32Array,所以我们可以从 a 构造一个新Float32Array的ArrayBuffer。

const floats = new Float32Array(bytes);  // assuming platform and bytes are same endianness!

这是一种在 JavaScript 中读取和写入数值数组的非常可扩展的方式。

4.何时使用 CBOR

我发现 CBOR 可作为 JSON 的替代品,用于处理大型(>2kB)原始数据块或数值数组。在许多其他情况下,JSON 是等效的或更好的,因为大多数语言在其标准库中都有本机 JSON 编码和解码。CBOR 编码器并不总是如此优化,但随着更广泛的采用,差距正在缩小。在决定使用 CBOR 之前,针对真实库对真实数据运行您自己的测试和基准测试。

许多读者会认识到,诸如协议缓冲区之类的模式格式是结构化数据的最后阶段。如果基础设施需求对您的应用程序有意义,这也是一个不错的方法。如果您正在使用已使用 JSON 的应用程序,则应根据每种方法的大小和性能增益来衡量将其移植到 CBOR 或类似 protobuf 的开发和维护成本的差异。

 

全文请看原文信息

原文转载自:问我学院,问我社区
原文链接:http://www.wenwoha.com/blog_detail-1663.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐