数据存储和传输的二进制编码格式概述

数据存储和传输的二进制编码格式概述

原创 夏群林 2025.12.27

数据存储与传输,一是追求"高效",即体积足够小,降低硬盘存储成本、减少网络带宽消耗;同时,解析足够快,减少CPU运算开销。二是必须"兼容",即能跨编程语言、跨硬件设备正常交互,最好能贴合业务场景的特殊需求,如数据库的索引,嵌入式设备的低内存占用刚需。

JSON(JavaScript Object Notation)大体满足这些需求,成为主流文本格式,深刻影响跨系统数据交互。所有现代浏览器均原生支持JSON序列化/反序列化,几乎所有编程语言都内置相关工具,无需额外依赖,是前端与后端、跨语言系统数据交互的通用语言。"轻量级文本数据交换格式"的核心定位,极其成功。

JSON诞生于2002年,基于JavaScript的对象字面量语法,相对于其后各种各样的数据编码格式,其核心价值,在于奠定了数据格式的易用性基准:

  • 人类可读可写:采用纯文本结构,用{}、[]、:、,等简单语法标记对象、数组与键值对,无需工具即可直接阅读和修改,调试成本极低,这是其区别于二进制格式的核心特征;

  • 可表达任意数据类型:虽原生仅支持字符串、数字、布尔、数组、对象、null六种基础类型,但通过对象、数组的嵌套组合,理论上可表达任意复杂数据结构,适配多数业务场景的存储传输需求。

    例如:描述用户信息的嵌套JSON结构

    json 复制代码
    {
        "id":1001,
        "name":"张三",
        "age":28,
        "isVIP":true,
        "address":
        {
            "province":"广东",
            "city":"深圳"
        },
        "hobbies":["读书","运动"]
    };

是不是一目了然?当然,有代价:

  • 冗余:为保证可读性,JSON需用大量冗余字符,如双引号包裹字符串、冒号分隔键值、逗号分隔元素。一个键值对{"age":25},JSON需10个字符(UTF-8编码下占10字节),有效数据("age"和25)仅占4字节,冗余率超50%;上述用户信息JSON(共118个字符,占118字节),冗余字符占比达35%以上;

  • 解析慢:JSON本质是文本,解析时需先逐字符扫描语法,识别{}、:等符号,再将字符串类型的数值、布尔值转换为程序原生类型,如"25"转int,步骤繁琐且耗时,CPU开销大;

  • 原生类型少:仅支持字符串、数字(无整数/浮点数细分)、布尔、数组、对象、null六种类型,缺少数据库/复杂应用必需的类型,如时间戳、二进制数据、正则表达式、地理空间数据等;

在JSON之前,XML与YAML曾是文本类数据交换的核心选择,XML以强结构化、可扩展性著称,适合复杂文档与配置场景;YAML以简洁的缩进语法实现可读性与结构化平衡。JSON则平衡了结构化能力与轻量简洁,解析效率优于XML、兼容性强于YAML,成为跨系统文本交互的首选。

随着应用场景从轻量交互转向海量数据存储与高频通讯,冗余成本会急剧放大。在微服务高频RPC调用、物联网设备低带宽传输、海量日志存储等场景中,体积与解析速度成为性能瓶颈。JSON的固有痛点逐渐凸显,二进制编码格式随之诞生。Protobuf、MessagePack、BSON、CBOR等,让人眼花缭乱。

二进制编码的基本原理

所有二进制编码格式,无论定位如何差异,其底层都共享一套核心转换原理:类型/长度标记 + 原生二进制数据 ,这是理解各类二进制格式设计逻辑的基础。它以解决JSON在存储传输中体积大、解析慢痛点为目标,剔除冗余、直接存储有效数据,替代JSON的文本语法+字符串存储模式,适配存储传输对小体积、快解析的需求。

  1. 类型/长度标记(Tag):核心是用1~4字节的二进制小标签,同时说明两个关键信息,数据类型(如整数、字符串、对象)和数据长度(如字符串占4字节、数组含2个元素),直接替代JSON的冗余语法。

比如:表达"name字段,值为张三(字符串类型,长度4)",JSON需写""name":"张三""(含双引号、冒号共8字节);二进制格式用1字节标记(比如0xA4,其中高4位表字符串类型,低4位表长度4)+4字节"张三"的UTF-8编码,总字节数仅5字节,直接省掉3字节冗余;

  1. 原生二进制数据(Value):按计算机"原生语言"存储数据,避免JSON"所有数据转字符串"的低效操作。
