引言
最近公司準(zhǔn)備使用elasticsearch(es)诫睬,將數(shù)據(jù)庫(kù)的記錄同步到es中舷暮,往外提供查詢(xún)的功能态罪,而同步工具在選擇上有主要幾種:
1:elasticsearch-jdbc:作者蠻努力的,源源不斷的更新下面,Java寫(xiě)的
2:elasticsearch-river:太監(jiān)了复颈,已經(jīng)兩三年沒(méi)更新了
3:Go-mysql-elastic:國(guó)人寫(xiě)的,還未穩(wěn)定
4:logstash-input-jdbc:Ruby寫(xiě)的沥割,且是官方推薦
由于本人是寫(xiě)Java出身耗啦,所以盡量選擇Java的同步工具,所以Go机杜、Ruby就沒(méi)有做更多考慮帜讲,而river的話,也是好久沒(méi)更新了叉庐,所以最終選擇下來(lái)準(zhǔn)備使用elasticsearch-jdbc舒帮,說(shuō)干就干,咋就擼起袖子開(kāi)干了
調(diào)研及安裝
elasticsearch-jdbc的安裝不復(fù)雜陡叠,把zip包拉下來(lái)玩郊,放到一個(gè)環(huán)境跑起來(lái)就行了,具體可以去度娘及Google都行
問(wèn)題
環(huán)境跑起來(lái)后枉阵,就看看功能是不是滿(mǎn)足要求译红,還不錯(cuò),除了物理刪除支持不是很好外兴溜,其他的增量數(shù)據(jù)侦厚,全量數(shù)據(jù)都能進(jìn)行同步,但是問(wèn)題來(lái)了拙徽,用jconsole連上環(huán)境卻發(fā)現(xiàn)刨沦,這個(gè)線程數(shù)源源不斷的增加,如下:
我們知道線程其實(shí)是很消耗系統(tǒng)資源的,內(nèi)存膘怕,Cpu等等想诅,如果這個(gè)線程數(shù)量一致增加,那最終是OOM的結(jié)果岛心,這樣的結(jié)果是不能進(jìn)行生產(chǎn)上運(yùn)行的来破,最終我們要解決這個(gè)問(wèn)題的,故苦逼的排查開(kāi)始了:
1:查文檔忘古,翻看issue徘禁,我擦,還真有同道中人髓堪,有一個(gè)國(guó)人用中文提了一個(gè)問(wèn)題送朱,和我碰到的問(wèn)題是一樣的娘荡;
作者也回復(fù)了,這個(gè)issue會(huì)在最新的版本中修復(fù)掉骤菠,但是他最新版本發(fā)布是啥時(shí)候它改,不知道啊,只能自己排查了商乎。
2:用jstack來(lái)看了當(dāng)前線程的狀態(tài)央拖,發(fā)現(xiàn)是wait-condition,wait。其他詳細(xì)信息沒(méi)有了鹉戚,我們知道線程的狀態(tài)一般出現(xiàn)wait-condition都是因?yàn)榫W(wǎng)絡(luò)請(qǐng)求過(guò)去了鲜戒,但是卻一直沒(méi)有返回,或者寫(xiě)文件未關(guān)閉抹凳,只能是拉源碼自己看了
3:elasticsearch-jdbc的源碼還是比較精簡(jiǎn)的遏餐,其就是一個(gè)source,slink赢底,其中source是從RDMS里面讀取數(shù)據(jù)失都,而slink是將數(shù)據(jù)寫(xiě)入到Es中,而這兩個(gè)都是會(huì)有網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)幸冻,于是開(kāi)始注代碼
把source的讀取注釋掉粹庞,如下:
這個(gè)是嵌入了source的拉取和slink的推送(不太清楚作者的命名是怎么想的),只要把beforeFetch(),fetch()注釋掉洽损,source就不起作用了庞溜。
把a(bǔ)fterFetch()注釋掉,slink就不起作用了碑定,然而發(fā)現(xiàn)沒(méi)什么用流码,線程數(shù)還是源源不斷的增加
4:只能啃代碼了
elasticsearch-jdbc的增量同步的思路是提交一個(gè)Cron表達(dá)式或者時(shí)間間隔,然后每次都是創(chuàng)建一個(gè)同步對(duì)象來(lái)進(jìn)行同步的延刘,如下:
而JDBCImporter是每一次調(diào)度都會(huì)進(jìn)行一次新建漫试,所以相當(dāng)于每一次進(jìn)行同步該對(duì)象都是新的。仔細(xì)看了JDBCImporter的代碼
仔細(xì)看看prepare()方法
executorService由于JDBCImporter的新創(chuàng)建調(diào)度碘赖,又會(huì)進(jìn)行重新一次設(shè)置驾荣,最終的結(jié)果就是每一次調(diào)度executorService都是最新的,而同步完成后崖疤,卻沒(méi)有釋放掉該線程池,最終修改也比較簡(jiǎn)單。
在finally中典勇,把這個(gè)新建的線程池關(guān)閉掉劫哼,并且設(shè)置為null值,讓他等待Gc就行了割笙。修改完重新打包部署阐虚,觀察下線程數(shù),不再繼續(xù)增加了
最終代碼上傳在:
https://github.com/linking12/YuGong
總結(jié)
盡管java的gc讓程序員不再關(guān)注對(duì)象的消亡戴已,但是對(duì)線程池這類(lèi)的一些公共資源的一些維護(hù)還是需要慎重
另外就是想表達(dá)的是:我們使用任何一個(gè)開(kāi)源項(xiàng)目還是首先的了解下他的一些設(shè)計(jì)思路蓖救,最好是閱讀一遍源碼