天天看點

58到家通用實時消息平台架構細節

一、解決什麼問題 + 難點

解決什麼業務問題

端到雲的實時上報需求:58速運司機端gps實時上

雲到端的實時推送需求:58速運司機訂單實時推送

(3)端到端的聊天消息需求:使用者、商戶、客服之間的聊天溝通

難點:

(1)app無線環境下消息可達性<

(2)通用性,平台實作盡量與業務解耦

二、傳統解決方案與潛在不足

【端到雲:http輪詢上報gps消息】

方案一:直接通過業務線web-server寫db

方案二:通用web-server層調用業務服務層寫db

潛在不足:

(1)http短連接配接代價高(反複建立與銷毀連接配接)

(2)web-server層吞吐量較低(每秒處理千級别請求)

【雲到端:通過第三方push或者推送服務】

方案一:通過apns或者米推等第三方推送

方案二:通過自己搭建mqtt服務推送

(1)第三方可達性與實時性無法保證,第三方會進行推送限速

(2)mqtt可用性是個問題

【端到端:結合上面兩種方法實作】

傳統方案往往可以通過結合【端到雲】與【雲到端】來結合解決【端到端】的實時消息推送問題。

三、通用實時消息平台實作細節

業務的分析與抽象:司機、使用者、商家、客服均為“線上”業務 【端到雲的優化】

傳統方案潛在的問題:http輪詢效率不高,web-server性能有限 優化tips:消息平台使用tcp長連接配接(如上圖)

潛在的問題:消息平台與業務線app-server耦合,需要switch case業務線類型來分發投遞消息,新增業務線需要新增rpc調用(如上圖) 優化tips:使用消息總線msg-queue解耦(如下圖)

可以看到,使用消息總線後,新增消息發送方,消息平台隻需要配置消息類型與消息總線主題的映射關系,新增的app-server消費方訂閱新的主題即可,實作消息平台與業務的解耦。

【雲到端的優化】

潛在的問題:可用性問題與第三方限速優化tips:自己提供消息平台叢集,提供rpc接口,實作“雲到端”的消息通道

這裡要注意的是,“端到雲”使用消息總線,是為了業務解耦。“雲到端”直接使用rpc接口,也是為了業務解耦,新增消息推送方,消息平台無需改動代碼。

潛在的問題:不少司機推送訂單無回複,搶單率比預期的低

優化tips:引入狀态實時存儲,隻有“線上”狀态的使用者才推送消息

如果業務無關,則直接通過tcp通道投遞;如果業務相關,發送方先來一個“端到雲”的投遞(通過mq),業務伺服器處理再反向來一個“雲到端”的投遞(rpc)給接收方。

潛在問題:如果接收方不線上怎麼辦

優化tips:增加db存儲離線消息

潛在的問題:無線環境下經常網絡不穩(例如進出電梯斷網),消息經常丢失

優化tips:消息平台收到消息先落地資料庫,接收方收到後應用層ack再删除,以保證不丢失

如上圖(本文最重要的2張圖之一),整個消息投遞流程為:

(1)發送發将消息發給消息平?

(2)消息平台先将消息落地db

(3)消息平台回複發送方消息發送成功(此時和接收方是否接到無關)

(3)與此同時,并行的把消息投遞給接收方(如果不線上就存離線了)

(4)接收方應用層ack表示收到了消息

(5)消息平台将消息删除

(6)告之接收方ack已經成功處理

可以看到,是使用“應用層ack來解決消息可達性問題的”

潛在問題:發送方沒有收到第3步驟中的消息平台回複怎麼辦?

優化tips:發送方重發(伺服器無狀态)

潛在問題:接收方收到重發的備援消息怎麼辦?

優化tips:接收方去重(可以做到服務端完全無狀态,隻需要簡單投遞消息即可)

【分層架構說明】

整個系統的分層架構如上圖(本文最重要的2張圖之二),整個消息平台系統由:

(1)消息平台在app裡的msg-sdk,向app提供帥氣的接口

(2)msg-gate,整個消息平台的tcp接入門戶,保持tcp長連接配接,初步攻防,加解密,壓縮解壓縮

(3)msg-logic,整個消息平台邏輯處理的部分

(4)redis,高可用redis叢集存儲使用者線上狀态online/offline,以及使用者在哪一台msg-gate接入(如果線上)

