前言
前不久针对公司线上项目的一个模块进行了第二次重构与数据迁移,因数据量过大,在运行期间产生了10至20GB的数据,严重影响了该模块功能的正常使用,所以本次重构略有感触,特此分享一下这次大数据量的处理方案,希望对大家将来的开发过程中能带来些许帮助.
背景介绍
该模块功能处理流程如下:
我方公司暴露webservice服务供外部公司系统调用,外部系统讲数据电文发送致我方服务器,拿到电文之后进行转译为我们内部的数据,然后在需要打印时,我方打印服务直接读取数据通过Ireport转为PDF文件直接打印.
版本演变 1.最初版本
在最初的设计时并未考虑到将来可能会对接多家外部公司,并且数据结构完全不同,所以第一版开发时可以看做是专门为当时A公司量身定做开发的,一切以简单快速为基准.
其主要实现思路:
(1).约定好电文格式,并根据电文内容新建对应entity和table
(2).针对收到的电文直接将电文字符串转为对应entity然后分别存储在不同表中
(3).打印服务直接读取表中数据将数据输出为PDF文档
在其对接开发过程中,A公司的电文数据为主从结构,共4条电文
故我方系统新建了4张表 分别为 表A_MAIN、A_DETAIL、B_MAIN、B_DETAIL
经过跟踪发现整个17年大约收到并处理了接近七八十万条电文,所以平均一张表的数据量也就是二十万左右,整个功能模块使用没有任何问题.
2.第二版本
在18年初接到上级要求,该功能模块功能要求对接另一家公司B公司,
B公司通过同样的方式将数据传送到我方服务器,然后由我方向下游其它客户提供打印服务.
在最初的版本里并未考虑到未来可能会对接多家公司,所以针对电文数据都是采用定制化开发,即 :
一种电文格式对应一种数据表结构
在对接B公司时反思,难道以后每对接一家公司就要专门为其建立一套数据表,然后分别存储分别打印吗?这种开发模式虽然能以最快的速度完成开发,但过程过于繁琐,并且不利于打印服务的调用,以及web页面端的查询
故在此进行了第一次重构,也是这次重构为后面衍生出亿万条数据埋下了伏笔.
在本次重构中着重解决的问题就是如何将不同数据源的电文数据保存在一份表中,
最后经过讨论协商决定,采用列转行的模式,即:
通过配置表转译,将收到的电文每一个字段都作为一行记录进行存储
示例:
假设有两条电文内容分别如下:
电文1:{
name:'张三',
sex:'男',
phone:'138888888'
},
电文2:{
name:'李四',
sex:'女',
phone:'139999999'
}
通过配置表配置映射关系,最终存储下来的数据为:
数据ID展示名称字段名称字段值
姓名
name
张三
性别
sex
男
电话
phone
138888888
姓名
name
李四
性别
sex
女
电话
phone
139999999
如上图所示,一条电文有3个字段所以生成了3条电文数据,通过建立配置中心,将数据都存储在一个表里,那么无论将来 再有C公司来D公司来,只要提前约定好电文格式,拿到电文结构每个字段对应的含义,直接在配置中心进行电文配置,无需修改任何程序就可以完成新的厂家对接.
这种模式虽然能够尽可能的保证了该功能的灵活和兼容性,但其最大的问题的就在于对一条电文进行了多条数据拆分,如果一条电文里需要用到的字段越多那么其生成的对应数据就会多,空间复杂度会随着字段数的增多成指数型增长,
当初根据17年全年收到的电文进行判断,错误的预估了B公司推送的电文一年不会超过一百万,并且因为A公司发送的电文对应字段大概也就二三十个,所以认为B公司的电文字段不会超过30个
有些事你是真的想不到!
该模块重构上线仅仅1-2个月之后,B公司内部整改,数据结构进行了调整,并要求我们针对推送电文全文接收,
此时B公司一条电文大约有220个左右的字段,一条电文大约6-8KB
所以针对B公司的电文,一条数据就会对应的生成220条我方数据库数据,
然后数据量也不是A公司可以相比的,仅仅半年的时间就大约推送了200万条数据,其数据量达到了10多个GB,导致打印服务每次调用都是在调用一个几千万级数据量的表,随着时间的推移,打印服务每打印一次就需要几分钟乃至十分钟,严重的影响了公司正常业务的开展,再次重构已经迫在眉睫.
截止重构完成时,原有历史表数据已经达到了2亿级.
这就是最后该表的数据量.
3.第三版本
在进行第二次重构时,不光要对数据的存储方式进行变更优化,同时还要对历史数据进行割接,原有的数据不能丢弃,必须全部转换,面对如何快速的完成10-20个G的数据处理,我将在:
记一次大数据量处理案例(运用多线程完成数据快速处理)-----下(事件处理).