1. 程式人生 > >《即時訊息技術剖析與實戰》學習筆記4——IM系統如何保證訊息的可靠性

《即時訊息技術剖析與實戰》學習筆記4——IM系統如何保證訊息的可靠性

IM 系統中,保證訊息的可靠投遞主要體現在兩方面,一是訊息的不丟失,二是訊息的不重複。

一、訊息不丟失

訊息丟失的原因

首先看一下發送訊息的流程,如下圖所示:
訊息。可以採取“時間戳比對”機制進行完整性檢查。


(圖片來源於即時訊息技術剖析與實戰第 04 講)

使用者 A 發出的訊息,先到達IM服務端(步驟1),由服務端暫存(步驟2),成功後,服務端將成功的結果返回給使用者A(步驟3),同時將訊息推送給使用者B(步驟4)。
在這個過程中,丟失訊息有以下幾種情況:
1)步驟 1 因為網路不通等原因導致使用者A把訊息傳送到IM伺服器失敗;
2)步驟 2 IM伺服器儲存訊息失敗;
3)步驟 3 使用者A在超時時間內未收到IM伺服器返回的結果;

4)步驟 4 由於IM伺服器斷電等原因導致訊息未能成功推送給使用者B(但步驟 3 使用者A可以收到IM伺服器返回的響應成功結果);
5)步驟 4 訊息成功推送給使用者B的裝置,但使用者B的裝置因為一些原因如裝置寫入本地DB失敗等,也會導致訊息丟失。
前三種情況,使用者A將被提示訊息傳送失敗;後兩種情況,使用者B未收到訊息。

訊息丟失的解決方案

大部分場景中,業務層ACK確認機制 + 訊息重傳機制 + 訊息完整性檢查,能解決訊息丟失的問題。
1.業務層的ACK確認機制和重傳機制

ACK是確認字元(Acknowledge character)的意思,TCP協議預設提供了ACK機制,如果接收方成功接收到資料,就會回覆一個ACK資料,表示傳送方發出的資料已確認接收無誤,在“三次握手”、“四次揮手”中經常見到。

ACK確認機制:TCP傳輸時將每個位元組的資料都進行編號,即序列號。TCP傳輸的過程中,每次接收方收到資料後,都會對傳輸方進行確認應答,也就是傳送ACK報文。這個ACK報文當中帶有對應的確認序列號,告訴傳送方,接收到了哪些資料,下一次的資料從哪裡發。有了序列號能夠將接收到的資料根據序列號排序,並且去掉重複序列號的資料。這也是TCP傳輸可靠性的保證之一。
重傳機制:傳送方傳送一部分資料後,都會等待接收方傳送的ACK報文,並解析ACK報文,判斷資料是否傳輸成功。傳送方遲遲收不到ACK報文的原因可能有兩個:
1)資料在傳輸過程中由於網路原因等直接全體丟包,接收方沒有接收到;
2)接收方接收到了響應的資料,但是傳送的ACK報文響應卻由於網路原因丟包了。
超時重傳機制就是傳送方在傳送完資料後等待一個時間,如果在超時時間內沒有接收到ACK報文,就重新發送資料。如果是上述的第一個原因,接收方收到二次重發的資料後,便進行ACK應答。如果是第二個原因,接收方發現接收的資料已存在,就直接丟棄,仍舊傳送ACK應答。

業務層的ACK確認機制參考了TCP的ACK確認機制,其策略是IM伺服器在推送訊息時,攜帶一個標識SID(安全識別符號,類似TCP的sequenceId),推送出訊息後會將當前訊息新增到“待ACK訊息列表”,客戶端B成功接收完訊息後,會給IM伺服器回一個業務層的ACK包,包中攜帶有本條接收訊息的SID,IM伺服器接收後,會從“待ACK訊息列表”記錄中刪除此條訊息,本次推送才算真正結束。

業務層的訊息重傳機制也參考了TCP協議的重傳機制,IM伺服器的“等待ACK佇列”一般會維護一個超時計時器,一定時間內如果沒有收到使用者B發回的ACK包,就從“等待ACK佇列”中重新拉取並進行重推。

為什麼有了TCP協議本身的ACK機制,還需要業務層的ACK機制?
這是因為TCP屬於傳輸層,而IM服務屬於應用層。TCP的ACK保證網路傳輸層的可靠性,即訊息是否送達,但不能保證資料能夠被應用層正確可靠處理;業務層ACK進行訊息是否送達和是否正確處理的邏輯,達到不丟訊息、訊息不重複的目的。

2.時間戳比對檢查訊息完整性
在上面列舉的丟失訊息的第 4 種可能性中,如果步驟 4 IM伺服器將訊息推送出去後就宕機了,而這條訊息又因為某些原因丟失了,伺服器由於宕機無法觸發重傳機制,導致使用者B收不到該訊息。可以採取“時間戳比對”機制進行完整性檢查。


(圖片來源於即時訊息技術剖析與實戰第 04 講)

時間戳比對過程如下:
1)IM伺服器給使用者B推送msg1,同時帶上一個最新時間戳timestamp1。使用者B收到msg1後,更新本地的時間戳為timestamp1;
2)IM伺服器給使用者B推送msg2,同時帶上一個最新時間戳timestamp2。由於某種原因,使用者B和IM伺服器的連線斷開,導致msg2沒有成功推送到使用者B;
3)使用者B和IM伺服器重新建立連線後,將本地的時間戳timestamp1傳送給IM伺服器,IM伺服器將時間戳大於timestamp1的所有訊息全部發送給使用者B,同時帶上時間戳timestamp2(這裡假設時間戳大於timestamp1的訊息只有msg2,如果有msg3、msg4等多條訊息,應取最新訊息的時間戳);
4)使用者B收到msg2後,更新本地的時間戳為timestamp2。
通過這樣的比對可以有效解決訊息丟失的問題。但時間戳由於有時鐘不同步、或者一個時間戳內多條訊息的可能性,存在誤差,因此可以使用全域性的自增序列版本號來代替。

二、訊息不重複

訊息重複的原因

在上面列舉的丟失訊息的幾種可能性中,第 3 種可能性存在一種場景,步驟 4 將訊息成功推送給使用者B,但步驟 3 因為某些原因導致超時、使用者A收不到響應,這個時候會觸發重傳機制,使用者A重新發送請求,使用者B可能會收到重複訊息。

訊息重複的解決方案

IM伺服器推送訊息時,攜帶一個Sequence ID,這個Sequence ID在本次連線會話中唯一,同時針對同一條訊息不變。當接收方接收到訊息後,會根據這個Sequence ID來進行業務層的去重,可以有效地保證訊息的不重複。

三、小結

通過業務層的ACK機制、重傳機制和完整性檢查,可以有效解決推送過程中訊息丟失的問題;
通過客戶端的去重機制,可以有效解決訊息重複的問題。