【如何構建商業級別聊天系統】 MQTT 篇(五)保活 Keep Alive,請不要讓你的 MQTT 服務變成小豬佩奇!
特關人上人!dying 擱淺 神秘連接
哥哥姐姐弟弟妹妹叔叔阿姨們~
說點閑話
keep alive 保活,不光是對于 MQTT 來說需要保活,其實我們很多的系統,在需要確定對方是否處于可通信狀態的時候都是需要這種保活機制,比如音頻聊天,那么音頻聊天的雙方和服務器端同樣也是需要一套 keep alive 保活的機制來確定雙方的狀態以便進行相應的處理,
了解 keep alive 對于系統設計來說是具備指導性意義,
MQTT 的 Keep Alive 保活機制
為什么需要保活?
TCP 半開連接問題 half-open ,
首先 MQTT 是基于 TCP 協議的,那么 TCP 的特性同樣適用于 MQTT :可靠、有序、錯誤檢測,
然而使用 TCP 連接的通信雙方之間的傳輸有時不會同步,
例如,通信程序中一方崩潰或者傳輸錯誤,這種不完全連接的狀態稱為 ”half-open“
那么此時的問題就是,通信雙方,一方崩潰并不會通知另一方,那么仍然連接的一方會繼續請求并等待回復,這顯然對于仍然連接的一方是體驗很差的,或者說不合理的,

對于此 MQTT 的發明者 Andy Stanford-Clark 是如此解釋的,
進一步說明規范的內容,keepalive 的目的是讓應用程式 級別(客戶端應用程式和代理)可以知道底層連接仍然是端到端的,
盡管理論上 TCP/IP 會在 socket 中斷時通知你,但實際上,特別是在移動和衛星鏈接等情況下,通常會通過空中 “偽造” TCP 并在每一端放回標頭,極有可能 TCP 會話到“黑洞”,即它似乎仍然打開,但實際上只是將你寫入的任何內容傾倒在地板上,
因此,keepalive 會確認你確實仍在與代理交談(并且從代理端,客戶端確實仍處于連接狀態),特別是當處于長時間連接的連接上時,或者訂閱了不常發布的主題,或在 qos0(即無確認)發布給 borker 代理,
應使用(由 MQTT 庫)從代理回傳的回應客戶端啟動的“ping-req”的 ping-resp(“pong”!)來告訴應用程式連接是否已消失,或觸發重新連接,
那么 MQTT 包含了這樣一個 ”保活“ 的功能,該功能為 half-open 問題提供了一個解決方案,或者說一個評估連接是否斷開的依據,
keep alive 確認 broker 代理 和 client 客戶端 之間的連接仍然打開,并且 broker 和 client 之間是可以感知到彼此是有連接的
具體操作就是,當客戶端與服務端建立連接后,客戶端向服務端進行以秒未間隔的通訊,這個時間間隔定義了,客戶端和服務器沒有通訊的最大時長,
MQTT 這樣對其定義:
“The Keep Alive … is the maximum time interval that is permitted to elapse between the point at which the Client finishes transmitting one Control Packet and the point it starts sending the next. It is the responsibility of the Client to ensure that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client MUST send a PINGREQ Packet.”
即: keep alive 是客戶端完成發送資料包的時間點到下一個發送資料包的時間點所允許經過的最大時間間隔,準確發送 PINGREQ 資料包是客戶端的責任,
只要訊息交換頻繁,且在 keep alive 所定義的時間范圍內,就不需要發送額外的訊息來確認連接,
但如果,在此期間,客戶端沒有發送訊息,它必須發送一個 PINGREQ 資料包 來確認 客戶端和代理雙方都是可用的狀態,
代理如果在 1.5 倍的 keep alive 時間間隔中 沒有收到客戶端的任何訊息或者 PINGREQ 保活資料包,則斷開客戶端連接,同樣的對于 客戶端,在合理的時間內沒有收到代理的回應也應該關閉連接,
Keep Alive Flow
keep alive 功能使用兩個資料包來保證: PINGREQ 和 PINGRESP

PINGREQ 由客戶端發送,無有效負載,客戶端可以在任何時候發送該包來確認連接狀態,

當服務端收到 PINGREQ 資料包時,必須回復一個 PINGRESP 資料包來表示其仍然可用,同樣的 PINGRESP 也不包含有效負載
必須要知道的事
- 如果客戶端在 keep alive 的時間段內 沒有發送任何資料包或者 PINGREQ 給服務端代理,則代理關閉連接,并且發送 LWT 最后的遺囑訊息 (如果客戶端有設定的話)
- MQTT 客戶端有責任設定合適的 keep alive 值,例如可以根據當前信號的強度來調整 keep alive 的時間間隔,
- 最大的 keep alive 間隔為 18h 12min 15 sec,如果 keep alive 的間隔為 0 則 keep alive 機制是無效的,
Client Task-Over 客戶端接管
通常,客戶端斷開連接后可能會重新連接,有時 broker 服務器仍然會提供 half-open 半開連接給客戶端(如在 1.5 倍的 keep alive 間隔內,客戶端嘗試斷線重連,此時就會有兩個客戶端連接),在 MQTT 中,如果 broker 代理檢測到了 半開連接,則會執行 客戶端接管,borker 會斷開先前的連接,并和客戶端建立新的連接,這一行為保證了 半開連接 不會阻止客戶端斷線重連,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/296848.html
標籤:其他
上一篇:專案實戰2 | 基于Swarm+Prometheus實作雙VIP可監控Web高可用集群
下一篇:grpc-go原始碼剖析六十一之假設在一條呼叫鏈上,存在多個grpc服務的呼叫,如A服務呼叫B服務呼叫C服務,那么他們的超時時間如何?
