强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

MessagePack 序列化完全指南 / 01 - MessagePack 概述 / Introduction to MessagePack

MessagePack 概述 / Introduction to MessagePack

MessagePack 是什么? / What is MessagePack?

MessagePack(全称 MessagePack Binary Serialization Format)是一种高效的二进制序列化格式,由日本开发者 Sadayuki Furuhashi 于 2008 年创建。它的设计目标是:

“It’s like JSON, but fast and small.” “像 JSON 一样灵活,但更快、更小。”

MessagePack 在功能上与 JSON 最为接近——都是无 Schema、自描述的序列化格式——但采用二进制编码,因此在体积和速度上有显著优势。

MessagePack is functionally closest to JSON — both are schema-free, self-describing serialization formats — but MessagePack uses binary encoding, resulting in significant size and speed advantages.


📖 设计目标 / Design Goals

MessagePack 的设计围绕以下核心原则:

1. 紧凑性(Compactness)

通过变长编码(Variable-length Encoding)减少数据体积:

数据类型JSON 编码MessagePack 编码节省
整数 4242(3 字节)0x2a(1 字节)67%
字符串 "hello""hello"(7 字节)\xa5hello(6 字节)14%
布尔 truetrue(4 字节)\xc3(1 字节)75%
nullnull(4 字节)\xc0(1 字节)75%
数组 [1,2,3][1,2,3](7 字节)\x93\x01\x02\x03(4 字节)43%

2. 跨语言互操作性(Cross-language Interoperability)

一次序列化的数据可以在不同语言之间无缝传递:

Python 序列化 → 网络传输 → Go 反序列化 → 业务处理

3. 简单性(Simplicity)

  • 无需 Schema 定义文件
  • 类型系统与主流语言自然映射
  • 规范文档仅约 20 页

4. 速度(Speed)

序列化/反序列化速度远超 JSON,接近 Protocol Buffers:

序列化速度基准(相对值,越高越快):
JSON:     ████░░░░░░  1.0x
MsgPack:  ████████░░  3.5x
Protobuf: █████████░  5.0x

📖 与 JSON 对比 / Comparison with JSON

JSON 是目前最广泛使用的数据交换格式。MessagePack 经常被定位为 “JSON 的二进制替代品”。

核心区别

维度JSONMessagePack
编码方式文本(UTF-8)二进制
可读性✅ 人类可读❌ 需要工具解析
类型支持string, number, bool, null, array, object同上 + binary, extension, 区分 int/float
整数精度所有 number 都是 float64区分 uint8/16/32/64, int8/16/32/64
二进制数据需要 Base64 编码原生支持
调试直接 cat 查看需要 xxd 或专用工具
浏览器原生支持JSON.parse/stringify❌ 需要第三方库

代码对比

// JSON 编码
{"id": 1, "name": "Alice", "tags": ["dev", "ops"]}

对应的 MessagePack 二进制(十六进制表示):

83 a2 69 64 01 a4 6e 61 6d 65 a5 41 6c 69 63 65
a4 74 61 67 73 92 a3 64 65 76 a3 6f 70 73
  • JSON 版本:51 字节
  • MessagePack 版本:39 字节
  • 节省 23.5%

何时选 JSON?

场景推荐
前后端 REST APIJSON(浏览器原生支持)
配置文件JSON(人类可读)
日志可读性要求高JSON
高频 RPCMessagePack
带宽受限MessagePack
嵌入式设备MessagePack

📖 与 Protocol Buffers 对比 / Comparison with Protobuf

Protocol Buffers(Protobuf)是 Google 开发的语言中立、平台中立的序列化机制。

核心区别

维度MessagePackProtocol Buffers
Schema不需要(自描述)必须(.proto 文件)
版本兼容天然兼容(无 Schema)需要字段编号管理
数据大小较小更小(字段用编号而非名称)
编解码速度更快(编译期优化)
学习曲线中(需要学 .proto 语法)
动态结构✅ 运行时可变❌ 编译期确定
适用场景通用数据交换大规模 RPC 系统

代码对比

// Protocol Buffers 需要先定义 Schema
syntax = "proto3";

message User {
  int32 id = 1;
  string name = 2;
  repeated string tags = 3;
}
# MessagePack 无需 Schema,直接序列化
import msgpack

user = {"id": 1, "name": "Alice", "tags": ["dev", "ops"]}
packed = msgpack.packb(user)

何时选 Protobuf?

场景推荐
大型微服务系统(gRPC)Protobuf
需要严格类型检查Protobuf
快速原型开发MessagePack
数据结构经常变化MessagePack
与已有 JSON 系统集成MessagePack

📖 与 Apache Avro 对比 / Comparison with Avro

Apache Avro 是 Apache Hadoop 生态中的序列化系统,广泛用于大数据场景。

核心区别