数据内容 JSON存储(字符串形式) 二进制存储(原生格式) 体积节省比例
整数25 "25"(2字节) 0x19(1字节varint编码) 50%
布尔值true "true"(4字节) 0x01(1字节) 75%
字符串"张三" ""张三""(6字节) 0xE5BCA0E4B889(4字节UTF-8) 33%
  1. 结构化组织:整个二进制流由"标记+数据"的字段单元串联而成,无额外分隔符。解析逻辑简单直接:先读标记(知道后续数据是"字符串+长度4"),再精准读4字节数据即可,无需像JSON那样逐字符扫描"{、}、:"等语法符号。

比如解析上述用户信息,JSON需扫描118个字符识别语法,二进制格式仅需按"读标记→读数据"的逻辑读取6个字段单元,解析速度提升至少2倍;

基于这套核心转换原理,各类二进制格式的差异本质是对性能、灵活性、通用性三大维度的权衡:

  • 性能:核心衡量指标为"体积压缩比"(相较于文本格式的字节数减少比例)和"解析速度"(序列化/反序列化的CPU耗时)。极致性能通常依赖"精简冗余信息""原生数据存储""预定义结构"等设计。
  • 灵活性:核心是"数据结构的适配能力",包括是否需要预定义Schema(协议)、支持的数据类型丰富度、能否动态新增/删除字段。高灵活性适合异构数据、频繁迭代的场景。
  • 通用性:核心是"跨场景、跨系统的适配能力",包括跨语言支持广度、官方/社区标准化程度、生态工具完善度(如调试工具、集成插件)。高通用性降低多系统协作的沟通与开发成本。

这三大维度决定了它们的优化方向,有侧重性能的,有侧重灵活性的。Protobuf、MessagePack、BSON是当前应用最广泛的三类二进制编码格式,分别代表了通讯优先、通用兼容优先、文档存储优先的设计方向,三者共同占据二进制编码市场70%以上份额。它们均遵循类型/长度标记+原生二进制数据的核心转换原理,只是对三大维度的权衡不同,形成了差异化的适用场景。

MessagePack:JSON的二进制平替

MessagePack的核心定位是"像JSON一样易用,但更小、更快",本质是JSON的二进制超集。由社区主导开发,无单一官方强制主导方,其标准化由社区主导,拥有清晰的编码规范,虽无官方强制标准,但社区的实现高度统一。零学习成本、无缝兼容JSON,是最通用的二进制格式。

MessagePack 严格遵循"类型/长度标记+原生二进制数据"的核心转换原理,重点保留JSON的灵活性,不做极致压缩以追求性能:

  • 类型/长度标记:灵活性优先:用1字节二进制标记同时表类型与长度(如0xA4表"长度4的字符串",0x19表"正整数25"),替代JSON的双引号、冒号等冗余字符。为兼容动态类型,标记覆盖更多场景,体积略大于Protobuf,但灵活性更高;
  • 原生数据+类型扩展:按原生格式存储数据(整数存varint、字符串存UTF-8),同时完整支持JSON所有基础类型,新增二进制数据、64位整数等JSON缺失类型;
  • 无Schema设计:无需预定义结构,可直接序列化/反序列化任意JSON兼容数据,解析逻辑与JSON一致但更高效,开发者无需改变习惯即可升级。

MessagePack 的综合表现

  • 性能:中高------体积比JSON小30%-50%,解析速度是JSON的2-10倍,略逊于Protobuf但远超BSON;

  • 灵活性:极高------无Schema约束,支持动态新增字段、异构数据,可与JSON双向无缝转换,调试时可直接转为JSON查看;

  • 通用性:极强------支持50+编程语言(覆盖主流及小众语言),社区库成熟,集成成本低,是"不想改架构却想优化JSON性能"的最优解。

MessagePack 典型应用

Redis缓存的二进制存储格式、Elasticsearch的部分数据序列化、前后端高性能API交互(如移动端节省流量)、多语言微服务的轻量数据交换、日志系统的压缩存储。

Protobuf:通讯高性能之选

Protobuf(Protocol Buffers)由Google于2008年开源,核心定位是跨系统高效通讯,专为解决微服务、分布式系统间数据传输的"体积大、解析慢、版本兼容难"问题设计。其标准化由Google主导,目前最新稳定版为Protobuf 3,拥有严格的语法规范(.proto文件)和多语言官方实现指南,是工业级通讯场景的事实标准。

