![](http://image109.360doc.cn/DownloadImg/2023/02/2811/261645907_1_20230228111352303.jpeg)
01
—
背景介绍
有这样一种业务场景,业务计算完成之后,会产生上百万的数据,而这百万级的数据如何入库保存,成了让人头疼的问题。
数据库是MySql,由于数据库超时时间限制和单次提交的数据量的限制,百万级数据不可能一次性入库,于是采用分批提交的方式,尽管数据能够成功入库保存,但时间慢的有些让人难以接受。本地开发主机由于程序和数据库在同一台电脑,硬盘是固态硬盘,保存耗时30秒,服务器由于网络及硬盘速度的影响,百万数据保存耗时在2分钟左右。
下面分享一下在不改变硬件及现有基础技术框架的前提下,仅靠修改代码逻辑,如何将百万数据保存耗时降到0.6秒,速度提升50倍,内存减少50%。
02
—
处理逻辑
第一步:合并数据
这个问题的本质是:数据量大,而优化的首个出发点是,如何减少数据量。按照这个思路,将数据按照数据主体进行汇总合并,多条数据合并成一条,以JSON形式,存储在一个字段中,减少入库数据量,最终,数据条数降低了100倍,现在需要处理的就是万级数据的入库问题,问题难度一下子降低了。
第二步:压缩数据,减少数据大小
经过上一步数据合并之后,数据的数量减少了,但数据空间大小并没有改善,这百万数据占用空间在100M左右,这一步从减小数据空间的角度,采用GZip压缩JSON数据,减少网络传输,及数据磁盘写入压力。
JSON格式是最常用的一种序列化格式,但是否是最好的,考虑到具体的业务场景,是否可以用一种更简单的序列化格式进行取代呢,在这一步中,便进行了一次尝试,由于数据都是key-value形式,而value都是值类型,自定义序列化也变得非常简单。
![](http://pubimage.360doc.com/wz/default.gif)
第四步:优化反射性能
上一步自定义序列化的过程中使用到了反射,由于数据量大,反射的性能问题被放大,这一步采用委托优化反射性能。
第五步:多线程并行处理
经过以上几步,执行速度降到了2秒,但这个速度我依然不够满意,于是祭出性能优化的终极杀器:多线程处理。有关多线程编程可以参考我之前的文章。
至此:处理速度为0.59秒,性能提升近50倍(49.23倍)内存占用减少50%。
用一张MySql数据库仪表盘的截图,直观展示两段逻辑执行时的性能差异:
03
—
1.减少数据数量:合并数据项
2.减小数据空间:GZip压缩
3.优化反射性能:创建属性访问委托,提升属性读写速度
4.多任务并行:信号量控制并发数量,加锁控制临界资源访问,留意多线程下异常处理,任务取消
04
—
再啰嗦几句
起初优化的目标是性能提升100倍,显然有点高了,最终提升了50倍,当然目前还有一定优化空间,比如:有些小伙伴可能已经看到了,计算结果数据大部分的是0,这些为0的数据,其实是不需要保存的,这样即可以进一步减小数据量。
另外考虑到数据增量,每次有几百万数据入库,一年产生的数据将近5亿,这样大的数据量,在MySql中处理压力是很明显的,因此,引入分布式数据库才是长久的解决办法。