java千萬(wàn)級(jí)別數(shù)據(jù)處理_第1頁(yè)
java千萬(wàn)級(jí)別數(shù)據(jù)處理_第2頁(yè)
java千萬(wàn)級(jí)別數(shù)據(jù)處理_第3頁(yè)
java千萬(wàn)級(jí)別數(shù)據(jù)處理_第4頁(yè)
java千萬(wàn)級(jí)別數(shù)據(jù)處理_第5頁(yè)
已閱讀5頁(yè),還剩6頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

java千萬(wàn)級(jí)別數(shù)據(jù)生成文件思路和優(yōu)化博客分類(lèi):

java大數(shù)據(jù)處理javajava大數(shù)據(jù)java數(shù)據(jù)處理千萬(wàn)級(jí)別數(shù)據(jù)

一年前寫(xiě)過(guò)一個(gè)百萬(wàn)級(jí)別數(shù)據(jù)庫(kù)數(shù)據(jù)生成配置xml文件的程序,程序目的是用來(lái)把數(shù)據(jù)庫(kù)里面的數(shù)據(jù)生成xml文件.程序可以配置多少文件生成到一個(gè)文件中去.

程序剛開(kāi)始設(shè)計(jì)的時(shí)候說(shuō)的是最多百萬(wàn)級(jí)別數(shù)據(jù),最多50W數(shù)據(jù)生成到一個(gè)xml文件里面去,所以在做測(cè)試的時(shí)候自己也只是造了100W的數(shù)據(jù)并沒(méi)有做過(guò)多數(shù)據(jù)量的測(cè)試,然后問(wèn)題就來(lái)了....由于程序使用的局點(diǎn)數(shù)據(jù)量巨大,需要生成xml文件的客戶(hù)資料接近千萬(wàn)級(jí)別的程度,而現(xiàn)場(chǎng)對(duì)程序的配置大約是100W條數(shù)據(jù)生成一個(gè)xml文件里面去,程序在這樣的大數(shù)據(jù)量下面偶爾會(huì)有崩潰.

最近幾天現(xiàn)場(chǎng)催的比較緊,最近抽空把這個(gè)問(wèn)題處理了一下,在解決問(wèn)題的過(guò)程中我把解決的步驟和方法記錄了下來(lái),正好和大家共享一下

現(xiàn)場(chǎng)提的問(wèn)題概況:

數(shù)據(jù)量:生成xml,每個(gè)文件100W+條的數(shù)據(jù)

內(nèi)存控制:最好不要超過(guò)512M

問(wèn)題詳情:在處理70W左右的時(shí)候內(nèi)存溢出一、先來(lái)看一下程序要生成的xml文件的結(jié)構(gòu)Xml代碼

<File>

<FileType>1</FileType>

<RType>12</RType>

<Version>03</Version>

<BNo>004</BNo>

<FileQ>5</FileQ>

<FNo>0006</FNo>

<RecordNum>1000000</RecordNum>

<!--

上面是文件頭

下面是百萬(wàn)個(gè)<RecordList>

-->

<RecordList>

<Msisdn>10350719507</Msisdn>

<State>1</State>

<StartDate>20110303</StartDate>

<Date>20110419</Date>

<Balance>45000</Balance>

</RecordList>

...

<!--

可能百萬(wàn)個(gè)

<RecordList>

塊-->

</File>

二、給大家說(shuō)一下如何把大數(shù)據(jù)生成xml文件

1、小數(shù)據(jù)量的情況下

<

1W條數(shù)據(jù)

比較好用的方法是使用開(kāi)源框架,比如XStream直接把javabean生成xml

優(yōu)點(diǎn):api操作簡(jiǎn)單,方便維護(hù)

缺點(diǎn):數(shù)據(jù)量大的情況下太消耗內(nèi)存

2、大數(shù)據(jù)量生成一個(gè)xml文件(本程序采用的方法)

自己做的一個(gè)可以使用極少的內(nèi)存生成無(wú)限制大的xml文件框架由3部分生成xml文件

第一部分:生成文件頭

例如:xxx.toXML(Objectobj,StringfileName)

第二部分:通過(guò)每次向文件里面追加3000(可配置)條數(shù)據(jù)的形式生成文件塊

5、專(zhuān)門(mén)把批處理代碼提取出來(lái)通過(guò)JProfile內(nèi)存分析.最終問(wèn)題定位完畢.

