System Design [youtube搬运] Whatsapp 笔记

邵浩大
2023-12-01

原视频链接

https://www.youtube.com/watch?v=vvhC64hQZMk

 

Whatsapp是基于chat的APP,了解了Whatsapp的design有助于了解其他所有聊天类APP的design。Whatsapp比较重要的两个功能是1) group chatting,2) read reciepts。Whatsapp也有其他一些功能。

本视频提到的主要有以下features。

1) group messaging, 群聊,可支持200人的群聊

2) sent + delievered + read reciepts, 发的信息处于的状态是已发送,发送成功,还是已读

3) online/ last seen,是否在线,上一次上线是什么时候

4) image sharing,几乎所有的chat app 都应该支持图片分享的功能

5) chats are temporary / permant,如果用户删除了APP,聊天记录是被用久的删除还是保留在server

6) one-to-one chat,一对一聊天

以上的features,image sharing已经在tinder的system design里提到过了 (在tinder笔记里的 store profile的部分https://blog.csdn.net/lauraliu123/article/details/106169112),本视频就不再提了。

 

接下来是对其余feature的说明。

1)one-to-one chat

  假设用户A想向用户B发信息,按照Tinder里面的设计用户A不会直接和任何service通信,A只能把信息发给gateway 1。由gateway 1来转发给内部的服务,再由内部的服务转发给B所在的gateway 2,这个gateway再转发给B这条信息。

  为了能处理one-to-one chat,需要decouple出来一个单独的session mircoservice。这个micro service 需要有保存有哪个用户连接到哪个gateway的数据表的数据库,也需要有保存message(from A to B)的数据库,这个数据库能对信息所处的已发送,成功发送,已读的状态进行保存,以及对消息保存,保证消息在传输的途中失败了能重传保证一定传到。

  在gateway到用户,和session microservice到gateway的过程中,不能使用像http那样的Client-Server protocol,因为这样消息没法实时的从用户B经过gate way,session service传回A,只能等server的定期刷新。所以一个比较好的选择是用基于TCP的web socket。因为web socket允许peer to peer 传输,这样就能实现用户A和用户B之间的实时传输了。

  用户A向用户B发消息,只要A的消息到达session service,那么就算已经sent,已发送,因为session service 会保证一定将信息传给B,那么B在确认收到后回复session service,此时才算消息delievered,即消息成功送达,当B读了消息告知session service,就算消息已读了。

 

2) online/ last seen

当另一个用户B想查看用户A的上一次在线时间,B需要想service 端进行询问,为了实现这个功能,又decouple出来一个新的service - last seen service,这个service保存了所有用户acticity的时间log,就跟绝这个时间的log来决定用户上一次在线的时间。

  假设一个用户上一个活动是3秒前(时间很短,基本等于用户当前还在线),那么可以选择不显示是上一次在线时间而是现实用户当前在线,这个时间长短可以自定义。

  另一个可能需要考虑的问题是activity到底是真的用户行为向gateway发的请求,还是APP在后台做的更新而向gateway发送的请求,用户的APP应该能比较准确的判定只有真的用户activity才能存入last seen service的数据中。

 

3) group messaging

loader balancer, heatbeat 有关的一些service, profile service, image service, email service, SMS service 在本视频中都跳过。

  将谁在哪个group的信息单独存储在一个group service 上,这样也是decouple system,避免session service 的负荷过重。当某个用户在用户组中发了消息,那么这个消息先通过gateway传到session service,session service 从group service 中获取这个群所有其他的用户,再将消息通过gateway转发到所有其他用户的设备上。如果一个群的用户太多就不太好,因为session service 可能会不停地需要将消息实时转发几百遍甚至更多,所以群聊的人数一般有限制。

  因为会有很多的用户连接在gateway上,gateway本身处理web socket的负荷就很重了,应该将一些检查request是否授权,处理不同的协议下的message type的这些责任从gateway中剥离出来,那么一个办法是将没有任何处理(unparsed)的用户message直接传给session service,另一个更好的做法是将unparsed message传给一个parser mircoservice,在这个microservice上对消息进行parse,进行一些授权认证。

  在gourp service上,会存有数据表包括group ID对应的user ID。这个service可能包含多个服务器,意味着group的数据会分别存在不同的机器上,为了避免某一些机器存有过量的数据,而另一些机器上数据较少,一个可以balance load的方法是使用基于group ID的 consistent hashing。

  一旦某条信息传输失败了,session service 会retry 至传输成功。实现这个retry的一个技术叫message queue。一个message queue可以保证一旦message进入message queue,这个message一定会被成功传输。如果message queue也retry 失败了,这个message queue会通过group service找到这个group,然后再通过session service,接着gateway向这个群里发送信息的用户发送无法传递此信息。

  group reciept,就是群消息的已发送,发送成功,已读状态的显示成本很高,因为需要得到所有群成员的回复,一般很多chat app 也选择不实现这个消息。

  goup messaging需要保持的几个特点包括1)Retrial;2)Imdempotency;3)Ordering。

 

  视频里的system design很resilient,可以说是相对完整,当然还有一些具体的trick在真正做messging的时候才会知道的更多。

  Facebook messaging 有一个比较有意思的是deprioritizing feature。比如在新年的时候大家都会发祝福,这个时候上面提到的feature 比如last seen/ online,比如read recipiet,信息已读,已发送之类的状态这样的功能可以放在用户之间chat的功能之后,这个时候保证信息被顺利及时地传达更重要。

  

 

 类似资料: