java千萬級別數(shù)據(jù)處理.doc_第1頁
java千萬級別數(shù)據(jù)處理.doc_第2頁
java千萬級別數(shù)據(jù)處理.doc_第3頁
java千萬級別數(shù)據(jù)處理.doc_第4頁
java千萬級別數(shù)據(jù)處理.doc_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

java千萬級別數(shù)據(jù)生成文件思路和優(yōu)化博客分類: java大數(shù)據(jù)處理javajava大數(shù)據(jù)java數(shù)據(jù)處理千萬級別數(shù)據(jù) 一年前寫過一個百萬級別數(shù)據(jù)庫數(shù)據(jù)生成配置xml文件的程序,程序目的是用來把數(shù)據(jù)庫里面的數(shù)據(jù)生成xml文件.程序可以配置多少文件生成到一個文件中去. 程序剛開始設(shè)計的時候說的是最多百萬級別數(shù)據(jù),最多50W數(shù)據(jù)生成到一個xml文件里面去,所以在做測試的時候自己也只是造了100W的數(shù)據(jù)并沒有做過多數(shù)據(jù)量的測試,然后問題就來了.由于程序使用的局點數(shù)據(jù)量巨大,需要生成xml文件的客戶資料接近千萬級別的程度,而現(xiàn)場對程序的配置大約是100W條數(shù)據(jù)生成一個xml文件里面去,程序在這樣的大數(shù)據(jù)量下面偶爾會有崩潰. 最近幾天現(xiàn)場催的比較緊,最近抽空把這個問題處理了一下,在解決問題的過程中我把解決的步驟和方法記錄了下來,正好和大家共享一下現(xiàn)場提的問題概況: 數(shù)據(jù)量:生成xml,每個文件100W+ 條的數(shù)據(jù) 內(nèi)存控制:最好不要超過512M 問題詳情:在處理70W左右的時候內(nèi)存溢出一、先來看一下程序要生成的xml文件的結(jié)構(gòu)Xml代碼1. 2. 13. 124. 035. 0046. 57. 00068. 10000009. !-上面是文件頭下面是百萬個-10. 11. 1035071950712. 113. 2011030314. 2011041915. 4500016. 17. .!-可能百萬個塊-18. 二、給大家說一下如何把大數(shù)據(jù)生成xml文件 1、小數(shù)據(jù)量的情況下 1W條數(shù)據(jù) 比較好用的方法是使用開源框架,比如XStream 直接把javabean 生成 xml 優(yōu)點:api操作簡單,方便維護(hù) 缺點:數(shù)據(jù)量大的情況下太消耗內(nèi)存 2、大數(shù)據(jù)量生成一個xml文件(本程序采用的方法) 自己做的一個可以使用極少的內(nèi)存生成無限制大的xml文件框架由3部分生成xml文件 第一部分:生成文件頭 例如: xxx.toXML(Object obj, String fileName) 第二部分:通過每次向文件里面追加3000(可配置)條數(shù)據(jù)的形式生成文件塊 例如:xxx.appendXML(Object object); /object 可以是ArrayList 或者一個單獨的javaBean 第三部分:生成xml文件尾巴 例如:xxx.finishXML(); 程序中的調(diào)用:調(diào)用xxx.toXML(Object obj, String fileName) 生成文件頭之后,可以循環(huán)從數(shù)據(jù)庫中讀取數(shù)據(jù)生成ArrayList,通過xxx.appendXML(Object object) 方法追加到xml文件里面,xxx.finishXML() 對文件進(jìn)行收尾 對框架說明:我上面提供的例子有文件頭 + 文件塊 + 文件尾巴. 如果和你們的實際使用文件不太一致的話,可以參考上面提供的思路修改一下即可,主要的方法是把相同的文件塊部分分離出來通過追加的形式寫入xml文件. 有了思路之后,大家可以嘗試著自己寫一個類似的大數(shù)據(jù)處理框架(千萬級別以上),如何有什么需要幫助的可以直接聯(lián)系我,因為是公司的程序,不太敢放出來,怕. 三、我是如何測試性能和優(yōu)化的 1、手動排除 根據(jù)文件崩潰時候的日志發(fā)現(xiàn)是在生成xml的框架里面報的錯誤,第一想到的是框架有些資源沒有釋放.于是把自己做的文件生成框架整體的排查了一遍,并且自己寫個簡單程序生成200萬條數(shù)據(jù),使用xml框架生成一個xml文件,整個生成過程中任務(wù)管理器(xp)查看程序?qū)?yīng)的java進(jìn)程使用的內(nèi)存基本在20M左右,因此排除框架的問題.懷疑是數(shù)據(jù)庫查詢和調(diào)用框架的部門出現(xiàn)問題. 檢測了一遍主程序的關(guān)鍵部分代碼,優(yōu)化了一下字符串處理.手動的釋放一些對象的內(nèi)存(例如:調(diào)用ArrayList.clear(),或者把對象置空等),分配512內(nèi)存后運行程序,60萬數(shù)據(jù)的時候內(nèi)存溢出,因為能主動釋放的對象都已經(jīng)釋放掉了,還是沒有解決,果斷放棄看代碼,準(zhǔn)備使用JProfile進(jìn)行內(nèi)存檢測. 2、手動排除沒有解決,借助內(nèi)存分析工具JProfile進(jìn)行排除 通過在數(shù)據(jù)庫中生成300W條數(shù)據(jù),在JProfile上面多跑程序,一邊運行,一邊調(diào)用JProfile 提供的執(zhí)行GC按鈕主動運行垃圾回收,運行50W數(shù)據(jù)后,通過檢測中發(fā)現(xiàn) java.long.String 和 oracle.jdbc.driver.Binder 兩個對象的數(shù)目一直保持在自增狀態(tài),而且數(shù)目基本上差不多,對象數(shù)目 都在200W以上,由于java.long.String對象是需要依賴對象而存在的,因此斷定問題就出在oracle.jdbc.driver.Binder上面,由于改對象存在引用導(dǎo)致String不能正?;厥? 3、通過在JProfile對象查看對象的管理 檢測到oracle.jdbc.driver.Binder 被 oracle.jdbc.driver.T4CPreparedStatement 引起,而T4CPreparedStatement正好是Oracle對jdbc OraclePreparedStatement的具體實現(xiàn),因此斷定是在數(shù)據(jù)庫處理方面出現(xiàn)的問題導(dǎo)致oracle.jdbc.driver.Binder對象不能正常釋放,通過再一次有目的的檢測代碼,排查jdbc數(shù)據(jù)查詢的問題,把問題的矛頭直至數(shù)據(jù)庫的批處理和事務(wù)處理.因此程序是每生成一個文件成功后,會把已經(jīng)處理的數(shù)據(jù)轉(zhuǎn)移到對應(yīng)的歷史表中進(jìn)行備份,而再個表操作的過程中使用了批處理和事務(wù),使用批處理主要是保證執(zhí)行速度,使用事務(wù)主要是保證同時成功和失敗。 4、又因此程序每次從數(shù)據(jù)庫中查詢3000條數(shù)據(jù)處理,所以準(zhǔn)備監(jiān)控oracle.jdbc.driver.Binder的對象數(shù)目是否和查詢次數(shù)對應(yīng).,通過在程序中Sysout輸出查詢次數(shù) + JProfile運行GC測試 Binder,數(shù)據(jù)匹配,證實是java在數(shù)據(jù)庫批處理的過程中有些問題. 5、專門把批處理代碼提取出來通過JProfile內(nèi)存分析.最終問題定位完畢. 原因如下:100W數(shù)據(jù)生成一個文件的過程中,等文件生成完畢之后才能把數(shù)據(jù)庫中的數(shù)據(jù)備份到歷史表中,這個時候才能進(jìn)行事務(wù)的提交,也就是執(zhí)行commit(), 并且刪除原表數(shù)據(jù),100W數(shù)據(jù)按照3000一批寫入文件,每批次只是通過 PreparedStatement.addBatch();加入到批次里面去,并沒有執(zhí)行PreparedStatement.executeBatch(),而是在commit()之前統(tǒng)一調(diào)用的PreparedStatement.executeBatch(),這樣的話PreparedStatement就會緩存100W條數(shù)據(jù)信息,造成了內(nèi)存溢出.錯誤的方法如下: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數(shù)據(jù)/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數(shù)據(jù)/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本機(jī)文件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. 檢測本地文件是否已經(jīng)下載,如果下載文件的大小.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多個線程,在線程監(jiān)控上做了一些處理,可以檢測那些死掉的線程,并及時的拉起來。 t.setUncaughtExceptionHandler(new ThreadException(exList);原理:給每個線程添加 UncaughtExceptionHandler,死掉的時候把線程對應(yīng)的信息加入到一個list里面,然后讓主線程每隔一段時間掃描一下list,如果有數(shù)據(jù),直接重新建一個線程運行即可6、如果程序是常駐內(nèi)存的話,別忘記了在finally中關(guān)閉掉 不用的ftp連接7、做大數(shù)據(jù)庫采集程序必須考慮到的一件事情 磁盤空間已滿的處理 java虛擬機(jī)對于磁盤空間已滿,在英文環(huán)境下的 linux aix 機(jī)器上 一般報 There is not enough space in the file system 中文環(huán)境下 一般報 磁盤空間已滿 大家可以使用下面的代碼進(jìn)行驗證 Java代碼1. /檢測磁盤控件是否已滿的異常Java代碼1. /

溫馨提示

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

評論

0/150

提交評論