原因如下:100W數(shù)據(jù)生成一個(gè)文件的過(guò)程中,等文件生成完畢之后才能把數(shù)據(jù)庫(kù)中的數(shù)據(jù)備份到歷史表中,這個(gè)時(shí)候才能進(jìn)行事務(wù)的提交,也就是執(zhí)行commit(),并且刪除原表數(shù)據(jù),100W數(shù)據(jù)按照3000一批寫(xiě)入文件,每批次只是通過(guò)PreparedStatement.addBatch();加入到批次里面去,并沒(méi)有執(zhí)行PreparedStatement.executeBatch(),而是在commit()之前統(tǒng)一調(diào)用的PreparedStatement.executeBatch(),這樣的話(huà)PreparedStatement就會(huì)緩存100W條數(shù)據(jù)信息,造成了內(nèi)存溢出.錯(cuò)誤的方法如下:Java代碼

try{

conn.setAutoCommit(false);

pst

=

conn.prepareStatement(insertSql);

pstDel

=

conn.prepareStatement(delSql);

pstUpdate

=

conn.prepareStatement(sql);

...

//totalSize

=

100W數(shù)據(jù)

/

3000一批次

for

(int

i

=

1;

i

<=

totalSize;

i++)

{

client.appendXML(list);

}

//

錯(cuò)誤的使用方法

client.finishXML();

pst.executeBatch();

pstDel.executeBatch();

}

...

finally

{

try

{

if

(isError)

{

conn.rollback();

}

else

mit();

...

}

...

}

正確的方法如下

