有朋友問:數據庫
以微信爲例,能夠PC端,phone端同時登陸,同時收發消息。
畫外音:須要注意的是,一個端只能登陸一個實例,例如同一個QQ號,在pc1上登陸,再到pc2上登陸,後者會把前者踢出,pc1會收到通知「你已在別處登陸xxoo」。微信
在任何一個終端的任何一個實例登陸,都可以拉取到全部歷史聊天消息,這個就是消息漫遊。
畫外音:微信目前只支持「多點登陸」同時收發在線消息,以及最近幾條消息的「消息漫遊」,沒有實現所有消息的「漫遊」。架構
實現「接收方」多點登錄,架構要作什麼調整?
接收方多點登陸,pc也登陸,phone也登陸,後一端登陸不會將前一端踢出,cache中存儲狀態與登陸點時,再也不以user_id爲key,改成以user_id+終端類型爲key便可。ide
B:online(狀態),gate2(登陸點)優化
B+pc:online(狀態),gate2(登陸點)
B+phone:online(狀態),gate3(登陸點)架構設計
當用戶A給用戶B發送消息時,取出全部B的登陸點,進行消息羣發便可(如上圖中步驟4與步驟5)。
畫外音:接收方多點登陸,比較容易。設計
有朋友可能要問,發送方和多點登陸有什麼關係?
假設:
用戶A登陸了兩個點,A1和A2;
用戶B登陸了兩個點,B1和B2;
這樣:
A(A1發出的)發送消息給B(B1和B2);
B(B1發出的)發送消息給A(A1和A2);
不就能夠了麼?router
其實否則:
A(A1發出的)發送消息給B(B1和B2);
B(B1發出的)發送消息給A(A1和A2);
可是:
A2端雖然收到了全部B回覆的消息,但消息實際上是在A1端發出的,故A2端只知道聊天消息的一半(全部B的回覆),缺失了聊天的上下文(全部A1端的發出)。
畫外音:這個邏輯有點繞,多看幾遍。blog
故,若是發送方也進行了多點登陸,發送出去的任何消息,除了要投遞給多點登陸的接收方,還須要投遞給多點登陸的發送方。
畫外音:發送方發出的消息,也須要發給「發送方」。
如上圖,發送方A和接收方B都進行了多點登錄,cache中存儲的信息爲:
A+pc:online(狀態),gate0(登陸點)
A+phone:online(狀態),gate1(登陸點)
B+pc:online(狀態),gate2(登陸點)
B+phone:online(狀態),gate3(登陸點)路由
當用戶A(phone端)給用戶B發送消息時,除了要投遞給B的全部多點登陸端,還須要投遞給A多點登錄的其餘端(pc端),如上圖中步驟4與步驟5。
只有這樣,才能在全部用戶的全部端,恢復與還原雙方聊天的上下文。
畫外音:搞清楚了原理,修改並不難。
若是不須要支持「消息漫遊」,對於在線消息,若是用戶接收到,是不須要存儲到數據庫的。但若是要支持「換一臺機器也能看到歷史的聊天消息」,就須要對全部消息進行存儲。
消息投遞如上圖,用戶A發送消息給用戶B,雖然B在線,仍然要增長一個步驟2.5,在投遞以前進行存儲,以備B的其餘端登錄時,能夠拉取到歷史消息。
消息拉取如上圖,本來不在線的B(phone端)從新登陸了,怎麼拉取歷史消息呢?
只須要在客戶端本地存儲一個上一次拉取到的msg_id(time),到服務端從新拉取便可。
這裏還有個問題,因爲服務端存儲全部消息成本是很是高的,因此通常「消息漫遊」是有時間(或者消息數)限制,不能拉取全部全部幾年前的歷史消息,只能拉取最近的雲端消息。
畫外音:
你猜,微信有沒有存儲,幾年前的消息呢?
你猜,交一個超級會員費,是否是能夠查詢呢?
「多點登陸」是指多個端同時登陸一個賬號,同時收發消息,關鍵點是:
(1) 須要在服務端存儲同一個用戶多個端的狀態與登錄點;
(2) 發出消息時,要對發送方的多端與接收端的多端,都進行消息投遞;
「消息漫遊」是指一個用戶在任何端,均可以拉取到歷史消息,關鍵點是:
(1) 全部消息存儲在雲端;
(2) 每一個端本地存儲last_msg_id,在登陸時能夠到雲端同步歷史消息;
(3) 雲端存儲全部消息成本較高,通常會對歷史消息時間(或者條數)進行限制;
假如你來實現,你會怎麼作?
但願你們有收穫。
架構師之路-分享可落地的技術文章
相關推薦:《GFS架構啓示》《Google MapReduce解決什麼問題?》《Google MapReduce巧妙優化思路?》《Google MapReduce架構設計實踐》《MapReduce,顛覆了分層架構的本質?》