缓存序列化选型是什么
缓存里存什么格式决定了三件事:占用内存、可读性、演进难度。JSON 通用可读但体积最大,MsgPack 更紧凑,Protobuf 体积最小最快但需要 schema 与生成代码;大 value 还可以选择先压缩再存,用 CPU 换内存与带宽。无论选哪种,都要给键值加版本前缀,并把「反序列化失败」当作缓存未命中处理,而不是抛错给用户。
基本信息
| 适用版本 | 与 Redis 版本无关,取决于客户端序列化库 |
|---|---|
| JSON | 通用、可读、调试友好,体积最大 |
| MsgPack | 二进制紧凑,需工具才能阅读 |
| Protobuf / Thrift | 体积最小、跨语言,需要 schema 与代码生成 |
| 压缩 | JSON + gzip/zstd 省内存,但消耗 CPU |
| 演进策略 | 键值加版本前缀(如 :v2),新增字段可空,删除字段先过渡 |
典型使用场景
- 多语言服务共享缓存:Protobuf 保证各语言解析一致
- 调试频繁的业务:JSON 便于直接查看内容
- 内存紧张的大缓存:紧凑格式或压缩能显著降低占用
- 结构演进:用版本化键名实现新旧格式并行过渡
- 大对象缓存:先压缩再存,评估 CPU 与网络收益
格式对比
| 格式 | 体积 | 可读性与兼容 |
|---|---|---|
| JSON | 大 | 可读性好,字段增减较宽容 |
| MsgPack | 中 | 需工具查看,字段增减同样宽容 |
| Protobuf | 小 | 需 schema,跨语言一致性最好 |
| JSON + gzip | 小(CPU 换) | 可读性好,解压有 CPU 开销 |
| Java 原生序列化 | 较大 | 跨语言与升级易碎,不建议在缓存中使用 |
版本前缀与容错实践
版本前缀与容错实践
# 键值带版本前缀,结构升级时并行存在 v2 与 v3
SET user:1001:v2 '{"name":"张三"}' EX 300
GET user:1001:v2
TTL user:1001:v2
# 结构升级时的双写过渡
SET user:1001:v3 '{"name":"张三","level":3}' EX 300
# 反序列化失败的处理原则:视为未命中,回源重建而不是报错大小与编码核对
大小与编码核对
# 对比不同序列化后的实际占用
MEMORY USAGE user:1001:v2
OBJECT ENCODING user:1001:v2 # 超过 44 字节即为 raw
# 大 value 加压缩后体积变化需实测,别凭感觉判断
STRLEN user:1001:v2跨语言服务用 Protobuf 或 Thrift 更稳,单语言且调试频繁用 JSON 更省事;关键是别在缓存里存不可演进的结构,并把格式与版本写进接口文档,避免不同服务各自解读同一份数据。
缓存中的序列化异常必须降级为「未命中」:把解析错误抛给用户会让一次格式变更直接变成线上故障,而正常做法是回源重建并记录日志统计比例。