微信多點(diǎn)登錄與QQ消息漫游架構(gòu)隨想

2018-09-06 17:44 更新

【需求緣起】

之前的一些文章簡(jiǎn)單介紹了“單人消息”》《“離線消息”》《“群消息”》《“用戶狀態(tài)”》的一些相關(guān)技術(shù)(點(diǎn)擊上面的link直接閱讀),今天來(lái)聊一聊“多點(diǎn)登陸”與“消息漫游”。


提問(wèn):什么是多點(diǎn)登錄?

回答:以微信為例,可以PC端,phone端同時(shí)登錄,同時(shí)收發(fā)消息

需要注意的是,一個(gè)端只能登錄一個(gè)實(shí)例,例如同一個(gè)QQ號(hào),在pc1上登錄,再到pc2上登錄,后者會(huì)把前者踢出,pc1會(huì)收到通知“你已在別處登錄xxoo”。


提問(wèn):什么是消息漫游?

回答:在任何一個(gè)終端的任何一個(gè)實(shí)例登錄qq,都能夠拉取到所有歷史聊天消息,這個(gè)就是消息漫游。

微信目前只支持“多點(diǎn)登錄”同時(shí)收發(fā)在線消息,沒(méi)有實(shí)現(xiàn)“消息漫游”,潛臺(tái)詞是:登出手機(jī)微信,登錄PC微信,聊天,再登錄手機(jī)微信,是看不到歷史消息的。


【架構(gòu)回顧】

常見(jiàn)即時(shí)通訊系統(tǒng)架構(gòu)抽象

整個(gè)即時(shí)通訊架構(gòu)可以抽象成這么幾層:

(1)客戶端:例如pc微信,手機(jī)qq

(2)服務(wù)端:

(2.1)入口層gate集群:能夠水平擴(kuò)展,保持與客戶端的連接

(2.2)邏輯層logic、路由層router集群:高可用可擴(kuò)展,實(shí)現(xiàn)業(yè)務(wù)邏輯,進(jìn)行消息的路由

(2.3)cache:高可用cache集群,用來(lái)存儲(chǔ)用戶的在線狀態(tài),與接入節(jié)點(diǎn)(用戶具體連接在哪個(gè)gate節(jié)點(diǎn))

(2.4)db固化存儲(chǔ)消息,群信息,好友關(guān)系鏈等信息


一個(gè)典型的消息投遞流程如上圖步驟1-5:

(1)用戶A登錄在gate1上,發(fā)出消息

(2)gate1將消息給logic/router

(3)logic/router查詢接收方的在線狀態(tài)(B在線,C不在線)

(4)例如接收方C不在線,存儲(chǔ)離線

(4)例如接收方B在線,且登錄在gate2上,消息投遞給gate2

(5)gate2將消息投遞給B

當(dāng)然,單對(duì)單消息有一系列應(yīng)用層超時(shí)、重傳、確認(rèn)、去重的機(jī)制,這不是本文的重點(diǎn),不進(jìn)行展開(kāi),細(xì)節(jié)詳見(jiàn)《微信為什么不丟消息》。


【接收方多點(diǎn)登陸】

接收方多點(diǎn)登陸

接收方多點(diǎn)登錄,pc也登錄,phone也登錄,后一端登錄不會(huì)將前一端踢出,cache中存儲(chǔ)狀態(tài)與登錄點(diǎn)時(shí),不再以u(píng)ser_id為key,改為以u(píng)ser_id+終端類(lèi)型為key即可。

B:online(狀態(tài)),gate2(登錄點(diǎn))

改為

B+pc:online(狀態(tài)),gate2(登錄點(diǎn))

B+phone:online(狀態(tài)),gate3(登錄點(diǎn))


當(dāng)用戶A給用戶B發(fā)送消息時(shí),取出所有B的登錄點(diǎn),進(jìn)行消息群發(fā)即可(如上圖中步驟4與步驟5)。

【發(fā)送方多點(diǎn)登陸】

有朋友可能要問(wèn),發(fā)送方和多點(diǎn)登錄有什么關(guān)系?

