TimeLine模型下確保訊息有序不丟

普通程式設計師發表於2018-11-08

透過《基於TimeLine模型的訊息同步機制》一文,我們瞭解到Timeline模型有非常多的優點,也是釘釘採用的訊息同步機制。實際工作中,我們也將該模型應用在了C端使用者的訊息場景中。實施過程中也遇到了一些問題,積累了一些經驗。本文將介紹極端情況丟失訊息的問題及解決辦法。

一、Timeline概念

Timeline可以簡單理解為是一個訊息佇列,某個使用者所有的訊息都儲存在這個Timeline中,使用者的各個端可以從這個佇列中同步各自訊息。 


TimeLine模型下確保訊息有序不丟

圖中的例子中,訊息傳送方是A,訊息接收方是B,同時B存在多個接收端,分別是B1、B2和B3。A向B傳送訊息,訊息需要同步到B的多個端,待同步的訊息透過一個Timeline來進行交換。A向B傳送的所有訊息,都會儲存在這個Timeline中,B的每個接收端都是獨立的從這個Timeline中拉取訊息。每個接收端同步完畢後,都會在本地記錄下最新同步到的訊息的msgid,即最新的一個位點,作為下次訊息同步的起始位點。

二、丟失訊息的原因

理論上講,Timeline模型能夠確保訊息不重不漏。實際實施中,根據系統架構特點以及選用中介軟體的不同,極端情況下,可能出現丟訊息。最主要的原因是某一時刻,Timeline中的資料不連續或不完整

舉個例子,如果使用者有兩條時間間隔非常近的訊息msg1、msg2,對應的msgId分別為10,11。由於時間很相近,(分散式系統)某些情況下可能出現msg2先寫入TimeLine,如果此時使用者某個端正好執行Sync同步訊息,將同步到最大msgId為11的msg2訊息,造成msg1丟失(msg1此時還沒有寫入TimeLine)。

下圖是IM系統的結構。Dispatcher負責生成msgId,透過Kafka傳遞給具體業務邏輯處理單元Processor(名稱與圖不完全一致),Processor將訊息寫入Redis/MongoDb。 


TimeLine模型下確保訊息有序不丟


這個過程中有三個環節會造成順序不一致

1、訊息msgid在Dispatcher節點生成(採用類snowflake演算法),由於不同節點時間可能存在誤差,有可能造成msgid和時序不一致

2、Kafka有多個patition,不同patition不能保證訊息順序

3、Processor是多例項部署,多執行緒處理,也不能保證順序

三、解決辦法

1、服務端嚴格有序

應用神奇的hash演算法,把屬於同一使用者的訊息路由到相同的Dispatcher節點,相同的Kafka分割槽,相同的Processor執行緒即可保證訊息循序性。但是對於群訊息,極端情況下還是可能出現時序問題(當然要丟訊息還需要客戶端正好執行Sync同步,這個機率極低)

2、客戶端補償

服務端為Timeline中的每條訊息都進行嚴格遞增編號,叫做sequenceid。從1開始,2、3、4……加一遞增。這樣,客戶端拉取到訊息,能夠透過sequenceid感知是否丟失訊息。如果丟失訊息,可以再次嘗試拉取。

這裡有個問題,這個嚴格編號服務我們利用了redis,萬一redis資料丟失怎麼辦呢?個人收件箱Timeline中最新一條訊息就是已有的最大編號,redis資料萬一丟失了可以從這條訊息中取得之前的最大編號。

透過這兩個方法,能夠確保訊息可靠性。 

微信ID:farmerbrag

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2219241/,如需轉載,請註明出處,否則將追究法律責任。

相關文章