阿里IM技術分享(七):閒魚IM的線上、離線聊天資料同步機制優化實踐

JackJiang發表於2022-03-16

本文由阿里閒魚技術團隊書閒分享,原題“如何有效縮短閒魚訊息處理時長”,有修訂和改動。

1、引言

閒魚技術團隊圍繞IM這個技術範疇,已經分享了好幾篇實踐性總結文章,本篇將要分享的是閒魚IM系統中線上和離線聊天訊息資料的同步機制上所遇到的一些問題,以及實踐性的解決方案。

學習交流:

(本文已同步釋出於:http://www.52im.net/thread-38...

2、系列文章

本文是系列文章的第7篇,總目錄如下:

《阿里IM技術分享(一):企業級IM王者——釘釘在後端架構上的過人之處》
《阿里IM技術分享(二):閒魚IM基於Flutter的移動端跨端改造實踐》
《阿里IM技術分享(三):閒魚億級IM訊息系統的架構演進之路》
《阿里IM技術分享(四):閒魚億級IM訊息系統的可靠投遞優化實踐》
《阿里IM技術分享(五):閒魚億級IM訊息系統的及時性優化實踐》
《阿里IM技術分享(六):閒魚億級IM訊息系統的離線推送到達率優化》
《阿里IM技術分享(七):閒魚IM的線上、離線聊天資料同步機制優化實踐》(* 本文)

3、問題背景

隨著使用者數的快速增長,閒魚IM系統也迎來了前所未有的挑戰。

歷經多年的業務迭代,客戶端側IM的程式碼已經因為多年的迭代層次結構不足夠清晰,之前一些隱藏起來的聊天資料同步問題,也隨著使用者數的增大而被放大。

這裡面的具體流程在於:後臺需要同步到使用者端側的資料包,後臺會根據資料包的業務型別劃分成不同的資料域,資料包在對應域裡面存在唯一且連續的編號,每一個資料包傳送到端側並且被成功消費後,端側會記錄當前每一個資料域已經同步過的版本編號,下一次資料同步就以本地資料域的編號開始,不斷的同步到客戶端。

當然使用者不會一直線上等待訊息,所以之前端側採用了推拉結合的方式保證資料的同步。

具體就是:

1)客戶端線上時:使用ACCS實時的將最新的資料內容推送到客戶端(ACCS是淘寶無線向開發者提供全雙工、低延時、高安全的通道服務);
2)客戶端從離線狀態啟動後:根據本地的資料域編號,拉取不線上時候的資料差;
3)當資料獲取出現黑洞時:觸發資料同步拉取(“黑洞”即指資料包Version不連續的狀態)。

4、問題分析

當前的聊天資料同步策略確實是可以基本保障IM的資料同步的,但是也伴隨著一些隱含的問題。

這些隱含的問題主要有:

1)短時間密集資料推送時,會快速的觸發多次資料域同步。域同步回來的資料如果存在問題,又會觸發新一輪的同步,造成網路資源的浪費。冗餘資料包/無效的資料內容會佔用有效內容的處理資源,又對CPU和記憶體資源造成浪費;
2)資料域中的資料包客戶端是否正常消費,服務端側無感知,只能被動地根據當前資料域資訊返回資料;
3)資料收取/訊息資料體解析/儲存落庫邏輯拆分不夠清晰,無法針對性的對某一層的程式碼拆分替換進行ABTest。

針對上述問題,我們對閒魚IM進行了分層改造——即抽離資料同步層。這樣優化,除了希望以後這個資料的同步內容可以用在IM之外,也希望隨著穩定性的增加,賦能其他的業務場景。

接下來的內容,我們重點來看下解決客戶端側閒魚IM聊天資料同步問題的一些實踐思路。

5、優化思路

5.1 分層拆分
對於服務端來說:業務側產出資料包後,會拼接上當前的資料域資訊,然後通過資料同步層將資料推送到端側。

