messagepack 因二进制序列化、无文本解析开销、体积小且解析快,比 json 更适合高性能场景;在微服务、rpc、redis 缓存及 iot 中性能提升 2–5 倍、体积减少 30%–60%,但不可读、需注意 schema 兼容性与序列化选项配置。

MessagePack 为什么比 JSON 更适合高性能场景
MessagePack 是二进制序列化协议,体积小、解析快,天然比 JSON 文本序列化节省带宽和 CPU。它不依赖字符串解析,跳过 UTF-8 编码/解码、括号匹配、引号转义等开销。在微服务通信、高频 RPC、本地缓存(如 Redis)或 IoT 设备数据传输中,MessagePackSerializer.Serialize 通常比 JsonSerializer.Serialize 快 2–5 倍,序列化后体积减少 30%–60%。
但要注意:MessagePack 不可读、不可调试,不能直接用浏览器查看;跨语言兼容性虽好,但需双方使用相同 schema 或启用兼容模式(如 MessagePackSerializerOptions.Default.WithCompatibilityResolver())。
安装与基础序列化/反序列化(.NET 6+)
通过 NuGet 安装 MessagePack 包(注意不是 MessagePack.CSharp,后者是旧版):
dotnet add package MessagePack
基础用法极简:
- 默认支持
public字段和属性,无需[Serializable]或[MessagePackObject](但加了能控制字段顺序和忽略) - 使用
MessagePackSerializer.Serialize<t>(value)</t>和MessagePackSerializer.Deserialize<t>(bytes)</t> - 推荐显式传入
MessagePackSerializerOptions.Standard,避免隐式使用全局静态选项带来的线程安全风险
示例:
var data = new { Id = 123, Name = "Alice" };
var bytes = MessagePackSerializer.Serialize(data, MessagePackSerializerOptions.Standard);
var obj = MessagePackSerializer.Deserialize<dynamic>(bytes, MessagePackSerializerOptions.Standard);
处理类成员、继承与自定义契约
默认行为对简单 POCO 友好,但遇到私有字段、只读属性、基类或需要版本兼容时,必须显式标注:
- 用
[MessagePackObject]标记类,用[Key(n)]指定字段序号(序号不可变,否则反序列化失败) - 私有字段需加
[Ignore]显式排除,或用[SerializationConstructor]控制构造逻辑 - 继承结构需在基类加
[MessagePackObject] [Union(0, typeof(SubType1))] [Union(1, typeof(SubType2))],否则子类信息会丢失 - 枚举默认序列化为整数,如需字符串形式,加
[EnumMember(Value = "value")]并启用EnumAsString = true选项
常见坑:[Key] 序号一旦发布就不能改;若新增字段,必须设默认值或标记为 [Ignore],否则老客户端反序列化新数据会抛 MessagePackSerializationException。
与 System.Text.Json 共存及性能调优
项目中常同时存在 JSON API 和 MessagePack 内部通信,二者可共存,但要注意:
- 不要混用
MessagePackSerializerOptions和JsonSerializerOptions—— 它们互不兼容 - 启用
MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4Block)可进一步压缩体积(尤其含重复字符串时),但增加 CPU 开销 - 对高频小对象(如
Point { x, y }),禁用自动装箱:用Span<byte></byte>重载接口(Serialize<t>(Span<byte> buffer, T value)</byte></t>)避免 GC 分配 - 避免在循环内反复创建
MessagePackSerializerOptions实例,应复用或使用静态只读字段
真正影响落地的细节往往藏在序列化选项里:比如未启用 AllowPrivateField = true 就无法序列化私有字段,而默认是 false;又比如 Security.SecurityMode = SecurityMode.Strict 会拒绝反序列化未知类型,这在插件系统中可能引发意外失败。






