天天看點

如何設計斷線自動重連機制 轉載

在有連接配接依賴關系的服務與服務之間,或用戶端與伺服器之間,無論是出于友善使用、降低運維成本、提高工作效率(服務與服務之間),還是優化使用者體驗(用戶端與伺服器之間)自動重連機制通常都是一個非常重要的功能。

  • 情景一

對于一組服務之間,如果其中一些服務(主動連接配接方,下文以 A 代稱)需要與另外一些服務(被連接配接方,下文以 B 代稱)建立 TCP 長連接配接,如果 A 沒有自動連接配接 B 的功能,那麼在部署或者測試這些服務的時候,必須先啟動 B,再啟動 A,因為一旦先啟動 A,A 此時去嘗試連接配接 B(由于 B 還沒有啟動)會失敗,之後 A 再也不會去連接配接 B了(即使随後 B 被啟動了),進而導緻整個系統不能正常工作。這是缺點一。

  • 情景二

即使部署或測試的時候,先啟動了 B,再啟動 A,A 與 B 之間的連接配接在運作期間内,可能由于網絡波動等原因導緻 A 與 B 之間連接配接斷開,之後整個系統也不能再正常工作了。這是缺點二。

  • 情景三

如果我們想更新 B,更新完程式後,重新開機 B,也必須重新開機 A。如果這種依賴鍊比較長(例如 A 連接配接 B,B 連接配接 C,C 連接配接 D,D 連接配接 E,等等),那麼更新某個程式的效率和成本會非常高。這是缺點三。

  • 情景四

對于用戶端軟體來說,如果因為使用者的網絡短暫故障導緻用戶端與伺服器失去連接配接,等網絡恢複後,較好的使用者體驗是用戶端能檢測到使用者網絡變化後,自動與伺服器重連,以便使用者能及時收到最新的消息。

以上四個情景說明了斷線自動重連功能的重要性,那如何去設計好的斷線重連機制呢?

重連本身的功能開發很簡單,其實就是調用 socket 函數 connect 函數,不斷去“重試”。這裡的“重試”我使用了雙引号,是為了說明重試的技巧非常有講究:

  • 對于伺服器端程式,例如 A 連接配接 B,如果連接配接不上,整個系統将無法工作,那麼我們開發 A 服務時,重連的邏輯可以很簡單,即 A 一旦發現與 B 斷開了連接配接,就立即嘗試與 B 重新連接配接,如果連接配接不上,隔一段時間再重試(一般設定為 3 秒或 5 秒即可),一直到連接配接成功為止。當然,期間可以不斷發送報警郵件或者持續輸出錯誤日志,來引起開發或者運維人員的盡快幹預,以便盡早排查和解決連接配接不上的原因。
  • 對于用戶端軟體,以上做法也是可以的,但是不是最優的。用戶端所處的網絡環境比伺服器程式所處的網絡環境一般要惡劣的多,等間隔的定時去重連,一般作用不大(例如使用者拔掉了網線)。是以,對于用戶端軟體,一般出現斷線,會嘗試去重連,如果連接配接不上,會隔個比前一次時間更長的時間間隔去重連,例如這個時間間隔可以是 2 秒、4 秒、8 秒、16秒等等。但是,這樣也存在一個問題,随着重連次數的變多,重連的時間間隔會越來越大(當然,你也可以設定一個最大重連時間間隔,之後恢複到之前較小的時間間隔)。如果網絡此時已經恢複(例如使用者重新插上網線),我們的程式需要等待一個很長的時間間隔(如 16 秒)才能恢複連接配接,這同樣不利于使用者體驗。一般情況下,如果網絡發生波動,我們的程式可以檢測網絡狀态,如果網絡狀态恢複正常此時應該立即進行一次重連,而不是一成不變地按照設定的時間間隔去重連。
作業系統提供了檢測網絡狀态變化的 API 函數,例如對于 Windows 可以使用 IsNetworkAlive() 函數去檢測,對于 Android,網絡變化時會發送消息類型是 WifiManager.NETWORK_STATE_CHANGED_ACTION 的廣播通知。

另外,還需要注意的是,如果用戶端網絡斷開,一般會在界面某個地方顯式地告訴使用者目前連接配接狀态,并提醒目前正在進行斷線重連,且應該有一個可以讓使用者放棄斷線重連或者立即進行一次斷線重連的功能。

綜上所述,總結起來,對于伺服器程式之間的重連可以設計成等時間間隔的定時重連,對于用戶端程式要結合依次放大重連時間間隔、網絡狀态變化立即重連或使用者主動發起重連這三個因素來設計。

不需要重連的情形

  • 使用者使用用戶端主動放棄重連;
  • 因為一些業務上的規定,禁止用戶端重連;

    舉個例子,如果某個系統同一時刻同一個賬戶隻允許登陸一個,某個賬戶在機器 A 上登陸,此時接着又在機器 B 上登陸,此時 A 将被伺服器踢下線,那麼此時 A 用戶端的邏輯就應該禁止自動重連。

技術上的斷線重連和業務上的斷線重連

繼續閱讀