(5)db,存儲離線消息

非消息平台的幾個業務部分:

(1)app:業務方app,可以有多個,通過msg-sdk來接入消息平台

(2)mq:消息平台通過mq來給業務方伺服器發“端到雲”的消息

(3)app-server:業務方後端,可以有多個,通過mq接收“端到雲”的消息,通過rpc發送“雲到端”的消息

【對外提供的接口說明】

消息平台對業務方提供的接口是很少很通用的接口。

msg-sdk對app提供的核心接口有:

1)login:接入消息平台

(2)logout:登出消息平台

(3)c2s:發送client to server“端到雲”的消息

(4)c2c:發送client to client“端到端”的消息

(5)get-offline-msg:拉取離線消息

(6)on-msg-recieved:收到消息的callback回調接口

消息平台對app-server提供的核心接口有:

(1)s2c:發送server to client“雲到端”的消息

其他業務方不需要關注,是msg-sdk與消息平台之間的内部接口有:

(1)keepalive:用于msg-sdk與消息平台的連接配接保持(對業務方透明)

(2)c2c-ack:使用者c2c接口的應用層ack接口(對業務方透明)

【如何實作跨帳号體系的聊天】

既然是通用的消息平台,如何實作跨帳号體系的消息發送呢(即如何實作qq與旺旺的聊天)?

解決方案:不再使用uid作為整個系統運作的key,而使用domain+uid,或者appid+uid來作為整個系統運作的key

潛在耦合點:這樣的話,login接口的邏輯處理,消息平台需要switch case (domain或者appid)來進行不同的登入驗證,與業務有一定的耦合,不過新增帳号體系的頻度很低,遠比新增消息類型低

【協定的擴充性設計】

app本質是cs架構,一旦放出去的版本就很難收回來,其相容系要求遠比bs架構難,如何做到新增功能的同時,還能友善的相容曆史舊版app呢?

(1)如何友善的增加接口?

解決方案:協定使用定長標頭 + 變長包體,使用指令号cmd來擴充新接口【這個變化對業務層是透明的,是msg-sdk與消息平台之間的事情】

(2)對于同一個接口,能否增加參數,而不影響舊版本的app?

解決方案:使用可擴充的序列化協定,例如protobuffer【protobuffer這個東西也對業務線透明】

(3)對于業務方,有很多種類的消息類型,有很多複雜的業務需求,如何保證業務擴充性的同時,又不會增加消息平台的複雜性,并對舊版本app相容?

例如業務線可能有這樣的潛在需求:

a)推送一個營運消息

b)推送消息内容支援字型、字号、加粗、顔色

c)推送消息支援圖檔

d)業務支援“視窗震動”,以及“對方正在輸入......”等需求

解決方案:使用可擴充的消息體協定(對消息平台透明),例如xml/json來支援可擴充的多樣消息類型,并對舊版本app相容

使用這種消息内容協定,能保證:擴充性好、舊版本相容、對消息平台透明等諸多好處,強烈建議使用

四、分布式架構細節

抱歉,主持人提醒時間已到,分布式架構擴充性、負載均衡性、可用性、一緻性的問題線下和大家分享,先放一個分布式架構圖吧:

如果你讀到了這裡,說明對消息平台還是有點興趣的,58到家消息平台團隊隻有一個同學,奇缺人,歡迎有志之士加入。

一些說明:base北京,核心團隊,技術導向,java方向,和58沈劍一個團隊

加入方式:(1)直接在文章下面留言(2)在公衆号回複“招聘”擷取加盟密鑰

五、總結

(1)“端到雲”消息投遞:tcp消息通道,消息總線業務解耦

(2)“雲到端”消息投遞:提供rpc接口,引入狀态存儲

(3)“端到端”消息投遞步驟如下圖:

“端到端”消息投遞

a)先存離線消息防丢失

b)ack機制保證可達

c)發送方消息重發

d)接收方消息去重

5)可擴充協定設計

a)定長標頭,變長包體,随時增加接口

b)可擴充序列化協定,随時變化接口

c)可擴充消息協定,随時增加類型

6)支援跨帳号體系聊天(多個域):使用domain(或者appid)+uid作為綜合key

(7)分層架構如下圖