`
Acmey
  • 浏览: 52193 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

大数据量处理及存储代码优化过程

阅读更多
1. 原始场景再现:

    该模块主要是客户端负责上传一个包含手机号码的txt,其中一行一个手机号码。服务端读取并解析该文件,解析过程中需要做有效性验证。例如:号码位数,是有效数字及是否在有效号段之内。最后保存数据到DB。

    该包含手机号码文件数据在20W到200W之间。

    2. 问题所在

    在客户端上传20W数据的时候,后台相应很慢,查看后台的CPU及内存

    mpstat -P ALL 1   //查看LINUX系统内存及CPU的消耗情况

    发现CPU一直处在100%状态下,而且消耗的时间很长。近十分钟也没有回复到客户端。

    3. 问题详解

    首先查看代码。列下原代码思路:

    1) 使用apache的公用包来处理文件的上传,保存客户端文件到服务器

    2) 打开读取文件IO,及写日志IO,读取文件信息,到一个LIST中。

    3) 双重遍历LIST,进行查重操作。重复数据记录到日志文件中

    4) 遍历LIST进行有效位数的校验。重复数据记录到日志文件中

    5) 遍历LIST进行是否为有效数字验证。重复数据记录到日志文件中

    6) 遍历该LIST,组装为数据库存储对象传递到DAO层,DAO层再次遍历对象容器,将插入对象添加到了批量提交的LIST中。最后将20W的数据一次性批量提交

    4. 问题解决思路

    第一次改动:仔细查看代码我们可以很清晰的看出,问题主要在两块:

    一是数据的有效性检查,原代码采用了多次循环遍历的方式处理,很耗CPU。故首先将多次遍历的处理应该缩减为一次遍历即可,但是仔细想想其中存在一个查重的处理操作,故我们将原本用list存储的方式改为SET存储的方式,因为set不会存储重复的数据,这样可以达到查重的效果。

    Key:HashSet底层使用hash数组实现的,其原理就是当保存一个对象的时候,首先调用该对象的hashCode方法,获得hash码与原数组及数组子链表中的数据进行比较,若是相同的话则不进行插入操作,再不存在的情况下,才进行存储。由于String 类型已经实现了hashCode方法,所以我们不需要实现该方法若是其他类型的对象我们则需要实现该方法。

    二就是数组存储的地方了,原代码采用了几十万条数据的一次批量提交,当然很消耗资源,代码回复给客户端慢。这里我采用了ORACLE写一个存储过程,JAVA端传递一个数组给ORACLE,有存储过程来处理大数据量,这样就将服务器的压力转移到ORACLE安装的的那台服务器。

    好的,第一次改动过完成。重启TOMCAT试下。结果当我们只上传20W数据的时候,发现还是很慢很慢,回头又仔细看代码,打断点。再调试的过程中,发现在我只采用一个遍历循环的时候,CPU就一直处理100%,原来在处理这20W数据的时候,CPU就一直处理很高的状态了,那该怎么办呢?这个时候就是第二次改动了

    第二次改动:

    个人经验,一般处理这种大数据量有两种方法,其实这两次方法的本质是一样的,就是为了降低CPU。

    第一种是在我们在遍历循环的时候,在循环遍历到一定数量的时候,进行Thread.sleep(5)操作,带该线程睡眠片刻

    Java代码 

For (int I =0 ;I < list.size();i++)  
{  
    //…业务处理  
    If (3000 == i)  
{  
        Thread.sleep(5)  
    }  

     强制CPU暂时不处理该线程
第二种方法就是采用流控的方式,流控的原理就是我们有一个初始量,循环过程中我们累加这个量,当达到一定量的时候,该线程进行wait()操作,同时我们启动一个定时器,定时间周期对该变量进行清零操作,并唤醒该线程。其中可能会出现两种情况,一是我们定时器的清零操作还没到,累积量就已经到了,那么该线程就会处在等待状态,等待清零时间到,唤醒线程。二是累积量还没到,清零时间就到了,对线程进行清零,那么这个时候线程会一直处在一个运行状态,如果这个时候CPU使用率很高的话,就达不到我们需要的效果,所以该方式的控制就需要实际调整定时器的扫描周期、记累积量的值设定。实际过程中需要调整两参数。

    因为我们是将流控写成了一个工具类,所以不好贴出来,具体也就是上面所所得思路。

    比较两种方法我们明显可以看出,采用流控的方式更佳,因为它是不阻塞线程,wait的方式。第一次则是sleep,阻塞线程。

    好,第二次改动已经完成了,我们就开工试试了。当你怀着美好的愿望时,老天总是不能让你如意。结果很失望,还是慢的一塌糊涂,然后不断的调整参数,结果还是没降下来。这个时候我就开始反思了,难道这种方式有问题,再去打断点调试的过程发现,采用了流控后,在处理数据的时候是CPU确实是降下来了,但是还是存在一个问题,再没处理完一条记录后,都会有一个日志的记录,这个时候用的是bufferRead,结果我们在最后的close()IO的时候,一次行将内存缓存中的数据库刷到文件,导致CPU及内存的过高。知道原因后我开始了第三次的改动。

  



第三次改动:

    这个时候,我采用了流控相同的思路,就是在处理完一定数据量的数据后,我们进行一次flush操作,将内存中数据刷到文件中,免得一次性刷,同时因为我们一般是整数的W级数据,所以定义一个常量为3000(全局多个地方需要刷数据,好改动),作为flush标示。因为采用3000的话,最后一次我们刷的只有1000的数据量,同时关闭IO需要开销,所以能够在一定程度上降低CPU,同时发现在第一次flush的时候CPU会较高,越后CPU会越低,不知道什么原因。

    Java代码

If (…)  
{  
        if (3000 == i)  
{  
        read.flush()l  
}  

      OK ,又可以开工进行测试了,我是费了九牛二虎之力开动了TOMCAT(机子太差),哈哈,终于成功了。CPU从原来的100%降到了10%左右,很有成就感,嘿嘿。这样就将给测试区测试了。但是,但是,测试告诉我一个很不幸的消息,CPU还是很高,这个是为什么呢?

    仔细看看了,原来TMD应用的服务器跟DB在一台服务器上,气死老夫了。采用一次性传递数据的片刻,ORACLE会使CPU会飙到100%,而且处理这么多数据的时候也会持续5s左右的时间一直处在该位。这个时候咋办呢?这个就需要第四次改动了。

    第四次改动:

    这个时候,首先改动的是存储过程,采用了动态变量绑定,同时调整commit;的次数,在1000,3000,5000,10000条记录的时候提交数据,结果调试后,没什么改观,没则,只好换个思路。

    启用存储过程,在java端想办法,最简单的方法还是启用原来的批量提交方式,修改为一定数量数据后提交,因为这个提交,并在提交后sleep,方式CPU一直处在这个状态。

    伪代码就是

    Java代码

If ()  
{  
    If (3000 == i)  
{  
        //提交数据到DB  
    //清零标示,清空临时list  
    Thread.sleep();  
}  

      就这么简单。提交调试后,发现java端不会消耗很高的CPU,在第一次提交批量数据时会到30%左右,第二三次会降到15%左右,同时ORACLE消耗的CPU在第一次会100%,但是持续时间很短,就1s的时间,在达到这样的效果后,领导说可以了。总算结束了这段优化过程。

    简单的说,我这种方式不过是用时间换CPU的性能,只使用与对于时间要求不是很高,更要求CPU的性能的场景。
分享到:
评论

相关推荐

    经验大数据量处理及存储代码优化过程.pdf

    。。。

    经验大数据量处理及存储代码优化过程.docx

    。。。

    经验大数据量处理及存储代码优化过程 (2).pdf

    。。。

    经验大数据量处理及存储代码优化过程 (2).docx

    。。。

    SQL Server 存储过程与实例

    而且数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性。 B、 存储过程能够实现较快的执行速度 如果某一操作包含大量的T-SQL语句代码,分别被多次执行,...

    大数据量分页存储过程效率测试附测试代码与结果

    测试环境 硬件:CPU 酷睿双核T5750 内存:2G 软件:Windows server 2003 + sql server 2005 OK,我们首先创建一数据库:data_Test,并在此数据库中创建一表:tb_TestTable 代码如下: create database data_Test –创建...

    asp.net数据存储与交换系统设计(源代码+thesis).zip

    这包括使用高效的算法和数据结构、使用缓存技术和数据库索引、进行代码优化和资源管理等。 通过采用这些技术方案,我们的项目将能够提供一个高性能、可扩展和可靠的Web应用程序。我们将遵循最佳的软件开发实践,进行...

    mysql数据优化详细教程

    在实际生产环境中,由于数据库本身的性能局限,就必须要对前台的应用进行一些优化,来降低数据库的访问压力。频繁的创建关闭连接,是比较...分布式数据库架构适合大数据量、负载高的情况,它有良好的拓展性和高可用性。

    SQL查询安全性及性能优化

    只能执行存储过程中固定的代码 限制输入长度 防止黑客输入超大字符串,导致服务器瘫痪 防止黑客输入较长的恶意脚本等 实现方法:文本框的MaxLength属性 URL重写技术 示例: http://testWeb/news.aspx?id=111 ...

    Java优化编程(第2版)

    Java优化编程(第2版)通过丰富、完整、富有代表性的实例,展示了如何提升Java应用性能,并且给出了优化前与优化后的Java应用程序的性能差别,以实际的实例与数字告诉你,为什么不可以这么做,应该怎么做,深入分析...

    sql 存储过程分页代码 支持亿万庞大数据量

    代码如下: CREATE PROCEDURE page @tblName varchar(255), — 表名 @strGetFields varchar(1000) = ‘*’, — 需要返回的列 @fldName varchar(255)=’id’, — 排序的字段名 @PageSize int = 10, — 页尺寸 @...

    MySQL是一款开源的关系型数据库管理系统,能够解决许多数据存储和管理方面的问题

    包含 MySQL 数据库的基础知识,涵盖了 MySQL 的安装和配置、SQL 基础语法、索引和查询优化、事务和锁等内容,并提供了大量的案例代码和实践练习,方便学习和掌握 MySQL 的使用方法。以下是MySQL可以解决的一些问题:...

    kd树数据结构实现k-means聚类算法加速

    主要的方法就是,将数据存储在kd树这种空间数据结构中,树的思想类似于二叉搜索树、红黑树等,真的很强大(相信童靴们明白的)。改进的k-means方法主要考虑了合理的初始候选质心的方式,并且利用kd树的特性,减少了...

    python数据分析随书代码

    python数据分析/(印尼)伊德里斯(Idris.I.)著,韩波译。 资源包括所有章节的示例代码。需要用到python2和pip。 编辑推荐 实用的Python开源模块的大集合; 简单易懂、示例丰富的数据分析教程; 掌握数据可视化...

    购物商城系统源代码--036

    数据结构更经过精心的设计,从字段到表的分配、索引的构建、都经过缜密的考虑、相同数据量的购物系统,时代商城购物系统占用的数据库容量和其他类似产品相比要小,程序内核中查询遵循 ANSI SQL 规范。 模板体系 ...

    基于SQL语言MySQL数据库应用程序及其代码方案

    3. 高性能:MySQL通过优化查询、索引和存储过程等技术手段,提供了较高的数据处理性能。 4. 可扩展性:MySQL支持大量的表和数据,可以通过增加硬件资源来提高数据库的处理能力。 5. 多平台支持:MySQL可以在多种操作...

    oracle的sql优化

     大数据量表尽量要避免全表扫描,全部扫描会按顺序每条记录扫描,对于&gt;100万数据表影响很大。  Oracle中通过RowID访问数据是最快的方式  对字段进行函数转换,或者前模糊查询都会导致无法应用索引而进行全表扫描 ...

    Java毕业设计-基于springboot开发的科研工作量管理系统设计与实现-毕业论文(附毕设源代码).rar

    后端则通过Spring Boot框架的强大功能,实现了数据的持久化存储、业务逻辑的处理以及安全性的保障。 在实现过程中,项目注重代码的可读性和可维护性,采用了规范的命名规则和注释方式,使得代码易于理解和维护。...

    JAVA上百实例源码以及开源项目源代码

    EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean...

    asp.net4+JQuery 构建信息门户网站 源代码及ppt分享

    在针对项目的特色上,作者还对数据库进行了分库分表设计,对大容量数据库(百万级)进行了一定的性能优化,并使用实例演示了如何跨服务器跨库进行表的查询和存储过程的调用。本课程的所有代码作者进行了全程录屏,再...

Global site tag (gtag.js) - Google Analytics