今天踩了两个经典小坑,前后折腾了整整半天。
不编造、不跑偏,只讲真实排查过程和最终根因。
一、Redis 序列化乱码(\xac\xed 二进制)
问题现象
Redis 里存的值变成乱码,可视化工具看到一堆 \xac\xed 二进制,无法正常识别、业务读取异常。
真实排查过程
一开始只有 admin 服务在用这个 Redis,读写正常,没有任何问题。后续业务迭代,出现跨微服务调用场景,突然爆出数据乱码问题,完全读不到有效内容。
排查初期,我优先怀疑是可视化工具编码兼容问题,连续更换两个客户端查看,依旧乱码。接着排查 Redis 集群配置、连接参数,均未发现异常。
中途也看到过网上一些临时规避方案,但我并不认可。这类方案只能临时掩盖问题,无法根治,换一个服务、换一套读写逻辑依旧会崩。
真实根因
最终翻阅 Redisson 官方文档确认核心问题:Redisson 默认采用 Java 对象序列化,存储的是二进制字节流,并非纯字符串格式。
单一服务读写时,序列化、反序列化规则统一,所以不会出现乱码。一旦跨微服务调用,不同服务读写规则不统一,就会直接出现二进制乱码问题。
解决方案
统一全局编码规则,强制使用字符串序列化,所有微服务保持一致:
java
private static final Codec STRING_CODEC = StringCodec.INSTANCE;
public void setValue(String key, String value) {
RBucket<String> bucket = redissonClient.getBucket(getKey(key), STRING_CODEC);
bucket.set(value);
}
强制指定 StringCodec 后,Redis 全程以纯 UTF-8 字符串读写,跨服务乱码问题彻底根治,数据可视化正常、业务读取正常。
二、MySQL 配置迁移 → 字段全部为 null
问题现象
配置从 Nacos 迁移至 MySQL 后,ApiConfig 配置类可正常注入,对象不为空,但是内部 algoUrl、apiKey、apiSecret 所有业务字段全部为 null。无报错、无异常,日志无提示,隐蔽性极强,极难定位。
真实排查过程
本次改造是将原有 Nacos 动态配置,迁移落地到 MySQL 持久化存储,部分启动逻辑需要提前读取配置参数。
测试过程中发现所有配置字段为空,初期排查思路偏向复杂方向:怀疑类加载顺序问题、Spring 容器初始化时机问题,担心容器未完成初始化就提前读取配置。
反复调试代码、打印启动日志、对比新旧版本逻辑,来回排查近一小时,始终没有找到问题根源。
真实根因
逐字段比对配置数据与实体类,终于定位到核心原因:
Nacos 配置中心支持下划线命名自动映射驼峰实体字段,所以长期运行无异常。
但迁移至 MySQL 纯 JSON 存储后,Jackson 序列化不具备自动适配能力:
数据库 JSON 字段:algo_url、api_key、api_secret(下划线)
Java 实体字段:algoUrl、apiKey、apiSecret(驼峰)
命名格式不匹配,导致 Jackson 无法完成赋值,所有字段统一为 null。
解决方案
统一命名规范,将 MySQL 中 JSON 配置字段全部改为驼峰格式,与 Java 实体类完全对齐:
// 改造前(下划线,无法映射)
{"algo_url": "xxx", "api_key": "yyy", "api_secret": "zzz"}
// 改造后(驼峰,完美映射)
{"algoUrl": "xxx", "apiKey": "yyy", "apiSecret": "zzz"}
修改完成后,配置正常读取、字段成功赋值,彻底排除问题。与类加载顺序、Spring 注入时机、框架BUG均无关系。
三、核心问题一句话总结
Redis 乱码:Redisson 默认二进制序列化 + 跨微服务规则不统一 → 全局统一 StringCodec 解决。
配置字段为空:Nacos 自动映射特性掩盖命名问题,迁移 MySQL JSON 后暴露不兼容问题 → 统一驼峰命名解决。
四、写在最后
开发排查问题时,我们总习惯性先怀疑复杂的底层逻辑:类加载机制、容器初始化、框架底层 Bug。
但绝大多数线上、开发环境的诡异问题,最终的根因往往都是最简单、最基础的规范问题。
踏实对照代码、比对参数、梳理环境差异,远比盲目猜测高效。
本文是《技术底稿》系列第 43 篇,记录真实项目踩坑、排查、落地修复的完整全过程,为同类问题提供参考范本。