對於客戶端來說:接收到資料包後,會根據當前的資料域資訊,來確定需要消費資料包的業務方,確保資料包在資料域內完整連續後,將資料體脫殼後交於業務側消費,並且應答消費的狀況。

資料同步層的抽取:把資料同步中的加殼、脫殼、校驗、重試流程封裝到一起,可以讓上層業務只需要關心自己需要監聽的資料域資訊,然後當這些資料域更新資料的時候,可以獲取到這些資料進行消費,而不再需要關心資料包是否完整。

這樣做的話:

1)業務側只需要關心業務側對接的協議;
2)資料側只需要關心資料側包裝的協議;
3)網路層負責真實的資料傳輸。

整體的架構原理如下:

總結一下就是:

1)對齊資料層資料傳輸協議、描述當前資料包體資料域資訊;
2)將訊息的處理/合併/落庫抽離成資料消費者;
3)上下樓依賴抽象化,去除對於具體實現的依賴。

5.2 資料層結構模型
基於對於資料模型剝離和對當下遇見問題的解決方案規整,將資料同步層拆分為下圖這樣的架構。

具體的實施思路就是:

1)App啟動時建立ACCS長連結服務,保證推推送通道連結,並且根據當前本地資料域資訊觸發一次資料拉取;
2)資料消費者註冊消費者資訊和需要監聽的資料域資訊,這裡是一對多的關係;
3)新的資料抵達端側後,將資料包放到指定的資料域的緩衝池,批量資料歸納結束後,重新出發資料的讀取;
4)根據當前資料域優先順序彈出最高優的資料包,判斷資料域版本是否符合消費者要求,符合則將資料包脫殼後丟給消費者消費,不符合則根據上一次正確的資料包的域資訊觸發增量的資料域同步拉取;
5)觸發資料域同步拉取時,block資料讀取,此時通過ACCS觸達的資料依舊會在繼續歸納到指定的資料域佇列中,等待資料域同步拉取結果,將資料包進行排序、去重,合併到對應的資料域佇列中。然後重新啟用資料讀取;
6)資料包體被消費者正確消費後,更新域資訊並且通過上行通道告知服務端已經正確處理的資料域資訊。

  • 資料域同步協議:

Region中攜帶的資料不必過多,但需將資料包的內容描述清楚,具體是:

1)目標使用者的ID,用以確定目標資料包是否正確;
2)資料域ID和優先順序資訊;
3)當前資料包的域優先順序版本。

  • 排序策略:

針對於域資料歸納,無論是在寫入資料的時候進行排序還是在讀取的時候進行查詢都需要進行一次排序的操作,時間複雜度最優也是O(logn)級別的。

在實際coding中發現由於在一個資料域裡面,資料包的Version資訊是連續唯一併且不存在斷層的,上一個穩定消費的資料體的Version資訊自增就是下一個資料包的Version,所以這裡採用了以Versio為主鍵的Map儲存,既降低了時間複雜度,也使得唯一標識的資料包後抵達端側的包內容可以覆蓋之前的包內容。

6、新的問題及解決策略

6.1 多資料來源和唯一資料消費的平衡
每當產生一條針對於當前使用者的資料包:

1)如果當前ACCS長連結存在,就會通過ACCS將資料包推送到客戶端;
2)如果App切換到後臺一段時間,或者直接被殺死,ACCS連結斷開,那麼只能通過離線推送到使用者的通知皮膚。

所以:每當App切換到活躍狀態,都需要根據當前本地儲存的資料域資訊從後臺觸發一次資料同步。

資料包觸達到客戶端側的來源主要是ACCS長連結的推送和域同步時的拉取,但是資料包的消費是根據資料域的監聽劃分的唯一消費者,也就是同一時間內只能消費一個資料包。

在壓力測試中:當後臺短時間內密集的將資料包通過ACCS推送到端側時,端側接收到的資料包並不有序,不連續的資料包域版本又會觸發新的資料域同步,導致同樣的一份資料包會通過兩個不同的渠道多次的觸達到端側,浪費了不必要的流量。

