成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

長(zhǎng)連接的心跳及重連設(shè)計(jì)

dreamGong / 3146人閱讀

摘要:超過后則認(rèn)為服務(wù)端出現(xiàn)故障,需要重連。同時(shí)在每次心跳時(shí)候都用當(dāng)前時(shí)間和之前服務(wù)端響應(yīng)綁定到上的時(shí)間相減判斷是否需要重連即可??蛻舳藱z測(cè)到某個(gè)服務(wù)端遲遲沒有響應(yīng)心跳也能重連獲取一個(gè)新的連接。

前言

說道“心跳”這個(gè)詞大家都不陌生,當(dāng)然不是指男女之間的心跳,而是和長(zhǎng)連接相關(guān)的。

顧名思義就是證明是否還活著的依據(jù)。

什么場(chǎng)景下需要心跳呢?

目前我們接觸到的大多是一些基于長(zhǎng)連接的應(yīng)用需要心跳來“?;睢?。

由于在長(zhǎng)連接的場(chǎng)景下,客戶端和服務(wù)端并不是一直處于通信狀態(tài),如果雙方長(zhǎng)期沒有溝通則雙方都不清楚對(duì)方目前的狀態(tài);所以需要發(fā)送一段很小的報(bào)文告訴對(duì)方“我還活著”。

同時(shí)還有另外幾個(gè)目的:

服務(wù)端檢測(cè)到某個(gè)客戶端遲遲沒有心跳過來可以主動(dòng)關(guān)閉通道,讓它下線。

客戶端檢測(cè)到某個(gè)服務(wù)端遲遲沒有響應(yīng)心跳也能重連獲取一個(gè)新的連接。

正好借著在 cim有這樣兩個(gè)需求來聊一聊。

心跳實(shí)現(xiàn)方式

心跳其實(shí)有兩種實(shí)現(xiàn)方式:

TCP 協(xié)議實(shí)現(xiàn)(keepalive 機(jī)制)。

應(yīng)用層自己實(shí)現(xiàn)。

由于 TCP 協(xié)議過于底層,對(duì)于開發(fā)者來說維護(hù)性、靈活度都比較差同時(shí)還依賴于操作系統(tǒng)。

所以我們這里所討論的都是應(yīng)用層的實(shí)現(xiàn)。

如上圖所示,在應(yīng)用層通常是由客戶端發(fā)送一個(gè)心跳包 ping 到服務(wù)端,服務(wù)端收到后響應(yīng)一個(gè) pong 表明雙方都活得好好的。

一旦其中一端延遲 N 個(gè)時(shí)間窗口沒有收到消息則進(jìn)行不同的處理。

客戶端自動(dòng)重連

先拿客戶端來說吧,每隔一段時(shí)間客戶端向服務(wù)端發(fā)送一個(gè)心跳包,同時(shí)收到服務(wù)端的響應(yīng)。

常規(guī)的實(shí)現(xiàn)應(yīng)當(dāng)是:

開啟一個(gè)定時(shí)任務(wù),定期發(fā)送心跳包。

收到服務(wù)端響應(yīng)后更新本地時(shí)間。

再有一個(gè)定時(shí)任務(wù)定期檢測(cè)這個(gè)“本地時(shí)間”是否超過閾值。

超過后則認(rèn)為服務(wù)端出現(xiàn)故障,需要重連。

這樣確實(shí)也能實(shí)現(xiàn)心跳,但并不友好。

在正常的客戶端和服務(wù)端通信的情況下,定時(shí)任務(wù)依然會(huì)發(fā)送心跳包;這樣就顯得沒有意義,有些多余。

所以理想的情況應(yīng)當(dāng)是客戶端收到的寫消息空閑時(shí)才發(fā)送這個(gè)心跳包去確認(rèn)服務(wù)端是否健在。

好消息是 Netty 已經(jīng)為我們考慮到了這點(diǎn),自帶了一個(gè)開箱即用的 IdleStateHandler 專門用于心跳處理。

來看看 cim 中的實(shí)現(xiàn):

pipeline 中加入了一個(gè) 10秒沒有收到寫消息的 IdleStateHandler,到時(shí)他會(huì)回調(diào) ChannelInboundHandler 中的 userEventTriggered 方法。

所以一旦寫超時(shí)就立馬向服務(wù)端發(fā)送一個(gè)心跳(做的更完善應(yīng)當(dāng)在心跳發(fā)送失敗后有一定的重試次數(shù));