try{Java代碼

conn.setAutoCommit(false);

pst

=

conn.prepareStatement(insertSql);

pstDel

=

conn.prepareStatement(delSql);

pstUpdate

=

conn.prepareStatement(sql);

...

//totalSize

=

100W數(shù)據(jù)

/

3000一批次

for

(int

i

=

1;

i

<=

totalSize;

i++)

{

list

=

從數(shù)據(jù)庫(kù)中查詢(xún)3000條數(shù)據(jù)

client.appendXML(list);

pst.executeBatch();

pstDel.executeBatch();

}

client.finishXML();

...

inally

{

try

{

if

(isError)

{

conn.rollback();

}

else

mit();

...

}

...

如果碰到和我一樣的需要給大家一個(gè)提醒.

oracle在每次執(zhí)行executeBatch();進(jìn)行批處理的時(shí)候,當(dāng)前connection對(duì)應(yīng)的rownum會(huì)根據(jù)操作的結(jié)果發(fā)生變化.

在執(zhí)行pst.executeBatch();之后,當(dāng)前連接的rownum數(shù)就會(huì)發(fā)生變化.因此凡是通過(guò)rownum查詢(xún)數(shù)據(jù)的程序都要小心這一點(diǎn)java千萬(wàn)級(jí)別數(shù)據(jù)處理(2)-千萬(wàn)級(jí)別FTP下載博客分類(lèi):

Java開(kāi)發(fā)經(jīng)驗(yàn)javaFTP下載千萬(wàn)級(jí)別數(shù)據(jù)處理

這個(gè)也是以前做過(guò)的一個(gè)程序,目的主要是去ftp主機(jī)(最多100左右)去取xx數(shù)據(jù)文件.

千萬(wàn)級(jí)別只是個(gè)概念,代表數(shù)據(jù)量等于千萬(wàn)或者大于千萬(wàn)的數(shù)據(jù)

本分享不牽扯分布式采集存儲(chǔ)之類(lèi)的.是在一臺(tái)機(jī)器上處理數(shù)據(jù),如果數(shù)據(jù)量很大很大的話(huà),可以考慮分布式處理,如果以后我有這方面的經(jīng)驗(yàn),會(huì)及時(shí)分享的.1、程序采用的ftp工具,apache的commons-net-ftp-2.0.jar

2、千萬(wàn)級(jí)別ftp核心關(guān)鍵的部分--列目錄到文件,只要是這塊做好了,基本上性能就沒(méi)有太大的問(wèn)題了.

可以通過(guò)apache發(fā)送ftp命令"NLST"的方式列目錄到文件中去

#ftp列目錄執(zhí)行的命令以環(huán)境變量的配置優(yōu)先,不配置則使用默認(rèn)的列目錄方式NLSTJava代碼

#

DS_LIST_CMD

=

NLST

public

File

sendCommandAndListToFile(String

command,String

localPathName)

throws

IOException

{

try

{

return

client.createFile(command,

localPathName);

}

catch

(IOException

e)

{

log.error(e);

throw

new

IOException("the

command

"+command

+"

is

incorrect");

}

}

當(dāng)然應(yīng)該還有其他形式的,大家可以自己研究一下

十萬(wàn)級(jí)別以上的數(shù)據(jù)量的話(huà)千萬(wàn)不要使用下面這種方式,如果用的話(huà)====找死

FTPFile[]dirList=client.listFiles();

3、分批次從文件中讀取要下載的文件名.

加載到內(nèi)存中處理,或者讀取一個(gè)文件名就下載一個(gè)文件,不要把所有的數(shù)據(jù)都加載到內(nèi)存,如果很多的話(huà)會(huì)出問(wèn)題

為啥要分批次?

因?yàn)槭谴髷?shù)據(jù)量,如果有1000W條記錄,列出來(lái)的目錄文件的大小1G以上吧4、文件下載的核心代碼----關(guān)于文件的斷點(diǎn)續(xù)傳,獲得ftp文件的大小和本地文件的大小進(jìn)行判斷,然后使用ftp提供的斷點(diǎn)續(xù)傳功能

下載文件一定要使用二進(jìn)制的形式

client.enterLocalPassiveMode();//設(shè)置為被動(dòng)模式

ftpclient.binary();

//一定要使用二進(jìn)制模式

Java代碼

/**

下載所需的文件并支持?jǐn)帱c(diǎn)續(xù)傳,下載后刪除FTP文件,以免重復(fù)

*

@param

pathName

遠(yuǎn)程文件

*

@param

localPath

本地文件

*

@param

registerFileName

記錄本文件名稱(chēng)目錄

*

@param

size

上傳文件大小

*

@return

true

下載及刪除成功

*

@throws

IOException

*

@throws

Exception

*/

public

boolean

downLoad(String

pathName,

String

localPath)

throws

IOException

{

boolean

flag

=

false;

File

file

=

new

File(localPath+".tmp");//設(shè)置臨時(shí)文件

FileOutputStream

out

=

null;

try{

client.enterLocalPassiveMode();//

設(shè)置為被動(dòng)模式

client.setFileType(FTP.BINARY_FILE_TYPE);//設(shè)置為二進(jìn)制傳輸

if(lff.getIsFileExists(file)){//判斷本地文件是否存在,如果存在并且長(zhǎng)度小于FTP文件的長(zhǎng)度時(shí)斷點(diǎn)續(xù)傳;返之新增

long

size

=

this.getSize(pathName);

long

localFileSize

=

lff.getSize(file);

if(localFileSize

>

size){

return

false;

}

out

=

new

FileOutputStream(file,true);

client.setRestartOffset(localFileSize);

flag

=

client.retrieveFile(new

String(pathName.getBytes(),client.getControlEncoding()),out);

out.flush();

}

else{

out

=

new

FileOutputStream(file);

flag

=

client.retrieveFile(new

String(pathName.getBytes(),client.getControlEncoding()),out);

out.flush();

}

}catch(IOException

e){

log.error(e);

log.error("file

download

error

!");

throw

e;

}finally{

try{

if(null!=out)

out.close();

if(flag)

lff.rename(file,

localPath);

}catch(IOException

e){

throw

e;

}

}

return

flag;

}

/**

*

獲取文件長(zhǎng)度

*

@param

fileNamepath

本機(jī)文件

*

@return

*

@throws

IOException

*/

public

long

getSize(String

fileNamepath)

throws

IOException{

FTPFile

[]

ftp

=

client.listFiles(new

String(fileNamepath.getBytes(),client.getControlEncoding()));

return

ftp.length==0

?

0

:

ftp[0].getSize();

}

檢測(cè)本地文件是否已經(jīng)下載,如果下載文件的大小.

/**

*本地文件的

獲取文件的大小

*

@param

file

*

@return

*/

public

long

getSize(File

file){

long

size

=

0;

if(getIsFileExists(file)){

size

=

file.length();

}

return

size;

}

5、因?yàn)槌绦蛞茏疃?00多個(gè)線程,在線程監(jiān)控上做了一些處理,可以

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論