Protobuf 本质是对类型/长度标记+原生二进制数据原理的极致优化版落地,通过静态Schema、字段编号等设计,进一步压缩标记体积、提升解析效率。

  • 静态Schema奠基:需提前通过.proto文件定义数据结构(含字段名、类型、唯一编号),编译后生成对应语言代码。强类型约束使"类型/长度标记"更精简(无需兼容动态类型),同时减少解析错误,为高效编码奠定基础。

  • 字段标记极致压缩 :遵循"标记+数据"逻辑,将标记设计为"字段编号+类型编号"的复合结构,核心计算公式为 tag = (字段编号 << 3) | 字段类型编号。具体示例:.proto中定义"name字段(编号1,字符串类型,类型编号2)",计算得tag=(1<<3)|2= 8+2=10(十六进制0xA),用varint编码后仅占1字节;若直接存储字段名"name"需4字节,仅标记就节省75%体积。字段编号为.proto中定义的唯一数字(如1、2),类型编号为Protobuf预定义码(0=varint整数、1=fixed64、2=长度前缀型);整个tag以varint编码存储,小数字仅占1字节,相比存储完整字段名大幅节省体积。

  • 原生数据定制化编码:完全遵循"原生二进制存储"逻辑,针对不同数据类型优化:① varint(变长整数):小整数(0-127)占1字节,大整数按需扩展,比JSON字符串存储节省50%空间;② 长度前缀型:字符串、bytes、嵌套对象先存长度(varint编码)再存数据,避免冗余分隔符;③ 固定长度编码:fixed32/fixed64适配浮点数、大整数,平衡解析速度与体积。

  • 结构化字段单元:二进制流由"字段标记(tag)+字段值(value)"单元串联而成,解析时按"读标记→判类型/长度→读数据"逻辑还原,无需扫描语法符号,解析效率显著提升。

Protobuf 表现

  • 性能:极致领先------得益于"字段编号替代字段名""varint极致压缩""无冗余语法"的设计,体积比JSON小50%-70%,解析速度是JSON的10-30倍,远超MessagePack、BSON等JSON Binary,彻底解决JSON在高频通讯场景的性能瓶颈。

  • 灵活性:较低但适配迭代需求------强依赖Schema,字段新增/修改需同步更新.proto文件,不适合动态异构数据;但通过"字段编号固定"实现天然版本兼容,老版本可忽略新增字段,适配长期迭代的系统。

  • 通用性:强且生态完善------官方支持20+主流语言(Go、Java、Python、C++等),深度集成grpc等RPC框架,配套调试、编译工具齐全,是工业级跨系统通讯的事实标准。

Protobuf 典型应用

Google内部所有微服务通讯、Kubernetes组件交互、grpc框架默认编码格式、抖音/快手等短视频平台的跨服务数据传输、游戏服务器与客户端的实时数据同步。

BSON:文档存储的专属格式,MongoDB生态核心

BSON(Binary JSON)由MongoDB团队设计,核心定位是文档数据库的原生存储与传输格式,专为解决JSON不适合数据库存储(缺少日期、二进制类型,无法高效索引)的痛点。其标准化由MongoDB官方主导,规范与MongoDB的查询、索引功能深度绑定。

BSON 优化重点是在原理基础上适配数据库存储需求,与Protobuf的通讯场景优化形成差异:

  • 类型标记:扩展存储必需类型:保留核心标记逻辑,新增数据库专属类型标记(ObjectId、Date、地理空间数据等),解决JSON类型匮乏问题;

  • 结构优化:适配存储解析:采用"文档长度前缀+标记+键值对"结构,文档开头存储总长度,方便数据库快速定位文档边界;保留字段名字符串,确保查询语义清晰;

  • 索引友好设计:支持内嵌文档深度索引(如查询"user.address.city"),其"标记+数据"的嵌套结构让数据库可高效定位字段,解决JSON难索引的痛点。

BSON 表现

  • 性能:中高------体积比JSON小20%-40%,解析速度是JSON的5-15倍,因存储字段名导致体积略大于MessagePack;

  • 灵活性:高------无Schema约束,支持动态字段与复杂嵌套结构,专属类型适配数据库存储需求;

  • 通用性:中等------主要适配MongoDB生态,跨语言支持集中在数据库交互场景(如MongoDB客户端),通用通讯场景应用较少。

BSON 典型应用

MongoDB数据库的所有文档存储与客户端-服务器通讯、基于MongoDB的内容管理系统(如电商产品详情存储)、IoT设备的异构数据存储(如传感器数据+时间戳)。

其他常见二进制编码格式