维度MessagePackAvro
生态独立库Hadoop/Kafka/Flink 生态
Schema不需要必须(.avsc JSON Schema)
Schema 演进不适用✅ 强大的演进支持
数据大小较小更小(Schema 已知时可省略字段名)
序列化格式自描述需要 Schema 才能解码
块压缩不支持✅ 支持 Snappy/LZ4/Zstandard
适用场景通用 RPC/缓存大数据管道/数据湖

何时选 Avro?

场景推荐
Kafka 消息格式Avro(Kafka 原生支持)
数据湖存储Avro
通用 RPCMessagePack
临时数据交换MessagePack

📖 适用场景详解 / Detailed Use Cases

场景 1:高频 RPC 通信

在微服务架构中,服务间每秒可能有数万次调用。使用 MessagePack 替代 JSON 可以:

  • 减少 30%–50% 的网络带宽
  • 降低序列化/反序列化 CPU 开销
  • 减少网络延迟
┌──────────┐   msgpack binary   ┌──────────┐
│ Service A │ ──────────────────→ │ Service B │
│ (Python)  │ ←────────────────── │ (Go)      │
└──────────┘   msgpack binary   └──────────┘

场景 2:实时消息推送

WebSocket / MQTT 场景中,消息体积直接影响并发能力:

格式消息大小每秒可推送消息数
JSON200 bytes50,000
MessagePack120 bytes83,000

场景 3:缓存序列化

Redis 中存储序列化对象时,MessagePack 比 JSON 更节省内存:

import msgpack
import json

user = {"id": 12345, "name": "Alice", "roles": ["admin", "editor"]}

json_size = len(json.dumps(user).encode())      # 57 bytes
mp_size = len(msgpack.packb(user))               # 41 bytes

# 节省 28%

场景 4:IoT 设备通信

嵌入式设备资源受限,MessagePack 的紧凑编码可以:

  • 减少 LoRaWAN/NB-IoT 等窄带网络的传输时间
  • 降低设备功耗
  • 在有限的 MTU(最大传输单元)内传输更多数据

场景 5:游戏服务器

实时游戏对延迟极其敏感:

数据JSONMessagePack
玩家位置 {x:100,y:200,z:50}31 bytes12 bytes
批量更新(100 玩家)3,100 bytes1,200 bytes

📖 MessagePack 的局限性 / Limitations

局限说明应对方案
不可读二进制格式无法直接查看使用 msgpack-toolsxxd 查看
浏览器支持弱需要引入 JS 库仅在性能敏感时使用
无 Schema 验证不像 Protobuf 有编译期检查自行添加数据校验层
浮点数精度默认使用 float64明确指定 float32/float64
字符串编码规范为 UTF-8,但部分库不强制注意库的配置
字典键排序不保证顺序如需有序,业务层处理

⚠️ 注意事项 / Pitfalls

1. 类型映射差异

不同语言对 MessagePack 类型的映射不完全一致:

MessagePack 类型PythonJavaScriptGoJava
fixstrbytesstringstringString
binbytesUint8Array[]bytebyte[]
fixintintnumberint64long
float64floatnumberfloat64double

⚠️ Python 的关键陷阱:默认情况下,MessagePack 的 string 会被解码为 bytes 而非 str。需要设置 raw=False

import msgpack

data = msgpack.packb("hello")
# 默认行为
print(msgpack.unpackb(data))           # b'hello' (bytes!)
# 正确做法
print(msgpack.unpackb(data, raw=False)) # 'hello' (str)

2. null vs nil

JSON 的 null 和 MessagePack 的 nil 在大多数语言中都映射为 null/None/nil,但要注意 Python 中:

msgpack.packb(None)  # b'\xc0' (nil)

3. 嵌套深度限制

部分库对嵌套深度有限制,过深的嵌套可能导致栈溢出:

# 构造 1000 层嵌套
deep = {"a": None}
for _ in range(1000):
    deep = {"a": deep}
# 某些库可能崩溃

💻 快速体验 / Quick Hands-on

安装 Install

# Python
pip install msgpack

# JavaScript
npm install @msgpack/msgpack

# Go
go get github.com/vmihailenco/msgpack/v5

# Rust
cargo add rmp-serde serde

二进制查看 / Inspect Binary

# 安装 msgpack-cli (跨平台工具)
pip install msgpack-tools

# 或直接用 Python
python3 -c "
import msgpack
data = msgpack.packb({'hello': 'world', 'count': 42})
print(data.hex())
# 输出: 82a568656c6c6f a5776f726c64 a5636f756e74 2a
print(' '.join(f'{b:02x}' for b in data))
"

🔗 扩展阅读 / Further Reading

资源链接
官方网站https://msgpack.org/
规范文档https://github.com/msgpack/msgpack/blob/master/spec.md
各语言实现列表https://msgpack.org/#languages
GitHub 仓库https://github.com/msgpack/msgpack
Wikipediahttps://en.wikipedia.org/wiki/MessagePack

📝 下一章 / Next: 第 2 章 - 格式规范 / Format Specification — 深入了解 MessagePack 的二进制编码规则和类型系统。