设计 Facebook 聊天功能

原文:Design Facebook Chat Function

译者:飞龙

协议:CC BY-NC-SA 4.0

自豪地采用谷歌翻译

准备系统设计面试的最有趣的部分之一,就是你可以了解很多如何构建现有系统的细节。

为了使每周的博文更有帮助,我想涵盖广泛的主题。我们一直在谈论推荐这样的东西,在过去的几周里排名很高,这次我想要介绍一些不同的东西。

问题

我们从一个非常简单的问题开始 - 如何设计 Facebook 聊天功能?

Facebook 花 $19B 购买了 Whatsapp,而 Facebook Messenger 最近真的很受欢迎,聊天功能绝对是一个热门话题。所以在这篇文章中,我很乐意谈论它。

这里提到几件事情。首先,正如我在之前的文章中提到的,系统设计面试可能非常多样化。这主要取决于面试官决定讨论哪个方向。因此,即使在相同的问题上,不同的面试官也可能有完全不同的讨论,你不应该期望这篇文章是一个标准答案。

另外,我从来没有在 Facebook Messenger 或 Whatsapp 中工作过。所有的讨论都基于 Gainlo 团队的分析。

基础设施

如前所述,最好有一个概要解决方案,并谈论整体的基础设施。如果你之前没有消息应用的经验,你可能会发现想出一个基本的解决方案并不容易。但是这完全没问题。让我们想出一个非常朴素的解决方案,并在稍后进行优化。

基本上,构建消息应用最常用的方法之一,就是拥有一个聊天服务器,作为整个系统的核心。消息到达时,不会直接发送给接收者。相反,它会转给聊天服务器并先存储在那里。然后,根据接收者的状态,服务器可以立即向他发送消息或发送推送通知。

更详细的流程如下所示:

  • 用户 A 想要向用户 B 发送消息Hello Gainlo。首先将消息发送到聊天服务器。
  • 聊天服务器收到该消息,并将确认发送回 A,表示收到该消息。根据该产品,前端可能会在 A 的用户界面中显示单复选标记。
  • 情况1:如果 B 在线并连接到聊天服务器,那很好。聊天服务器只是将消息发送给 B.
  • 情况2:如果 B 不在线,则聊天服务器向 B 发送推送通知。
  • B 收到该消息,并向聊天服务器发回确认。
  • 聊天服务器通知 A,B 接收到消息,并在 A 的用户界面中使用双复选标记进行更新。

实时

一旦达到一定的水平,整个系统可能开销大而低效。那么我们可以通过什么方式来优化系统,以便支持大量的并发请求?

有很多方法。这里一个显而易见的开销就是,当向接收者传递消息时,聊天服务器可能需要产生 OS 进程/线程,最后初始化 HTTP(可能是其他协议)请求并关闭连接。事实上,每个消息都会发生这种情况。即使我们采取相反的方式,接收者一直请求服务器来检查是否有新消息,但仍然开销很大。

一个解决方案是使用 HTTP 长连接。简而言之,接收者可以通过长连接发出 HTTP GET 请求,直到聊天服务器返回任何数据才会返回。每个请求将在超时或中断时重新建立。这种方法在响应时间,吞吐量和开销方面有很多优势。

如果你想了解 HTTP 长连接的更多信息,你可以查看 BOSH。

在线通知

Facebook 聊天的另一个很酷的功能是显示在线的朋友。虽然这个功能乍一看似乎很简单,但它极大地改善了用户体验,绝对值得讨论。如果你被要求设计这个功能,你会怎么做?

显然,最简单的方法是,一旦用户在线,他会向所有的朋友发送通知。但是,如何评估这个开销?

在高峰时段,我们大致需要O(平均朋友数*峰值用户数)的请求,这在有数百万用户的情况下可能会很多。而这个开销甚至可能比信息开销本身更高。改进它的一个想法是,减少不必要的请求。例如,只有当这个用户重新加载页面或发送消息时,我们才发出通知。换句话说,我们可以将范围限制为“非常活跃的用户”。或者,用户已经在线五分钟之前,我们不会发送通知。这解决了用户显示在线并立即离开的情况。

总结

还有很多其他的话题,我都没有在这篇文章中讨论,例如,如果你深入了解网络,我们可以讨论在连接中可以使用什么网络协议。另外,如何处理系统错误和复制数据也可以是有趣的,因为聊天应用是完全不同的。

如果你想和我进一步讨论,请随时留下评论。