性能优化从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中处理压力是很明显的,因此,引入分布式数据库才是长久的解决办法。

相关阅读:

C#反射-性性能优化-不止于优化

C#多线程编程-必知必会

喜欢此内容的朋友可以点赞,转发,关注

以上是关于性能优化从30秒到0.6秒,百万级数据存储优化的主要内容,如果未能解决你的问题,请参考以下文章

百万级高并发MongoDB集群性能数十倍提升优化实践(上篇)

百万级高并发mongodb集群性能数十倍提升优化实践(上篇)

百万级高并发MongoDB集群性能数十倍提升优化实践(上)

MongoDB征文 | OPPO百万级高并发MongoDB集群性能数十倍提升优化实践

OPPO百万级高并发MongoDB集群性能数十倍提升优化实践(下)

MySQL百万级数据表or查询优化