引言
最近公司準備使用elasticsearch(es),將數(shù)據(jù)庫的記錄同步到es中,往外提供查詢的功能,而同步工具在選擇上有主要幾種:
1:elasticsearch-jdbc:作者蠻努力的,源源不斷的更新,Java寫的
2:elasticsearch-river:太監(jiān)了,已經(jīng)兩三年沒更新了
3:Go-mysql-elastic:國人寫的,還未穩(wěn)定
4:logstash-input-jdbc:Ruby寫的,且是官方推薦
由于本人是寫Java出身,所以盡量選擇Java的同步工具,所以Go、Ruby就沒有做更多考慮,而river的話,也是好久沒更新了,所以最終選擇下來準備使用elasticsearch-jdbc,說干就干,咋就擼起袖子開干了
調(diào)研及安裝
elasticsearch-jdbc的安裝不復雜,把zip包拉下來,放到一個環(huán)境跑起來就行了,具體可以去度娘及Google都行
問題
環(huán)境跑起來后,就看看功能是不是滿足要求,還不錯,除了物理刪除支持不是很好外,其他的增量數(shù)據(jù),全量數(shù)據(jù)都能進行同步,但是問題來了,用jconsole連上環(huán)境卻發(fā)現(xiàn),這個線程數(shù)源源不斷的增加,如下:

我們知道線程其實是很消耗系統(tǒng)資源的,內(nèi)存,Cpu等等,如果這個線程數(shù)量一致增加,那最終是OOM的結(jié)果,這樣的結(jié)果是不能進行生產(chǎn)上運行的,最終我們要解決這個問題的,故苦逼的排查開始了:
1:查文檔,翻看issue,我擦,還真有同道中人,有一個國人用中文提了一個問題,和我碰到的問題是一樣的;

作者也回復了,這個issue會在最新的版本中修復掉,但是他最新版本發(fā)布是啥時候,不知道啊,只能自己排查了。
2:用jstack來看了當前線程的狀態(tài),發(fā)現(xiàn)是wait-condition,wait。其他詳細信息沒有了,我們知道線程的狀態(tài)一般出現(xiàn)wait-condition都是因為網(wǎng)絡請求過去了,但是卻一直沒有返回,或者寫文件未關閉,只能是拉源碼自己看了
3:elasticsearch-jdbc的源碼還是比較精簡的,其就是一個source,slink,其中source是從RDMS里面讀取數(shù)據(jù),而slink是將數(shù)據(jù)寫入到Es中,而這兩個都是會有網(wǎng)絡請求的數(shù)據(jù),于是開始注代碼
把source的讀取注釋掉,如下:

這個是嵌入了source的拉取和slink的推送(不太清楚作者的命名是怎么想的),只要把beforeFetch(),fetch()注釋掉,source就不起作用了。
把afterFetch()注釋掉,slink就不起作用了,然而發(fā)現(xiàn)沒什么用,線程數(shù)還是源源不斷的增加
4:只能啃代碼了
elasticsearch-jdbc的增量同步的思路是提交一個Cron表達式或者時間間隔,然后每次都是創(chuàng)建一個同步對象來進行同步的,如下:

而JDBCImporter是每一次調(diào)度都會進行一次新建,所以相當于每一次進行同步該對象都是新的。仔細看了JDBCImporter的代碼

仔細看看prepare()方法

executorService由于JDBCImporter的新創(chuàng)建調(diào)度,又會進行重新一次設置,最終的結(jié)果就是每一次調(diào)度executorService都是最新的,而同步完成后,卻沒有釋放掉該線程池,最終修改也比較簡單。

在finally中,把這個新建的線程池關閉掉,并且設置為null值,讓他等待Gc就行了。修改完重新打包部署,觀察下線程數(shù),不再繼續(xù)增加了

最終代碼上傳在:
https://github.com/linking12/YuGong
總結(jié)
盡管java的gc讓程序員不再關注對象的消亡,但是對線程池這類的一些公共資源的一些維護還是需要慎重
另外就是想表達的是:我們使用任何一個開源項目還是首先的了解下他的一些設計思路,最好是閱讀一遍源碼