当前位置:首页 > 问答 > 正文

Redis调试时突然出现乱码,搞不懂到底哪里出问题了怎么办

那天下午,我正对着电脑屏幕发呆,Redis客户端里原本应该整齐显示的用户名、订单号,突然变成了一堆像“��������”或者“是我在做啊”这样的天书,我第一反应是揉了揉眼睛,以为是自己盯屏幕太久眼花了,重启了Redis服务,甚至重启了电脑,但那些乱码就像幽灵一样,阴魂不散,我当时就懵了,心里直嘀咕:“这到底是哪里出问题了?之前明明都是好好的!”

最开始,我怀疑是Redis本身的数据出了问题,是不是有什么错误的写入操作,把一堆二进制垃圾数据塞进去了?(来源:基于Redis数据持久化机制的普遍认知)但仔细一想,最近没有进行什么特殊的批量数据更新,都是常规的业务操作,用KEYS *命令粗略看了一下,发现并不是所有键值对都乱码,只有部分字符串类型的值显示不正常,这让我排除了Redis服务整体崩溃的可能性,问题应该更具体。

我把矛头指向了Redis的客户端工具,我平时用的是那种带图形界面的客户端,看起来挺方便,会不会是客户端在显示的时候“抽风”了?(来源:常见软件本地化或编码支持问题的经验)我换了一个最朴素的命令行客户端,就是系统自带的redis-cli,重新连接上去查看同样的数据,结果令人沮丧:在命令行里,那些乱码依然存在!这说明问题不是出在图形化客户端的渲染上,而是数据在存储或者传输的某个环节就已经“变质”了。

这下问题有点严肃了,数据本身可能真的坏了,我静下心来,开始回想乱码出现前后到底发生了什么,我突然记起来,大概在乱码出现前,我为了处理一些中文内容,在某个临时的脚本里,偷偷修改了客户端的字符编码设置,我当时想当然地以为,只要把编码改成UTF-8就能万事大吉。(来源:对字符编码设置错误导致乱码的常见排查经验)难道是因为这个?

Redis调试时突然出现乱码,搞不懂到底哪里出问题了怎么办

我立刻检查了当前redis-cli的编码设置,果然,不知道什么时候被设置成了其他编码,我赶紧用命令把它改回了UTF-8,满怀期待地再次查询数据——可惜,乱码依旧,我的心又沉了下去,既然不是当前查看时的编码问题,那极有可能是在写入数据的那一刻,编码就已经不对了。

思路到这里就清晰了,问题根源很可能出在向Redis写入数据的应用程序身上。(来源:Redis官方文档及社区常见问题中关于客户端编码一致性的强调)Redis数据库本身就像一个单纯的仓库,它不管你存进去的是中文、英文还是二进制代码,它都照单全收,它自己内部有自己处理字节的方式,乱码的产生,往往是因为“写”和“读”两方没有用好同一个“密码本”(也就是字符编码)。

Redis调试时突然出现乱码,搞不懂到底哪里出问题了怎么办

我的应用程序在写入数据时,可能用的是GBK编码把中文转换成字节流,然后存进了Redis,而后来,当我的Redis客户端(或者另一个应用程序)试图用UTF-8编码去解读这些字节时,由于编解码规则对不上,自然就解出了一堆毫无意义的乱码,这就好比一个人用英语写了一封信(GBK编码),你却拿着法语字典(UTF-8编码)去读,读出来的内容肯定是莫名其妙的。

为了验证这个想法,我找到了最近有数据更新功能的那个应用代码,果然,在连接Redis和处理字符串的那部分代码里,我发现了一些蛛丝马迹,这个应用比较老,它默认使用的字符编码并不是UTF-8,而可能是操作系统默认的编码,而在另一个新开发的服务里,我们统一强制使用了UTF-8,当两个服务操作同一个Redis键时,乱码就不可避免地产生了。

找到原因后,解决办法就相对明确了,治标的办法是,统一所有接入Redis的应用程序,强制它们都使用UTF-8编码来序列化和反序列化字符串数据,这是最根本的解决之道。(来源:软件开发中关于数据交换编码标准化的最佳实践)而对于已经产生乱码的历史数据,处理起来就比较麻烦,如果数据不重要,可以直接删除,如果数据重要,就需要弄清楚当初写入时具体用的是哪种编码,然后写一个脚本,用正确的编码方式读出来,再用UTF-8编码重新写回去,相当于做一次“数据迁移”。

这次调试经历让我深刻体会到,在处理文本数据,尤其是多语言环境下的文本时,字符编码是一个绝对不能忽视的“小细节”,它平时默默无闻,一旦出了问题,排查起来却往往让人一头雾水,以后在任何一个涉及数据流转的环节,无论是数据库、文件还是网络传输,我都会牢牢记住:先确认好大家的“密码本”是不是同一本。