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

序列化这块搞定了,数据终于能顺利往Redis里存储了,过程还挺顺的

(来源:程序员个人技术博客分享)

那天下午,当我看到测试用例的控制台终于不再抛出那些令人心烦的乱码和连接错误,而是清晰地打印出“数据写入Redis成功”的日志时,我长长地舒了一口气,几乎想从椅子上跳起来,心里一块悬了好几天的石头,总算“扑通”一声落了地,这事儿,算是暂时搞定了。

事情的起因很简单,我们有个新功能模块,需要把用户的一些实时操作数据临时、快速地存到Redis里,供其他服务查询,听起来挺 straightforward(直接)的,对吧?Redis嘛,内存数据库,以快著称,往里塞东西能有多难?我一开始也是这么想的,觉得这顶多就是调个API的事儿,一两个小时就能收工。

结果,现实结结实实地给我上了一课,我兴冲冲地写好了代码,把咱们Java程序里的一个对象,直接用最简单的序列化方式(来源:最初天真的实现方案)转换成字节流,然后信心满满地往Redis里存,一运行,坏了,Redis里存进去的东西,用命令行一看,全是一堆看不懂的二进制乱码,根本没法识别,这还不算,当另一个服务尝试来读取这个数据,并把它还原成对象时,程序直接崩溃了,抛出一堆反序列化失败的异常,错误日志红彤彤的一片,看得我心惊肉跳。

这下我才意识到,我太小看“序列化”这个小妖精了,它就像是一个翻译官,负责把咱们程序世界里活生生的、有结构有类型的对象,翻译成一种能够被存储或网络传输的通用语言(比如字节流),等需要的时候,再把这个通用语言精准地翻译回来,还原成原来的对象,这个翻译过程,必须保证信息不丢失、不走样。(来源:对序列化概念的通俗理解)

我的第一次失败,就败在了翻译官没选对,我用的那个默认序列化方式,可能只适合Java程序自己跟自己玩,它写出去的东西,别的语言、甚至同一个语言的不同环境都可能读不懂,兼容性很差,它好像把对象的所有家当,包括一些无关紧要的元信息,都一股脑儿塞进去了,导致存到Redis里的数据体积特别臃肿,Redis的内存多宝贵啊,哪能这么浪费?

我开始寻找更优秀的“翻译官”,我查了资料,也问了组里更有经验的同事(来源:寻求解决方案的过程),他们提到了好几种选择,比如JSON、XML,还有像Protobuf、MessagePack这种更高效的二进制协议,权衡了一下我们项目的需求——既要让人能看懂(方便调试),又要体积小、效率高——我最终决定先试试看JSON,毕竟,JSON是种纯文本格式,非常通用,几乎所有的编程语言都能轻松处理,而且结构清晰,我们在排查问题的时候,直接就能在Redis里看到存的是什么内容,这点非常友好。

方向定了,接下来就是动手改造,我引入了项目里已经在用的一个JSON处理库,重写了序列化和反序列化的工具方法,这个过程,说实话,比我想象的要顺利,原本以为会碰到很多坑,比如日期格式怎么处理啊,复杂的嵌套对象会不会有问题啊之类的,但可能是因为我们的数据结构暂时还比较简单,我按照库文档里的示例,一步步来,写好了把对象转换成JSON字符串的代码,以及把JSON字符串再转回对象的代码。

写完之后,怀着忐忑的心情,我再次运行了测试用例,眼睛紧紧盯着控制台,看着日志一行行滚动……没有报错!我迫不及待地打开Redis的桌面管理器,连接上测试数据库,找到了我存储的那个键,双击点开,心里默念着“千万别再是乱码”,果然,这次映入眼帘的不再是那些天书般的字符,而是一段规规矩矩、缩进整齐的JSON文本!每一个字段的名字,每一个属性的值,都清清楚楚地展现在那里,我甚至能直接看出哪个用户做了什么操作,数据是什么时候生成的,这种一目了然的感觉,真是太棒了!

为了确保万无一失,我又写了段代码,模拟另一个服务来读取这个数据,读取,反序列化,成功!程序没有崩溃,还原出来的对象,里面的字段值和之前存进去的一模一样,分毫不差。

那一刻,成就感油然而生,虽然这只是一个技术实现上的小节点,离整个功能上线还远,但这种通过自己的学习和尝试,把一个绊脚石搬开,让程序重新顺畅跑起来的感觉,是非常实在的快乐。(来源:问题解决后的个人感受)它让我对“序列化”这个以前只是停留在概念层面的词,有了更具体、更深刻的理解,我知道了不能想当然,知道了选择合适工具的重要性,也体验了一把从遇到问题、分析问题到最终解决问题的完整过程。

我也明白,现在用JSON可能只是第一步,万一以后数据量变得非常大,对性能要求极高,或许我们还会考虑换用更高效的二进制协议比如Protobuf,但那是后话了,至少眼下,数据能顺顺利利、明明白白地往Redis里存了,这关键的一步,总算是迈过去了,接下来的工作,又可以继续推进了。

序列化这块搞定了,数据终于能顺利往Redis里存储了,过程还挺顺的