3. 数据序列化与反序列化:Protobuf vs JSON vs MessagePack

做市商系统里,数据怎么在进程间、机器间高效传输?

这个问题我琢磨了很久。说白了,就是序列化与反序列化的选择。你想想看,每秒几万笔订单,每笔订单包含价格、数量、时间戳、订单ID……如果序列化效率低,整个管道的吞吐量就上不去。

我个人习惯把序列化方案分成三类:文本型(JSON)、二进制紧凑型(MessagePack)、二进制强类型型(Protobuf)。今天咱们就掰开揉碎聊聊这三兄弟。

3.1 三种方案的底层逻辑

JSON:人类可读,调试方便。但它的Schema是隐式的,解析时得动态构建对象树。我在项目中遇到过,一个嵌套5层的JSON结构,解析耗时占了整个请求处理时间的40%。

MessagePack:本质上是JSON的二进制变体。它用更少的字节表示相同的数据。比如数字123,JSON要存成字符串"123"占3字节,MessagePack只占1字节(0x7B)。但它的Schema依然是隐式的,这点和JSON一样。

Protobuf:Google出品,强类型。你得先定义.proto文件,然后生成代码。它的编码方式很聪明——用字段编号代替字段名,用Varint压缩整数。我做过测试,同样的订单数据,Protobuf比JSON小60%左右。

核心结论:JSON适合配置和调试,MessagePack适合对延迟不敏感但带宽有限的场景,Protobuf适合高性能、高吞吐的做市商核心链路。

3.2 Schema管理——别让数据变成一团乱麻

做市商系统里,数据格式会变。今天加个字段,明天改个类型。如果没有Schema管理,你会陷入噩梦。

我曾经接手过一个遗留系统,订单消息用JSON,但不同版本之间字段名大小写不统一。有的地方用"orderId",有的用"order_id"。解析时各种if-else,维护成本极高。

我的建议是:

  • Protobuf:天然支持Schema。.proto文件就是契约。用optionalrepeated处理可选字段和重复字段。版本升级时,遵循向后兼容原则——只加字段,不改已有字段编号。
  • JSON/MessagePack:需要手动维护Schema文档。我习惯用JSON Schema规范,配合代码生成工具(如quicktype)生成强类型类。但说实话,这不如Protobuf原生支持来得自然。

避坑指南:我曾经在.proto文件中使用required关键字,结果后来要删除这个字段时,发现所有历史数据都解析失败了。现在我只用optionalrepeated,绝不使用required

3.3 编解码性能基准测试

光说不练假把式。咱们直接看数据。

测试环境:Intel Xeon Gold 6248 @ 2.5GHz,32GB RAM,JDK 11。测试数据:100万条订单消息,每条包含10个字段(int64, string, double, int32, bool等)。

指标 JSON (Jackson) MessagePack (msgpack-java) Protobuf (protobuf-java)
序列化耗时 (ms) 1,245 987 412
反序列化耗时 (ms) 1,532 1,102 489
数据大小 (MB) 45.6 32.1 18.3
GC压力 (Minor GC次数) 23 17 6

看到没?Protobuf在序列化速度、数据大小、GC压力上全面领先。MessagePack比JSON好一些,但差距不大。

为什么会这样?

JSON解析时,Jackson需要先构建JsonNode树,再映射到Java对象。这个过程会产生大量临时对象。Protobuf直接操作字节流,用预生成的代码解析,几乎没有临时对象。

我印象很深,有一次优化做市商系统的行情推送管道。原来用JSON,GC暂停时间平均8ms,偶尔飙到30ms。换成Protobuf后,GC暂停降到2ms以下,再也没有超过5ms。嗯,这就是差距。

3.4 实战中的选择策略

做市商系统里,我一般这样选:

  • 行情数据推送:Protobuf。延迟敏感,数据量大,Schema稳定。
  • 订单日志:MessagePack。需要持久化,带宽有限,但Schema偶尔变化。
  • 配置文件和REST API:JSON。人类可读,调试方便,性能不是瓶颈。
  • 进程间通信(IPC):Protobuf。共享内存或Unix Domain Socket场景下,零拷贝优势明显。

注意:不要盲目追求极致性能。如果你们的系统每秒只有几百笔订单,JSON完全够用。引入Protobuf会增加编译步骤和Schema维护成本。我见过一个团队,为了用Protobuf而用Protobuf,结果.proto文件版本混乱,反而降低了开发效率。

3.5 知识体系图

下面这张图,是我梳理的数据序列化选型决策流程。你可以把它贴在工位上。

数据序列化选型决策流程 数据序列化需求 延迟敏感? Protobuf 强类型,高性能 Schema稳定? MsgPack 带宽敏感 JSON 灵活,可读 做市商系统数据管道设计实战 · 序列化选型 高性能链路 带宽敏感 灵活配置

这张图的核心逻辑:先问延迟敏感不敏感。敏感,直接上Protobuf。不敏感,再看Schema稳定性。Schema稳定,用MessagePack省带宽;Schema不稳定,用JSON保灵活。

好了,关于数据序列化,我就讲这么多。记住一句话:没有银弹,只有最适合你场景的方案。


公众号:蓝海资料掘金营,微信deep3321