性能优化从30秒到0.6秒,百万级数据存储优化
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能优化从30秒到0.6秒,百万级数据存储优化相关的知识,希望对你有一定的参考价值。
“性能优化就像挤出海绵中的水,能挤出多少,主要取决于海绵中的水分有多少”
@图片:2022年9月拍摄于北京中关村 @摄影师:刘先生
01
—
背景介绍
有这样一种业务场景,业务计算完成之后,会产生上百万的数据,而这百万级的数据如何入库保存,成了让人头疼的问题。
数据库是mysql,由于数据库超时时间限制和单次提交的数据量的限制,百万级数据不可能一次性入库,于是采用分批提交的方式,尽管数据能够成功入库保存,但时间慢的有些让人难以接受。本地开发主机由于程序和数据库在同一台电脑,硬盘是固态硬盘,保存耗时30秒,服务器由于网络及硬盘速度的影响,百万数据保存耗时在2分钟左右。
下面分享一下在不改变硬件及现有基础技术框架的前提下,仅靠修改代码逻辑,如何将百万数据保存耗时降到0.6秒,速度提升50倍,内存减少50%。
02
—
处理逻辑
第一步:合并数据
这个问题的本质是:数据量大,而优化的首个出发点是,如何减少数据量。按照这个思路,将数据按照数据主体进行汇总合并,多条数据合并成一条,以JSON形式,存储在一个字段中,减少入库数据量,最终,数据条数降低了100倍,现在需要处理的就是万级数据的入库问题,问题难度一下子降低了。
如下图所示,进行数据合并之后,BenchmarkDotNet测试结果,平均耗时从27.6秒降到4.6秒。
第二步:压缩数据,减少数据大小
经过上一步数据合并之后,数据的数量减少了,但数据空间大小并没有改善,这百万数据占用空间在100M左右,这一步从减小数据空间的角度,采用GZip压缩JSON数据,减少网络传输,及数据磁盘写入压力。
从下图的测试结果看,执行效率略有提升,重要的是数据大小从100M减低到30M,减少70%空间占用。
第三步:自定义序列化
JSON格式是最常用的一种序列化格式,但是否是最好的,考虑到具体的业务场景,是否可以用一种更简单的序列化格式进行取代呢,在这一步中,便进行了一次尝试,由于数据都是key-value形式,而value都是值类型,自定义序列化也变得非常简单。
JSON序列化后的数据
自定义序列化的数据
采用自定义序列化比采用JSON序列化,数据空间减少17%,尽管处理速度并没有明显提升,但内存耗用降低了50%。如下图所示
第四步:优化反射性能
上一步自定义序列化的过程中使用到了反射,由于数据量大,反射的性能问题被放大,这一步采用委托优化反射性能。
相较于上一步,速度提升近1倍,但内存耗用也增加了1倍,如下图
第五步:多线程并行处理
经过以上几步,执行速度降到了2秒,但这个速度我依然不够满意,于是祭出性能优化的终极杀器:多线程处理。有关多线程编程可以参考我之前的文章。
至此:处理速度为0.59秒,性能提升近50倍(49.23倍)内存占用减少50%。
用一张MySql数据库仪表盘的截图,直观展示两段逻辑执行时的性能差异:
03
—
思路总结
1.减少数据数量:合并数据项
2.减小数据空间:GZip压缩
3.优化反射性能:创建属性访问委托,提升属性读写速度
4.多任务并行:信号量控制并发数量,加锁控制临界资源访问,留意多线程下异常处理,任务取消
04
—
再啰嗦几句
起初优化的目标是性能提升100倍,显然有点高了,最终提升了50倍,当然目前还有一定优化空间,比如:有些小伙伴可能已经看到了,计算结果数据大部分的是0,这些为0的数据,其实是不需要保存的,这样即可以进一步减小数据量。
另外考虑到数据增量,每次有几百万数据入库,一年产生的数据将近5亿,这样大的数据量,在MySql中处理压力是很明显的,因此,引入分布式数据库才是长久的解决办法。
相关阅读:
喜欢此内容的朋友可以点赞,转发,关注
以上是关于性能优化从30秒到0.6秒,百万级数据存储优化的主要内容,如果未能解决你的问题,请参考以下文章
百万级高并发MongoDB集群性能数十倍提升优化实践(上篇)
百万级高并发mongodb集群性能数十倍提升优化实践(上篇)
MongoDB征文 | OPPO百万级高并发MongoDB集群性能数十倍提升优化实践