這樣也就只有在空閑時(shí)候才會(huì)發(fā)送心跳包。

但一旦間隔許久沒有收到服務(wù)端響應(yīng)進(jìn)行重連的邏輯應(yīng)當(dāng)寫在哪里呢?

先來看這個(gè)示例:

當(dāng)收到服務(wù)端響應(yīng)的 pong 消息時(shí),就在當(dāng)前 Channel 上記錄一個(gè)時(shí)間,也就是說后續(xù)可以在定時(shí)任務(wù)中取出這個(gè)時(shí)間和當(dāng)前時(shí)間的差額來判斷是否超過閾值。

超過則重連。


同時(shí)在每次心跳時(shí)候都用當(dāng)前時(shí)間和之前服務(wù)端響應(yīng)綁定到 Channel 上的時(shí)間相減判斷是否需要重連即可。

也就是 heartBeatHandler.process(ctx); 的執(zhí)行邏輯。

偽代碼如下:

@Override
public void process(ChannelHandlerContext ctx) throws Exception {

    long heartBeatTime = appConfiguration.getHeartBeatTime() * 1000;
    
    Long lastReadTime = NettyAttrUtil.getReaderTime(ctx.channel());
    long now = System.currentTimeMillis();
    if (lastReadTime != null && now - lastReadTime > heartBeatTime){
        reconnect();
    }

}
IdleStateHandler 誤區(qū)

一切看起來也沒毛病,但實(shí)際上卻沒有這樣實(shí)現(xiàn)重連邏輯。

最主要的問題還是對(duì) IdleStateHandler 理解有誤。

我們假設(shè)下面的場(chǎng)景:

客戶端通過登錄連上了服務(wù)端并保持長(zhǎng)連接,一切正常的情況下雙方各發(fā)心跳包保持連接。

這時(shí)服務(wù)端突入出現(xiàn) down 機(jī),那么理想情況下應(yīng)當(dāng)是客戶端遲遲沒有收到服務(wù)端的響應(yīng)從而 userEventTriggered 執(zhí)行定時(shí)任務(wù)。

判斷當(dāng)前時(shí)間 - UpdateWriteTime > 閾值 時(shí)進(jìn)行重連。

但卻事與愿違,并不會(huì)執(zhí)行 2、3兩步。

因?yàn)橐坏┓?wù)端 down 機(jī)、或者是與客戶端的網(wǎng)絡(luò)斷開則會(huì)回調(diào)客戶端的 channelInactive 事件。

IdleStateHandler 作為一個(gè) ChannelInbound 也重寫了 channelInactive() 方法。


這里的 destroy() 方法會(huì)把之前開啟的定時(shí)任務(wù)都給取消掉。

所以就不會(huì)再有任何的定時(shí)任務(wù)執(zhí)行了,也就不會(huì)有機(jī)會(huì)執(zhí)行這個(gè)重連業(yè)務(wù)。

靠譜實(shí)現(xiàn)

因此我們得有一個(gè)多帶帶的線程來判斷是否需要重連,不依賴于 IdleStateHandler。

于是 cim 在客戶端感知到網(wǎng)絡(luò)斷開時(shí)就會(huì)開啟一個(gè)定時(shí)任務(wù):

之所以不在客戶端啟動(dòng)就開啟,是為了節(jié)省一點(diǎn)線程消耗。網(wǎng)絡(luò)問題雖然不可避免,但在需要的時(shí)候開啟更能節(jié)省資源。

在這個(gè)任務(wù)重其實(shí)就是執(zhí)行了重連,限于篇幅具體代碼就不貼了,感興趣的可以自行查閱。

同時(shí)來驗(yàn)證一下效果。

啟動(dòng)兩個(gè)服務(wù)端,再啟動(dòng)客戶端連接上一臺(tái)并保持長(zhǎng)連接。這時(shí)突然手動(dòng)關(guān)閉一臺(tái)服務(wù),客戶端可以自動(dòng)重連到可用的那臺(tái)服務(wù)節(jié)點(diǎn)。


啟動(dòng)客戶端后服務(wù)端也能收到正常的 ping 消息。

利用 :info 命令查看當(dāng)前客戶端的鏈接狀態(tài)發(fā)現(xiàn)連的是 9000端口。

:info 是一個(gè)新增命令,可以查看一些客戶端信息。

這時(shí)我關(guān)掉連接上的這臺(tái)節(jié)點(diǎn)。

kill -9 2142