假設(shè)用戶A登錄了兩個(gè)點(diǎn),A1和A2;用戶B登錄了兩個(gè)點(diǎn)B1和B2

A(A1發(fā)出的)發(fā)送消息給B(B1和B2)

B(B1發(fā)出的)發(fā)送消息給A(A1和A2)

不就可以了么?

其實(shí)不然,A(A1發(fā)出的)發(fā)送消息給B(B1和B2),B(B1發(fā)出的)發(fā)送消息給A(A1和A2)

A2端雖然收到了所有B回復(fù)的消息,但消息其實(shí)是在A1端發(fā)出的,故A2端只知道聊天消息的一半(所有B的回復(fù)),缺失了聊天的上下文(所有A1端的發(fā)出)

故,如果發(fā)送方也進(jìn)行了多點(diǎn)登錄,發(fā)送出去的任何消息,除了要投遞給多點(diǎn)登錄的接收方,還需要投遞給多點(diǎn)登錄的發(fā)送方。

發(fā)送方多點(diǎn)登錄

如上圖,發(fā)送方A和接收方B都進(jìn)行了多點(diǎn)登陸,cache中存儲(chǔ)的信息為:

A+pc:online(狀態(tài)),gate0(登錄點(diǎn))

A+phone:online(狀態(tài)),gate1(登錄點(diǎn))

B+pc:online(狀態(tài)),gate2(登錄點(diǎn))

B+phone:online(狀態(tài)),gate3(登錄點(diǎn))


當(dāng)用戶A(phone端)給用戶B發(fā)送消息時(shí),除了要投遞給B的所有多點(diǎn)登錄端,還需要投遞給A多點(diǎn)登陸的其他端(pc端),如上圖中步驟4與步驟5。

只有這樣,才能在所有用戶的所有端,恢復(fù)與還原雙方聊天的上下文。


【消息漫游】

如果業(yè)務(wù)不需要支持“消息漫游”的功能,對(duì)于在線消息,如果用戶接收到,是不需要存儲(chǔ)到數(shù)據(jù)庫(kù)的。但如果要支持“換一臺(tái)機(jī)器也能看到歷史的聊天消息”,就需要對(duì)所有消息進(jìn)行存儲(chǔ)了。

消息漫游:所有消息均存儲(chǔ)

消息投遞如上圖,用戶A發(fā)送消息給用戶B,雖然B在線,仍然要增加一個(gè)步驟2.5,在投遞之前進(jìn)行存儲(chǔ),以備B的其他端登陸時(shí),可以拉取到歷史消息

消息漫游:客戶本地last_msg_id(time)拉消息

消息拉取如上圖,原本不在線的B(phone端),又重新登錄了,ta怎么拉取歷史消息?只需要在客戶端本地存儲(chǔ)一個(gè)上一次拉取到的msg_id(time),到服務(wù)端重新拉取即可。

這里還有個(gè)問(wèn)題,由于服務(wù)端存儲(chǔ)所有消息成本是非常高的,所以一般“消息漫游”是有時(shí)間(或者消息數(shù))限制,不能拉取所有所有幾年前的歷史消息,只能拉取3個(gè)月內(nèi)的云端消息。


【總結(jié)】

“多點(diǎn)登錄”是指多個(gè)端同時(shí)登錄一個(gè)帳號(hào),同時(shí)收發(fā)消息,關(guān)鍵點(diǎn)是:

(1)需要在服務(wù)端存儲(chǔ)同一個(gè)用戶多個(gè)端的狀態(tài)與登陸點(diǎn)

(2)發(fā)出消息時(shí),要對(duì)發(fā)送方的多端與接收端的多端,都進(jìn)行消息投遞


“消息漫游”是指一個(gè)用戶在任何端,都可以拉取到歷史消息,關(guān)鍵點(diǎn)是:

(1)所有消息存儲(chǔ)在云端

(2)每個(gè)端本地存儲(chǔ)last_msg_id,在登錄時(shí)可以到云端同步歷史消息

(3)云端存儲(chǔ)所有消息成本較高,一般會(huì)對(duì)歷史消息時(shí)間(或者條數(shù))進(jìn)行限制


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)