當資料域同步時:這個時間節點產生的新資料包也會推送到端側,資料體有效,並且需要被正確的消費。

針對上述這些問題的解決策略:

即在資料消費和資料獲取中間裝載一個資料中間層,當觸發資料域同步的時候block資料的讀取並且ACCS推送下來的資料包會被存放在一個資料的中轉站裡面,當資料域同步拉取的資料回來後,對資料進行合併後再重啟資料讀取流程。

6.2 資料域優先順序
需要推送到客戶端側的資料包,根據業務的不同優先順序也有不同的劃分。

使用者和使用者的聊天產生的資料包會比運營類的訊息的資料包優先順序要高一些,所以要當多優先順序的資料包快速的抵達端側時,高優先順序資料域的資料包需要被優先消費,而資料域的優先順序也是需要動態調整,需要不斷變換的優先順序策略。

針對這個問題的解決策略:

不同的資料域,產生不同的資料佇列,高優佇列裡面的資料包會被優先讀取消費。

每一個資料包體中帶回的資料域資訊,都可以標註當前的資料域優先順序,當資料域優先順序發生變化的時候,調整資料包消費優先順序策略。

7、優化後的效果

除去結構上分層梳理,使得資料同步層和依賴的服務內容可便捷解耦/每一個環節可插拔之外,資料同步中對於訊息消費時長/流量節省,壓力測試場景下優化效果更加明顯。

在“500ms內100條全亂序資料包推送”壓力測試場景下:

1)訊息處理時長(接收-上屏)縮短 31%;
2)流量損耗(最終拉取到端側資料包累積大小)降低35%。

8、後續的優化計劃

8.1 資料同步層能力提升
資料同步側的目標,既要保證資料包完整的到達端側,又要在保證穩定性的前提下儘可能的減少資料的拉取,使得每一次資料的獲取都有效。

後續資料同步層會著手於有效資料率和到達率進行更進一步的優化。

針對不同的場景,動態智慧調整資料同步的優先順序策略。

阻塞式長連結推送,保證同一時間只存在推模式或者拉模式,進一步減少冗餘資料包的推送。

8.2 IM端側整體架構升級
升級資料同步層策略主要還是要提升IM的能力,將資料同步分層後,接下來就是將訊息的處理流程化,對每一個流程都可監控可回溯,提升IM資料包的正確解析儲存和落庫率。

細化一下就是:

1)在資料來源側剝離開後,後續對IM的整改也會逐步的將訊息的處理分層剝離;
2)訊息處理關鍵節點的流程式上報、建立完整的監控體系,讓問題發現先於使用者輿情;
3)訊息完整性的動態自檢,最小化資料補償補全。

9、參考資料

[1] IM單聊和群聊中的線上狀態同步應該用“推”還是“拉”?
[2] IM群聊訊息如此複雜,如何保證不丟不重?
[3] 一套高可用、易伸縮、高併發的IM群聊、單聊架構方案設計實踐
[4] 一套億級使用者的IM架構技術乾貨(下篇):可靠性、有序性、弱網優化等
[5] 從新手到專家:如何設計一套億級訊息量的分散式IM系統
[6] 融雲技術分享:全面揭祕億級IM訊息的可靠投遞機制
[7] 移動端IM中大規模群訊息的推送如何保證效率、實時性?
[8] 現代IM系統中聊天訊息的同步和儲存方案探討
[9] 新手入門一篇就夠:從零開發移動端IM
[10] IM訊息送達保證機制實現(一):保證線上實時訊息的可靠投遞
[11] IM訊息送達保證機制實現(二):保證離線訊息的可靠投遞
[12] 零基礎IM開發入門(四):什麼是IM系統的訊息時序一致性?
[13] IM開發乾貨分享:我是如何解決大量離線訊息導致客戶端卡頓的

(本文已同步釋出於:http://www.52im.net/thread-38...

相關文章