java千万级别数据处理Word格式文档下载.docx
- 文档编号:19909714
- 上传时间:2023-01-12
- 格式:DOCX
- 页数:11
- 大小:25.65KB
java千万级别数据处理Word格式文档下载.docx
《java千万级别数据处理Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《java千万级别数据处理Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。
BNo>
004<
/BNo>
6.
FileQ>
5<
/FileQ>
7.
FNo>
0006<
/FNo>
8.
RecordNum>
1000000<
/RecordNum>
9.
!
--
上面是文件头
下面是百万个<
RecordList>
-->
10.
11.
Msisdn>
/Msisdn>
12.
State>
/State>
13.
StartDate>
20110303<
/StartDate>
14.
Date>
20110419<
/Date>
15.
Balance>
45000<
/Balance>
16.
/RecordList>
17.
...
可能百万个
块-->
18.
/File>
二、给大家说一下如何把大数据生成xml文件
1、小数据量的情况下
1W条数据
比较好用的方法是使用开源框架,比如XStream直接把javabean生成xml
优点:
api操作简单,方便维护
缺点:
数据量大的情况下太消耗内存
2、大数据量生成一个xml文件(本程序采用的方法)
自己做的一个可以使用极少的内存生成无限制大的xml文件框架由3部分生成xml文件
第一部分:
生成文件头
例如:
xxx.toXML(Objectobj,StringfileName)
第二部分:
通过每次向文件里面追加3000(可配置)条数据的形式生成文件块
xxx.appendXML(Objectobject);
//object可以是ArrayList或者一个单独的javaBean
第三部分:
生成xml文件尾巴
例如:
xxx.finishXML();
程序中的调用:
调用xxx.toXML(Objectobj,StringfileName)生成文件头之后,可以循环从数据库中读取数据生成ArrayList,通过xxx.appendXML(Objectobject)方法追加到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对jdbcOraclePreparedStatement的具体实现,因此断定是在数据库处理方面出现的问题导致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.try{
conn.setAutoCommit(false);
pst
=
conn.prepareStatement(insertSql);
pstDel
conn.prepareStatement(delSql);
pstUpdate
conn.prepareStatement(sql);
//totalSize
100W数据
/
3000一批次
for
(int
i
1;
totalSize;
i++)
{
client.appendXML(list);
}
//
错误的使用方法
client.finishXML();
pst.executeBatch();
pstDel.executeBatch();
19.
finally
20.
try
21.
if
(isError)
22.
conn.rollback();
23.
24.
else
25.
connmit();
26.
27.
28.
29.
正确的方法如下
try{
1.
list
从数据库中查询3000条数据
17....
18.inally
如果碰到和我一样的需要给大家一个提醒.
oracle在每次执行executeBatch();
进行批处理的时候,当前connection对应的rownum会根据操作的结果发生变化.
在执行pst.executeBatch();
之后,当前连接的rownum数就会发生变化.因此凡是通过rownum查询数据的程序都要小心这一点
java千万级别数据处理
(2)-千万级别FTP下载
∙Java开发经验
这个也是以前做过的一个程序,目的主要是去ftp主机(最多100左右)去取xx数据文件.
千万级别只是个概念,代表数据量等于千万或者大于千万的数据
本分享不牵扯分布式采集存储之类的.是在一台机器上处理数据,如果数据量很大很大的话,可以考虑分布式处理,如果以后我有这方面的经验,会与时分享的.
1、程序采用的ftp工具
2、千万级别ftp核心关键的部分--列目录到文件,只要是这块做好了,基本上性能就没有太大的问题了.
可以通过apache发送ftp命令"
NLST"
的方式列目录到文件中去
#ftp列目录执行的命令以环境变量的配置优先,不配置则使用默认的列目录方式NLST
1.#
DS_LIST_CMD
NLST
2.public
File
sendCommandAndListToFile(String
command,String
localPathName)
throws
IOException
return
client.createFile(command,
localPathName);
catch
(IOException
e)
log.error(e);
throw
new
IOException("
the
command
"
+command
+"
is
incorrect"
);
当然应该还有其他形式的,大家可以自己研究一下
十万级别以上的数据量的话千万不要使用下面这种方式,如果用的话====找死
FTPFile[]dirList=client.listFiles();
3、分批次从文件中读取要下载的文件名.
加载到内存中处理,或者读取一个文件名就下载一个文件,不要把所有的数据都加载到内存,如果很多的话会出问题
为啥要分批次?
因为是大数据量,如果有1000W条记录,列出来的目录文件的大小1G以上吧
4、文件下载的核心代码----关于文件的断点续传,获得ftp文件的大小和本地文件的大小进行判断,然后使用ftp提供的断点续传功能
下载文件一定要使用二进制的形式
client.enterLocalPassiveMode();
//设置为被动模式
ftpclient.binary();
//一定要使用二进制模式
1./**
下载所需的文件并支持断点续传,下载后删除FTP文件,以免重复
*
param
pathName
远程文件
localPath
本地文件
registerFileName
记录本文件名称目录
size
上传文件大小
true
下载与删除成功
Exception
*/
public
boolean
downLoad(String
pathName,
String
localPath)
flag
false;
file
File(localPath+"
.tmp"
//设置临时文件
FileOutputStream
out
null;
try{
设置为被动模式
client.setFileType(FTP.BINARY_FILE_TYPE);
//设置为二进制传输
if(lff.getIsFileExists(file)){//判断本地文件是否存在,如果存在并且长度小于FTP文件的长度时断点续传;
返之新增
long
this.getSize(pathName);
localFileSize
lff.getSize(file);
if(localFileSize
>
size){
FileOutputStream(file,true);
client.setRestartOffset(localFileSize);
client.retrieveFile(new
String(pathName.getBytes(),client.getControlEncoding()),out);
out.flush();
else{
FileOutputStream(file);
30.
31.
32.
33.
34.
35.
}catch(IOException
e){
36.
37.
log.error("
download
error
38.
e;
39.
}finally{
40.
41.
if(null!
=out)
42.
out.close();
43.
if(flag)
44.
lff.rename(file,
localPath);
45.
46.
47.
48.
49.
flag;
50.
51.
/**
52.
获取文件长度
53.
fileNamepath
本机文件
54.
55.
56.
57.
getSize(String
fileNamepath)
IOException{
58.
FTPFile
[]
ftp
client.listFiles(new
String(fileNamepath.getBytes(),c
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 千万 级别 数据处理