Protobuf序列化需显式注册消息类、key必须用StringRedisSerializer、value才适用Protobuf,且须注意线程安全与Schema管理。

直接换 Protobuf 或 Kryo 能显著缓解序列化性能瓶颈,但不能“一换就灵”——关键在类型注册、线程安全和 RedisTemplate 配置粒度。盲目替换反而可能引发反序列化失败或内存泄漏。
Protobuf 序列化器必须显式注册消息类
Protobuf 不像 JSON 那样能靠反射自动识别类型,ProtobufCodec 或自定义 RedisSerializer 必须提前告知它要处理哪些 .proto 生成的 Java 类。没注册就存取,运行时抛 IllegalArgumentException: No message class registered for type。
- Spring Data Redis 场景:需实现
RedisSerializer<t></t>,构造时传入具体Message子类(如UserProto.User.class),不能只传Object.class - Redisson 场景:用
new ProtobufCodec(UserProto.User.class)初始化,多个类型需组合封装(如用CompositeCodec) - 注意
build()后的对象才是可序列化的实例;未调用build()的 Builder 直接塞进 Redis 会报ClassCastException
Kryo5Codec 在多线程下需避免共享实例
Kryo 实例不是线程安全的,Spring 默认单例 Bean 会把同一个 Kryo 实例复用到所有请求线程中,高并发下出现 KryoException: Buffer overflow 或字段错乱。
- Redisson 中推荐使用
Kryo5Codec(已内部做线程局部封装),不要自己 newKryo注册到Config - 若自研 Kryo 序列化器,必须用
ThreadLocal<kryo></kryo>包裹,或每次序列化都新建(代价高,不推荐) - 务必注册所有用到的集合类(
ArrayList、HashMap)、日期类(LocalDateTime),否则反序列化时抛Unable to find class
RedisTemplate 的 key 和 value 序列化器不能混用
常见错误是给 key 也配成 ProtobufSerializer,结果 redis-cli 连不上、KEYS user:* 查不到——因为 key 变成了二进制垃圾,Redis 命令行工具无法识别。
-
key必须用StringRedisSerializer(UTF-8 编码),这是硬性约定 -
hashKey(如HSET的 field)同理,也得是字符串,不能 protobuf -
value和hashValue才是性能瓶颈所在,才值得上 Protobuf/Kryo - 别忽略
setHashKeySerializer和setHashValueSerializer,漏配会导致 HGETALL 返回 null
Protobuf 比 Kryo 更适合跨服务场景,但代价是 Schema 管理
如果你的缓存数据会被 Go/Python 服务读取,或者未来要迁移到其他语言栈,Protobuf 是更稳的选择;Kryo 纯 Java 生态,升级 JDK 或 Kryo 版本时容易因序列化格式微变导致旧缓存失效。
- Protobuf 要求所有变更通过
.proto文件定义,新增字段必须设optional或保留编号,否则老客户端解析失败 - Kryo 允许类字段增删,但需手动维护
Registration表,且不保证向后兼容 - Protobuf 编译后的类体积小、解析快,实测比 Kryo 小 15%~20%,但编译流程增加 CI 步骤(需集成
protobuf-maven-plugin)
真正卡住性能的往往不是序列化协议本身,而是没关掉 Jackson 的 enableDefaultTyping、没配对 hash 的序列化器、或让 Kryo 去序列化未注册的 Lambda 表达式——这些细节比选 Protobuf 还重要。


















