分布式服務(wù)框架可能會(huì)運(yùn)行在非常惡劣的網(wǎng)絡(luò)環(huán)境中葵蒂,網(wǎng)絡(luò)超時(shí)担敌、閃斷郭宝、對(duì)方進(jìn)程僵死或者處理緩慢等情況都有可能發(fā)生辞槐。為了保證在這些極端異常場(chǎng)景下服務(wù)仍能夠正常調(diào)用或者自動(dòng)恢復(fù),需要底層的協(xié)議棧支持HA粘室。
5.3.1 客戶端連接超時(shí)
在傳統(tǒng)的同步阻塞編程模式下榄檬,客戶端Socket發(fā)起網(wǎng)絡(luò)連接,往往需要指定連接超時(shí)時(shí)間衔统,這樣做的目的主要有兩個(gè):
- 在同步阻塞I/O模型中鹿榜,連接操作是同步阻塞的海雪,如果不設(shè)置超時(shí)時(shí)間,客戶端I/O線程可能會(huì)被長(zhǎng)時(shí)間阻塞舱殿,這會(huì)導(dǎo)致系統(tǒng)可用I/O線程數(shù)的減少奥裸。
- 業(yè)務(wù)層需要:大多數(shù)系統(tǒng)都會(huì)對(duì)業(yè)務(wù)流程執(zhí)行時(shí)間有限制,例如web交互類的響應(yīng)時(shí)間要小于3s沪袭〈滩剩客戶端設(shè)置連接超時(shí)時(shí)間是為了實(shí)現(xiàn)業(yè)務(wù)層的超時(shí)。
對(duì)NIO的SocketChannel枝恋,在非阻塞模式下创倔,它會(huì)直接返回連接結(jié)果,如果沒有連接成功焚碌,也沒有發(fā)生IO異常畦攘,則需要將SocketChannel注冊(cè)到Selector上監(jiān)聽連接結(jié)果。所有十电,異步連接的超時(shí)無法在API層面直接設(shè)置知押,而是需要通過用戶自定義定時(shí)器來主動(dòng)監(jiān)測(cè)。
5.3.2 客戶端重連機(jī)制
客戶端通過鏈路關(guān)閉監(jiān)聽器監(jiān)聽鏈路狀態(tài)鹃骂,如果鏈路中斷台盯,等待INTERVAL時(shí)間后,由客戶端發(fā)起重連操作畏线,如果重連失敗静盅,間隔周期INTERVAL后再次發(fā)起重連,知道重連成功寝殴。
為了保證服務(wù)端能夠有充足的時(shí)間釋放句柄資源蒿叠,在首次斷連時(shí),客戶端需要等待INTERVAL時(shí)間之后再次發(fā)起重連蚣常,而不是失敗后立即重連市咽。
為了保證句柄資源能夠及時(shí)釋放,無論什么場(chǎng)景下的重連失敗抵蚊,客戶端都必須保證自身的資源被及時(shí)釋放施绎,包括但不限于SocketChannel、Socket等贞绳。
重連失敗后谷醉,需要打印異常堆棧信息,方便后續(xù)的問題定位熔酷。為了防止服務(wù)端正常下線長(zhǎng)期不再上線孤紧,客戶端通常會(huì)對(duì)重連次數(shù)做限制,防止無限重連下午無謂的損耗資源拒秘。
5.3.3 客戶端重復(fù)握手保護(hù)
當(dāng)客戶端握手成功之后号显,在鏈路處于正常狀態(tài)下臭猜,不允許客戶端重復(fù)握手,以防止客戶端在異常狀態(tài)下反復(fù)重連導(dǎo)致句柄資源被耗盡押蚤。
服務(wù)端接收到客戶端的握手請(qǐng)求消息之后蔑歌,首先對(duì)IP地址進(jìn)行合法性檢驗(yàn),如果校驗(yàn)成功揽碘,在緩存的地址表中查看客戶端是否已經(jīng)登錄次屠,如果已經(jīng)登錄,則拒絕重復(fù)登錄雳刺,返回錯(cuò)誤碼-1劫灶,同時(shí)關(guān)閉TCP鏈路,并在服務(wù)端的日志中打印握手失敗的原因掖桦。
客戶端接收到握手失敗的應(yīng)答消息之后本昏,關(guān)閉客戶端的TCP連接,等待INTERVAL時(shí)間之后枪汪,再次發(fā)起TCP連接涌穆,直到認(rèn)證成功。
為了防止由服務(wù)端和客戶端對(duì)鏈路狀態(tài)理解不一致導(dǎo)致的客戶端無法握手成功的問題雀久,當(dāng)服務(wù)端連續(xù)N次心跳超時(shí)之后需要主動(dòng)關(guān)閉鏈路宿稀,清空該客戶端的地址緩存信息,以保證后續(xù)該客戶端可以重連成功赖捌,防止被重復(fù)登錄保護(hù)機(jī)制拒絕掉祝沸。
5.3.4 消息緩存重發(fā)
無論客戶端還是服務(wù)端,當(dāng)發(fā)生鏈路中斷之后巡蘸,在鏈路恢復(fù)之前奋隶,緩存在消息隊(duì)列中待發(fā)送的消息不能丟失,等鏈路恢復(fù)之后悦荒,重新發(fā)送這些消息,保證鏈路中斷期間消息不丟失嘹吨。
考慮到內(nèi)存溢出的風(fēng)險(xiǎn)搬味,建議消息緩存隊(duì)列設(shè)置上限,當(dāng)達(dá)到上限之后蟀拷,應(yīng)該拒絕繼續(xù)想該隊(duì)列添加新的消息碰纬。
5.3.5 心跳機(jī)制
在凌晨等業(yè)務(wù)低谷期時(shí)段,如果發(fā)生網(wǎng)絡(luò)閃斷问芬、連接被Hang住等網(wǎng)絡(luò)問題時(shí)悦析,由于沒有業(yè)務(wù)消息,應(yīng)用進(jìn)程很難發(fā)現(xiàn)此衅。到了白天業(yè)務(wù)高峰期時(shí)强戴,會(huì)發(fā)生大量的網(wǎng)絡(luò)通信失敗亭螟,嚴(yán)重的回導(dǎo)致一段時(shí)間進(jìn)程內(nèi)無法處理業(yè)務(wù)消息。為了解決這個(gè)問題骑歹,在網(wǎng)絡(luò)空閑時(shí)采用心跳機(jī)制來檢測(cè)鏈路的互通性预烙,一旦發(fā)生網(wǎng)絡(luò)故障,立即關(guān)閉鏈路道媚,主動(dòng)重連扁掸。