




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
java千万级别数据生成文件思路和优化博客分类: java大数据处理javajava大数据java数据处理千万级别数据 一年前写过一个百万级别数据库数据生成配置xml文件的程序,程序目的是用来把数据库里面的数据生成xml文件.程序可以配置多少文件生成到一个文件中去. 程序刚开始设计的时候说的是最多百万级别数据,最多50W数据生成到一个xml文件里面去,所以在做测试的时候自己也只是造了100W的数据并没有做过多数据量的测试,然后问题就来了.由于程序使用的局点数据量巨大,需要生成xml文件的客户资料接近千万级别的程度,而现场对程序的配置大约是100W条数据生成一个xml文件里面去,程序在这样的大数据量下面偶尔会有崩溃. 最近几天现场催的比较紧,最近抽空把这个问题处理了一下,在解决问题的过程中我把解决的步骤和方法记录了下来,正好和大家共享一下现场提的问题概况: 数据量:生成xml,每个文件100W+ 条的数据 内存控制:最好不要超过512M 问题详情:在处理70W左右的时候内存溢出一、先来看一下程序要生成的xml文件的结构Xml代码1. 2. 13. 124. 035. 0046. 57. 00068. 10000009. !-上面是文件头下面是百万个-10. 11. 1035071950712. 113. 2011030314. 2011041915. 4500016. 17. .!-可能百万个块-18. 二、给大家说一下如何把大数据生成xml文件 1、小数据量的情况下 1W条数据 比较好用的方法是使用开源框架,比如XStream 直接把javabean 生成 xml 优点:api操作简单,方便维护 缺点:数据量大的情况下太消耗内存 2、大数据量生成一个xml文件(本程序采用的方法) 自己做的一个可以使用极少的内存生成无限制大的xml文件框架由3部分生成xml文件 第一部分:生成文件头 例如: xxx.toXML(Object obj, String fileName) 第二部分:通过每次向文件里面追加3000(可配置)条数据的形式生成文件块 例如:xxx.appendXML(Object object); /object 可以是ArrayList 或者一个单独的javaBean 第三部分:生成xml文件尾巴 例如:xxx.finishXML(); 程序中的调用:调用xxx.toXML(Object obj, String fileName) 生成文件头之后,可以循环从数据库中读取数据生成ArrayList,通过xxx.appendXML(Object object) 方法追加到xml文件里面,xxx.finishXML() 对文件进行收尾 对框架说明:我上面提供的例子有文件头 + 文件块 + 文件尾巴. 如果和你们的实际使用文件不太一致的话,可以参考上面提供的思路修改一下即可,主要的方法是把相同的文件块部分分离出来通过追加的形式写入xml文件. 有了思路之后,大家可以尝试着自己写一个类似的大数据处理框架(千万级别以上),如何有什么需要帮助的可以直接联系我,因为是公司的程序,不太敢放出来,怕. 三、我是如何测试性能和优化的 1、手动排除 根据文件崩溃时候的日志发现是在生成xml的框架里面报的错误,第一想到的是框架有些资源没有释放.于是把自己做的文件生成框架整体的排查了一遍,并且自己写个简单程序生成200万条数据,使用xml框架生成一个xml文件,整个生成过程中任务管理器(xp)查看程序对应的java进程使用的内存基本在20M左右,因此排除框架的问题.怀疑是数据库查询和调用框架的部门出现问题. 检测了一遍主程序的关键部分代码,优化了一下字符串处理.手动的释放一些对象的内存(例如:调用ArrayList.clear(),或者把对象置空等),分配512内存后运行程序,60万数据的时候内存溢出,因为能主动释放的对象都已经释放掉了,还是没有解决,果断放弃看代码,准备使用JProfile进行内存检测. 2、手动排除没有解决,借助内存分析工具JProfile进行排除 通过在数据库中生成300W条数据,在JProfile上面多跑程序,一边运行,一边调用JProfile 提供的执行GC按钮主动运行垃圾回收,运行50W数据后,通过检测中发现 java.long.String 和 oracle.jdbc.driver.Binder 两个对象的数目一直保持在自增状态,而且数目基本上差不多,对象数目 都在200W以上,由于java.long.String对象是需要依赖对象而存在的,因此断定问题就出在oracle.jdbc.driver.Binder上面,由于改对象存在引用导致String不能正常回收. 3、通过在JProfile对象查看对象的管理 检测到oracle.jdbc.driver.Binder 被 oracle.jdbc.driver.T4CPreparedStatement 引起,而T4CPreparedStatement正好是Oracle对jdbc OraclePreparedStatement的具体实现,因此断定是在数据库处理方面出现的问题导致oracle.jdbc.driver.Binder对象不能正常释放,通过再一次有目的的检测代码,排查jdbc数据查询的问题,把问题的矛头直至数据库的批处理和事务处理.因此程序是每生成一个文件成功后,会把已经处理的数据转移到对应的历史表中进行备份,而再个表操作的过程中使用了批处理和事务,使用批处理主要是保证执行速度,使用事务主要是保证同时成功和失败。 4、又因此程序每次从数据库中查询3000条数据处理,所以准备监控oracle.jdbc.driver.Binder的对象数目是否和查询次数对应.,通过在程序中Sysout输出查询次数 + JProfile运行GC测试 Binder,数据匹配,证实是java在数据库批处理的过程中有些问题. 5、专门把批处理代码提取出来通过JProfile内存分析.最终问题定位完毕. 原因如下:100W数据生成一个文件的过程中,等文件生成完毕之后才能把数据库中的数据备份到历史表中,这个时候才能进行事务的提交,也就是执行commit(), 并且删除原表数据,100W数据按照3000一批写入文件,每批次只是通过 PreparedStatement.addBatch();加入到批次里面去,并没有执行PreparedStatement.executeBatch(),而是在commit()之前统一调用的PreparedStatement.executeBatch(),这样的话PreparedStatement就会缓存100W条数据信息,造成了内存溢出.错误的方法如下:Java代码1. try2. conn.setAutoCommit(false);3. pst=conn.prepareStatement(insertSql);4. pstDel=conn.prepareStatement(delSql);5. pstUpdate=conn.prepareStatement(sql);6. .7. /totalSize=100W数据/3000一批次8. for(inti=1;i=totalSize;i+)9. 10. client.appendXML(list);11. 12. 13. /错误的使用方法14. client.finishXML();15. pst.executeBatch();16. pstDel.executeBatch();17. 18. .19. finally20. try21. if(isError)22. conn.rollback();23. 24. else25. mit();26. .27. 28. .29. 正确的方法如下 tryJava代码1. conn.setAutoCommit(false);2. pst=conn.prepareStatement(insertSql);3. pstDel=conn.prepareStatement(delSql);4. pstUpdate=conn.prepareStatement(sql);5. .6. /totalSize=100W数据/3000一批次7. for(inti=1;isize)21. returnfalse;22. 23. out=newFileOutputStream(file,true);24. client.setRestartOffset(localFileSize);25. flag=client.retrieveFile(newString(pathName.getBytes(),client.getControlEncoding(),out);26. 27. out.flush();28. else29. out=newFileOutputStream(file);30. flag=client.retrieveFile(newString(pathName.getBytes(),client.getControlEncoding(),out);31. 32. out.flush();33. 34. 35. catch(IOExceptione)36. log.error(e);37. log.error(filedownloaderror!);38. throwe;39. finally40. try41. if(null!=out)42. out.close();43. if(flag)44. lff.rename(file,localPath);45. catch(IOExceptione)46. throwe;47. 48. 49. returnflag;50. 51. /*52. *获取文件长度53. *paramfileNamepath本机文件54. *return55. *throwsIOException56. */57. publiclonggetSize(StringfileNamepath)throwsIOException58. FTPFileftp=client.listFiles(newString(fileNamepath.getBytes(),client.getControlEncoding();59. returnftp.length=0?0:ftp0.getSize();60. 61. 62. 检测本地文件是否已经下载,如果下载文件的大小.63. 64. /*65. *本地文件的获取文件的大小66. *paramfile67. *return68. */69. publiclonggetSize(Filefile)70. longsize=0;71. if(getIsFileExists(file)72. size=file.length();73. 74. returnsize;75. 5、因为程序要跑最多100多个线程,在线程监控上做了一些处理,可以检测那些死掉的线程,并及时的拉起来。 t.setUncaughtExceptionHandler(new ThreadException(exList);原理:给每个线程添加 UncaughtExceptionHandler,死掉的时候把线程对应的信息加入到一个list里面,然后让主线程每隔一段时间扫描一下list,如果有数据,直接重新建一个线程运行即可6、如果程序是常驻内存的话,别忘记了在finally中关闭掉 不用的ftp连接7、做大数据库采集程序必须考虑到的一件事情 磁盘空间已满的处理 java虚拟机对于磁盘空间已满,在英文环境下的 linux aix 机器上 一般报 There is not enough space in the file system 中文环境下 一般报 磁盘空间已满 大家可以使用下面的代码进行验证 Java代码1. /检测磁盘控件是否已满的异常Java代码1. /
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- AI赋能高校思政教育的策略及实施路径
- 散文的鉴赏技巧:初中语文高级教学
- 写人绘形画影的绘画作文(12篇)
- 上海建平中学高一(下)期末语文试题及答案
- 我心中的老师抒情作文5篇
- 描写月全食作文八年级(8篇)
- 廉颇蔺相如列传故事解析:初中语文教案
- 案件执行协议书
- 详细工作经历及岗位证明文书(6篇)
- 公交公司学雷锋活动方案
- 人工智能导论习题答案
- 企业招标投标法律实务讲座课件
- dzz4四、六要素自动气象站用户手册
- 网络舆情概论(微课版)全书电子讲义完整版课件
- GB/T 31.1-2013六角头螺杆带孔螺栓
- GB/T 2900.50-2008电工术语发电、输电及配电通用术语
- GB/T 2518-2008连续热镀锌钢板及钢带
- GB/T 20145-2006灯和灯系统的光生物安全性
- GB 14784-2013带式输送机安全规范
- 常用公文的写作方法和要求课件
- 学前儿童发展评价课件
评论
0/150
提交评论