一、背景及問題出現(xiàn)原因
項(xiàng)目是移動(dòng)端服務(wù),考慮到移動(dòng)網(wǎng)絡(luò)不穩(wěn)定、信號(hào)不好等因素,采用了一個(gè)異步非阻塞框架Vert.x,該框架是基于EventLoop思想實(shí)現(xiàn)的,可以看作是java中的node,基本上和node的思想一樣,唯一不同的是node的eventLoop線程只有一個(gè),是單線程的,而vert.x的eventLoop線程可以設(shè)置多個(gè),與cpu核數(shù)有關(guān),感興趣的具體可以參考vert.x官方文檔。
eventLoop線程是用輪訓(xùn)的方式處理事件的,當(dāng)有事件到達(dá)時(shí),eventLoop線程會(huì)拿到該事件,并找到對(duì)應(yīng)的事件處理器來響應(yīng)事件,事件處理器中一定不能阻塞(如讀取網(wǎng)絡(luò)、查詢db、讀取文件等),一旦阻塞,那么后續(xù)的所有請(qǐng)求都會(huì)被拒絕,整個(gè)系統(tǒng)就會(huì)不可用,直到崩潰。官方文檔中也明確說明千萬不要阻塞eventLoop線程,如果有耗時(shí)任務(wù),可以放到work線程中執(zhí)行。
但是由于歷史原因,系統(tǒng)中的所有響應(yīng)都是在eventLoop線程中執(zhí)行的,db查詢、網(wǎng)絡(luò)讀取等,我們也意識(shí)到這樣是有問題的,也正在重構(gòu)整個(gè)系統(tǒng),出現(xiàn)問題就維護(hù)性重啟,突然在一個(gè)周六的晚上,整個(gè)系統(tǒng)不能使用,拒絕所有的http請(qǐng)求,造成系統(tǒng)所有模塊回滾,經(jīng)排查,是因?yàn)橐粋€(gè)服務(wù)中httpClient在調(diào)用其他部門的服務(wù)時(shí),沒有設(shè)置connectionTimeout,正好那個(gè)部門的服務(wù)也慢,造成一直阻塞等待,阻塞eventLoop線程,導(dǎo)致服務(wù)不可用。
用vert.x框架的初衷是能夠更多更快的接收用戶請(qǐng)求,結(jié)果由于使用不當(dāng),造成了嚴(yán)重后果。
二、解決過程
弄清楚問題的原因,解決起來就比較同意了,首先對(duì)httpClient的調(diào)用的調(diào)用超時(shí)進(jìn)行設(shè)置,這樣當(dāng)?shù)谌椒?wù)慢,或者不可用時(shí),頂多阻塞幾秒(設(shè)置的超時(shí)),而不會(huì)一直阻塞下去;其次,將該任務(wù)放到work線程中執(zhí)行,不讓其阻塞eventLoop線程。修改后上線沒有該問題在出現(xiàn)。所以在使用類httpClient調(diào)用http服務(wù)時(shí),一定要設(shè)置超時(shí)時(shí)間,而不是讓線程一直等待下去。
三、總結(jié)
經(jīng)過這次嚴(yán)重的線上問題,自己對(duì)eventLoop思想有了更深一層的認(rèn)識(shí),也吸取教訓(xùn),不要存在僥幸心里,不合規(guī)矩的使用,問題日積月累,總有一天會(huì)把問題放大暴露出來,造成重大的損失。
另外,vert.x是很好的一個(gè)技術(shù),相信用好后,會(huì)給系統(tǒng)的性能帶來質(zhì)的提升,我也打算寫一系列vert.x框架的技術(shù)博客,將自己在項(xiàng)目中遇到的坑描述出來,幫助對(duì)該框架感興趣的同學(xué)繞過這些坑,一起學(xué)習(xí)進(jìn)步。