有朋友问:数据库
以微信为例,能够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,颠覆了分层架构的本质?》