這時(shí)客戶端會(huì)自動(dòng)重連到可用的那臺(tái)節(jié)點(diǎn)。
這個(gè)節(jié)點(diǎn)也收到了上線日志以及心跳包。

服務(wù)端自動(dòng)剔除離線客戶端

現(xiàn)在來看看服務(wù)端,它要實(shí)現(xiàn)的效果就是延遲 N 秒沒有收到客戶端的 ping 包則認(rèn)為客戶端下線了,在 cim 的場(chǎng)景下就需要把他踢掉置于離線狀態(tài)。

消息發(fā)送誤區(qū)

這里依然有一個(gè)誤區(qū),在調(diào)用 ctx.writeAndFlush() 發(fā)送消息獲取回調(diào)時(shí)。

其中是 isSuccess 并不能作為消息發(fā)送成功與否的標(biāo)準(zhǔn)。

也就是說即便是客戶端直接斷網(wǎng),服務(wù)端這里發(fā)送消息后拿到的 success 依舊是 true

這是因?yàn)檫@里的 success 只是告知我們消息寫入了 TCP 緩沖區(qū)成功了而已。

和我之前有著一樣錯(cuò)誤理解的不在少數(shù),這是 Netty 官方給的回復(fù)。

相關(guān) issue

https://github.com/netty/netty/issues/4915

同時(shí)感謝 95老徐以及閃電俠的一起排查。

所以我們不能依據(jù)此來關(guān)閉客戶端的連接,而是要像上文一樣判斷 Channel 上綁定的時(shí)間與當(dāng)前時(shí)間只差是否超過了閾值。



以上則是 cim 服務(wù)端的實(shí)現(xiàn),邏輯和開頭說的一致,也和 Dubbo 的心跳機(jī)制有些類似。

于是來做個(gè)試驗(yàn):正常通信的客戶端和服務(wù)端,當(dāng)我把客戶端直接斷網(wǎng)時(shí),服務(wù)端會(huì)自動(dòng)剔除客戶端。


總結(jié)

這樣就實(shí)現(xiàn)了文初的兩個(gè)要求。

服務(wù)端檢測(cè)到某個(gè)客戶端遲遲沒有心跳過來可以主動(dòng)關(guān)閉通道,讓它下線。

客戶端檢測(cè)到某個(gè)服務(wù)端遲遲沒有響應(yīng)心跳也能重連獲取一個(gè)新的連接。

同時(shí)也踩了兩個(gè)誤區(qū),坑一個(gè)人踩就可以了,希望看過本文的都有所收獲避免踩坑。

本文所有相關(guān)代碼都在此處,感興趣的可以自行查看:

https://github.com/crossoverJie/cim

如果本文對(duì)你有所幫助還請(qǐng)不吝轉(zhuǎn)發(fā)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73151.html

相關(guān)文章

  • 手摸手教你使用WebSocket[其實(shí)WebSocket也不難]

    摘要:缺點(diǎn)可能會(huì)導(dǎo)致丟失數(shù)據(jù)在斷開重連的這段時(shí)間中,恰好雙方正在通信。博客前端積累文檔公眾號(hào)以上參考資料教程理解心跳及重連機(jī)制協(xié)議分鐘從入門到精通 showImg(https://segmentfault.com/img/remote/1460000016797888?w=1152&h=720); 在本篇文章之前,WebSocket很多人聽說過,沒見過,沒用過,以為是個(gè)很高大上的技術(shù),實(shí)際上...

    jhhfft 評(píng)論0 收藏0
  • 淺析 Netty 實(shí)現(xiàn)心跳機(jī)制與斷線重連

    摘要:基礎(chǔ)何為心跳顧名思義所謂心跳即在長(zhǎng)連接中客戶端和服務(wù)器之間定期發(fā)送的一種特殊的數(shù)據(jù)包通知對(duì)方自己還在線以確保連接的有效性為什么需要心跳因?yàn)榫W(wǎng)絡(luò)的不可靠性有可能在保持長(zhǎng)連接的過程中由于某些突發(fā)情況例如網(wǎng)線被拔出突然掉電等會(huì)造成服務(wù)器和客戶端的 基礎(chǔ) 何為心跳 顧名思義, 所謂 心跳, 即在 TCP 長(zhǎng)連接中, 客戶端和服務(wù)器之間定期發(fā)送的一種特殊的數(shù)據(jù)包, 通知對(duì)方自己還在線, 以確保 ...

    waterc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<