2.设计微信,Facebook messenger

系统的要求和目标

功能需求

支持1对1聊天

支持离线在线状态

支持永久存储聊天记录

非功能需求

实时聊天体验,延迟越小越好

高度一致,相同的聊天信息在USER的DEVICE上

可以容忍稍微低一点的可用为了一致性

拓展需求

群聊

推送通知

容量估计

500M DAU, 一个用户一天发40条微信。
20 B 消息每天。
QPS 大概在 20 B/100K = 0.2m = 200K
假设每条消息100B。 2T 每天

五年需要 3.6 P的存储


image.png

服务

image.png

用户A通过聊天服务器向用户B发送消息。

服务器接收消息并向用户A发送确认。

服务器将消息存储在其数据库中,并将消息发送给User-B。

用户B接收消息并将确认发送到服务器。

服务器通知用户A该消息已成功传递给用户B。

image.png

image.png

存储

自然我们会需要一个MESSAGE TABLE,用来存储用户发送的每一条信息。随后我们为了构建一个1对1的会话,我们需要一个THREAD TABLE。
Message 表有,message_id, from_user,content,created_at,thread_id
Thread 表有, Thread_id, participants, created_at,updated_at,owner_id,is_muted


image.png

这里MESSAGE TABLE,像LOG一样,可以用NOSQL直接来存。
使用像HBase这样的宽列数据库解决方案可以轻松满足我们的两个要求。 HBase是一个面向列的键值NoSQL数据库,可以将一个键的多个值存储到多个列中。 HBase以Google的BigTable为模型,运行在Hadoop分布式文件系统(HDFS)之上。 HBase将数据组合在一起以将新数据存储在内存缓冲区中,一旦缓冲区已满,它就会将数据转储到磁盘。这种存储方式不仅可以帮助快速存储大量小数据,还可以通过密钥或扫描范围获取行的行。 HBase也是一个存储可变大小数据的高效数据库,这也是我们服务所需要的。

THREAD TABLE,需要按照更新时间(updated_at)排序,同时需要对OWNER_ID+THREAD_ID来做PK。所以可以用SQL。

如何重试失败的请求?
比如用户发送一条消息,判断有没有收到服务器的ACK。因此,我们可以告诉用户这条消息未能发送过去,让他们选择是否重试。
只有当ACK的MESSAGE 才会被存入DB。

管理用户状态

每当客户启动应用程序时,它都可以将朋友列表中所有用户的当前状态拉出。(每当用户向另一个离线用户发送消息时,我们都可以向发件人发送失败消息并更新客户端上的状态。)

每当用户上线时,服务器总是可以延迟几秒钟来广播该状态,以查看用户是否没有立即下线。

客户端可以从服务器获取有关用户视口中显示的用户的状态。这不应该是一个频繁的操作,因为服务器正在广播用户的在线状态,我们可以暂时处理用户的陈旧离线状态。

每当客户端与另一个用户开始新的聊天时,我们就可以在那时提取状态。

用户定期去拿新的好友在线离线状态。

数据分区

Thread_id 基于USERID 分区
基于UserID的分区:假设我们基于UserID的哈希进行分区,这样我们就可以将用户的所有消息保存在同一个数据库中。

MESSAGE 可以基于THREAD_ID来分区。

实时方案

用WEB SOCKET
有人一发送消息,服务器就可以进行推送。
断开连接后,用户如何接受消息
可以通过下次上线的PULL 或者IOS NOTIFICATION
这里要引进一个PUSH SERVER。
当用户上线时,首先问WEB SERVER 要一个PUSH SERVER的IP。随后和PUSH SERVER注册一个WEB SOCKET的双向连接。
之后用户B发给A消息,会先发给WEB SERVER,WEBSERVER知道A在哪个PUSH SERVER,把消息转发过去。


image.png

Q: WebSocket 和Socket 是什么联系和区别?
A: Socket 是很早就有的技术,Web Socket 是在H5 之后才诞生的技术,专门用于让浏览器支持被服务器推送信息所用。Socket 是更通用和强大的可以在任何地方使用的。WebSocket 只在浏览器上使用。

Q: 如果Push Server 宕机了怎么办?用户还收得到信息么?
A: 因为Socket 是一个双向连接,如果Push Server 宕机了,Client 端是知道链接已经断开了的,因此Client 端上只需要有一个backup 的逻辑,让client fallback 到每隔10s 拉一次数据的poll 机制就可以了。

群聊支持

群聊的问题主要是,有一些人没上线。如果所有人都在线,其实就是你发了一条消息,我就再向这个群的另外所有人都发送。
如果有很多人不在线的时候,WEB SERVER就会往PUSH SERVER空发很多信息。
让费了资源。

这里我们再引入一个CHANNEL SERVICE。当用户上线了,就订阅到每一个THREAD_ID(群聊的) 对应的CHANNEL SERVICE。 当用户下线,PUSH SERVER 会把这个用户从那些CHANEL 上移除。
这样MESSAGE SERVICE(web server)就只要向CHANEL SERVICE发信息。
CHANNEL SERVICE向当前在线的用户发消息给PUSH SERVICE。

Q: Channel Service 中的数据是什么结构?
A: key-value 的结构。key 为channel name,可以是一个字符串比如“#personal::user_1”。value是一个
set 代表哪些人订阅到了这个channel 下。

Q: Channel Service 用什么数据存储?
A: 根据上面所提到的key-value 结构以及value 需要是一个set,Redis 是一个很好的选择。

Q: 如何知道一个用户该订阅到哪些Channels?
A: 首先用户需要订阅自己的personal channel,如#personal::user_1,与该用户有关的私聊信息都在这个channel 里发送。小于一定人数的群聊可以依然通过personal channel 推送,超过一定人数的群聊,
可以采用lazy subscribe 的方式,在用户打开APP 且群处于比较靠前的位置的时候才订阅,用户没有主动订阅的群聊靠Poll 的模式获取最新消息。

Q: 用户关闭APP 以后还能收到提醒么?
A: 如果真的关闭了APP 是不行的。所以很多APP 会常驻后台,保证至少Poll 模式还能工作即可。

容错

聊天服务器出现故障会发生什么? 我们的聊天服务器与用户保持着联系。 如果服务器出现故障,我们是否应该设计一种机制将这些连接转移到其他服务器? 将TCP连接故障转移到其他服务器非常困难; 更简单的方法是让客户端在连接丢失时自动重新连接。

我们应该存储多个用户消息副本吗? 我们不能只有一个用户数据副本,因为如果持有数据的服务器崩溃或永久停机,我们没有任何恢复该数据的机制。 为此,我们必须在不同的服务器上存储多个数据副本,或者使用Reed-Solomon编码等技术来分发和复制它。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容