除上述头部二进制编码格式类型外,以下格式在特定场景中应用广泛,形成补充生态:

1) CBOR:标准化的二进制JSON

CBOR(Concise Binary Object Representation)是IETF标准化的二进制JSON格式(RFC 8949),定位与MessagePack类似,但更强调"严格标准化"。原理与MessagePack接近(类型标记+长度前缀),支持更多标准扩展类型(如decimal、bigint)。优势是标准化程度高,适合金融、物联网等对规范一致性要求高的场景;劣势是生态完善度略逊于MessagePack。

2) UBJSON:简单易实现的二进制JSON

UBJSON(Universal Binary JSON)定位"极简实现",编码规则比MessagePack更简单(如用固定字符标记类型,而非二进制),适合资源受限的嵌入式设备或快速开发场景。性能与BSON接近,通用性中等,因实现成本低被部分小众IoT设备采用。

3)FlatBuffers:零拷贝的嵌入式/游戏首选

FlatBuffers由Google开源,核心定位是"零拷贝解析",专为嵌入式设备、游戏等"内存/CPU资源紧张"的场景设计。原理是"预定义Schema+固定偏移量存储",解析时无需反序列化整个数据,直接通过偏移量读取字段,解析速度极致。劣势是灵活性低、开发成本高,仅适合性能敏感的特定场景。

4) Thrift:RPC绑定的多格式编码

Thrift由Apache开源,本质是RPC框架,但其内置二进制编码格式(TBinaryProtocol)在分布式系统中应用广泛。支持静态Schema,性能接近Protobuf,优势是与RPC框架深度集成,适合"编码+通讯"一体化需求;劣势是通用性略逊于Protobuf。

主流格式对比表

格式 性能(体积/速度) 灵活性(Schema/类型) 通用性(跨语言/标准化) 核心解决的JSON痛点 核心优势场景
Protobuf ★★★★★ 极致 ★★☆ 强Schema,版本兼容好 ★★★★☆ 官方多语言支持 体积大、解析慢、版本兼容难 微服务通讯、跨系统RPC
MessagePack ★★★★☆ 优秀 ★★★★★ 无Schema,兼容JSON+扩展 ★★★★★ 50+语言支持 体积大、解析慢、类型少 通用JSON优化、缓存、轻量传输
BSON ★★★★☆ 优秀 ★★★★☆ 无Schema,数据库专属类型 ★★★☆☆ 适配MongoDB生态 类型少、难索引、不适配存储 文档数据库存储、MongoDB交互
CBOR ★★★★☆ 优秀 ★★★★☆ 无Schema,标准扩展类型 ★★★★☆ IETF标准 体积大、类型少、标准化弱 金融、IoT等强规范场景
FlatBuffers ★★★★★ 零拷贝极致 ★★☆ 强Schema ★★★☆☆ 嵌入式语言支持 解析慢、内存开销大 嵌入式设备、游戏实时数据

选型建议:

  • 锚定核心痛点:高频通讯延迟→Protobuf;JSON优化且不改动架构→MessagePack;文档存储+高效查询→BSON;强标准化→CBOR;嵌入式/游戏低内存→FlatBuffers;
  • 权衡三大维度:性能极致优先→牺牲灵活性(Protobuf/FlatBuffers);灵活性优先→接受小幅性能损耗(MessagePack/BSON);
  • 兼顾生态成本:已用MongoDB→BSON;已用gRPC→Protobuf;重度依赖JSON→MessagePack,降低迁移成本。

总结

本文核心结论:"类型/长度标记+原生二进制数据"是所有二进制编码格式的统一转换原理,Protobuf完全遵循此原理且做极致优化------这两大要点是理解二进制编码的支柱。二进制编码格式的诞生,本质是通过核心原理解决JSON的核心痛点;各类格式的差异,仅是在原理基础上对"性能、灵活性、通用性"的权衡。

三大主流格式的核心差异,本质是优化方向的不同:Protobuf在原理基础上拉满"性能",成为通讯场景王者;MessagePack保留原理且兼顾JSON灵活性,成为通用优化首选;BSON基于原理适配存储需求,锁定MongoDB生态。

未来趋势聚焦三点:一是"核心原理的场景化深化",针对AI张量、车联网等场景设计专属标记与编码;二是"Protobuf式优化普及",更多格式借鉴其极致性能设计;三是"生态一体化",编码格式与RPC框架、数据库的集成更紧密。对开发者而言,掌握核心转换原理与Protobuf的优化逻辑,即可快速理解任意二进制格式,精准选型。