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会拒绝反序列化未知类型,这在插件系统中可能引发意外失败。
