`

Json压缩方案 极限逼近——JSON四步香艳瘦身的故事

 
阅读更多

极限逼近1——JSON四步香艳瘦身的故事

CUC 黄进兵

概要:

中国联通总部有一个自助服务的项目,其中一个功能是要为联通用户在线上提供详单查询服务。由于详单存在多次重复查询的情况,如果每次都要通过接口去调用省分BSS系统的话,极度影响用户体验,特别是在用户能随意调整选择查询时间范围的时候,频繁调用接口也会让对端系统受不了。因此当时一个容易想到的方案,就是直接在用户查询详单时,把该用户最近一个月乃至三个月的详单,一把头地从BSS中拿过来,放在自助服务本身的HBASE数据库中缓存起来,然后通过这个系统内的缓存,为用户提供良好的详单查询体验。

在具体项目实现中,当时采用一种“偷懒”的方案,就是直接把详单JSON作为一个整体,存储到HBASE中,然后使用的时候,又一把头读出来,有点像银行的“整存整取”,实现起来相当方便。上线后产生的问题是,这种存储方案会导致每天详单的增量都在1T左右,对存储增长要求非常高。因此,当我了解到这个问题后,就给项目组提供了一个简单的优化方案,能在不改变“整存整取”方案的前提下,把详单存储容量降到原来的20%左右。本文就是向大家分享一下这一JSON瘦身的研究过程。

一、四步瘦身计划

首先就是样本分析,找我的同事蔡淑华要来了几段详单的样本,我要仔细端详一下,看看他们长的是什么样子。下图中,我截取了其中有代表性的一段,共1532个字节,如果把字节比喻成重量的斤的话,那么这段详单JSON就有1532斤,如果要“性感”比喻一下,那就是:对面的“女孩”看过来,原来是肥妞一枚。由于太肥了,感觉还是躺着舒服,坐着都费力,站起来就别想了。

怎么办,请将目光从右边的“肥妞”转移到左边的JSON数据上。眼睛不要离得太近,离远点,会发现这个JSON中,怎么满满的都是双引号啊。JSON中的KEY左边右边2个双引号,VALUE左右又两个双引号。当然标准JSON中,KEY是需要两个双引号包含起来的,VALUE如果是字符串类型的话,也是需要用两个双引号包含起来的。一个KEY-VALUE就需要4个双引号。如果先把JSON标准放一边,在VALUE全部都是常规字符串类型的情况下,把双引号消除(裸奔处理)的话,会不会影响JSON的语义呢?先下手为强,消除掉试试看。由于消除了所有的双引号之后,并没有破坏JSON的结构,因此并没有破坏JSON的语义,这么做就是无害的。此时,我们再上称称一下,发现比原始体重减掉了334斤。虽然第一步就减到了1198斤,但是还是胖啊,不过好歹站起来不费力了。

让我们再次在上图中将目光从右边移到左边,稍微拉近点距离,仔细端详一下,是不是还有比较明显的“肥肉”呢。很容易就发现,每一条详单的KEY名字都好长。Calldate通话日期、calllonghour通话小时、calltime通话时间、othernum对方号码……我们再看看VALUE,发现到处都是0.00,到处都是20130101,到处都是“国内通话”。根据处理重复的“三次原则”,如果重复达到3次,那么就可以将重复提炼出来,消除重复。这一步,我们依然不破坏JSON的结构,但是把KEY提炼出来,做一个映射,将长的名字映射成短的名字,把VALUE重复达到三次的,也提炼出来,给一个短名字的引用。经过这第2步的瘦身,多了两个字典的JSON,再加上瘦身过后的JSON,总共是846斤,欧耶,又成功甩掉352斤的肥肉,减到了846斤,如下图,这次不仅可以站起来,还可以运动起来了,这个美女大家都想要了吧。

经过上面的2步减肥,效果已经很不错了。目光自觉地再次移到左边的JSON上,名字都很短了,重复的VALUE也用@开头的名字来引用了。唯一的一点遗憾就是,每一条话单,都有一套一模一样的KEY。我们将KEY做成表头,将VALUE做成纯的数据行,将JSON对象转换成JSON数组,就又可以成功减掉118斤了。

经过3步减肥,效果已经很明显了,从原来的1532斤减到了728斤,减掉了将近一半。再从字面上去减的话,基本上到顶了。那么能不能通过压缩来进行压缩呢,很快实验一下GZIP压缩并且以BASE64编码来表示,发现又成功减肥了173斤。这次减肥,相当于把美女蜷缩起来装进了箱子。

样本成功瘦身了。我们再拿一个真实的大小184K的详单来进行实验,经过4步瘦身后,可以减到6K,效果杠杠的。

所有的这些“瘦身”都是无损的,也就是完全可以以相反的顺序来恢复成原始模样。我把前面的3JSON实验的代码,也已经分享到了GITHUB上( https://github.com/bingoohuang/westjson )。加入你看不惯打印到日志中那么多JSON中的双引号的话,就可以引用westjson,通过调用new WestJson().json(standardJSON, WestJson.UNQUOTED)就很方便地把双引号消除掉,再通过调用new WestJson().parse(unquotedJSON, WestJson.UNQUOTED)就可以恢复到标准JSON

二、总结思考

首先,我们应当不拘泥于标准的JSON格式,这样我们才能放手去做一些事情。标准只是参考而已,对外接口的时候需要保持,内部使用的时候可以适当调整。本文还是以文本格式为基准的瘦身过程,其实除了文本格式的JSON之外,也有二进制的BJSON(谷歌搜索Binary JSON即可),如果采用BJSON是否可以达到更高的瘦身效果,需要进一步去研究。

其次,消除重复的“赘肉”永远效果是最佳的。把相同的反复重复的数据进行规整,只存储一份原始数据,这样重复越多,瘦身效率越高。

最后,是GZIP压缩,应当也可以通过HBASE相关的压缩选项来完成,这样应用本身就可以忽略压缩这一步了。

       有人会有疑问,这点瘦身放在若干条详单上到底有没有必要。还是引用一位90岁老太太谈南海局势的话吧:“南海是中国的,要不观音菩萨住哪里,东海也是,要不龙王住哪,月球也是,要不嫦娥住哪。有什么好协商的,打仗就是打钱,国家14亿人口,每个人10块就是140亿,先打10块钱的,不够再打100块钱的,打他。“你若干条话单费那么大力省那么点存储,意义没那么明显,但是如果是上千万上亿的话单,省下来的那可不得了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics