最近在 Facebook 工程师博客上,软件工程师 Eugene Letuchy 写了一篇关于 Facebook Chat 项目的决策细节的文章。
当产品的客户有可能在一夜之间从零增加到七千万的时候,可扩展性就变为从一开始就必须考虑的问题。
Eugene 在文中指出了面临如此庞大的客户群会遇到的一系列挑战。首先的挑战是:
在用户上线或者下线时通知其所有好友的做法是非常幼稚可笑的,这么做的代价是 O(平均好友个数×高峰期用户数×上下线频率) 条短信 / 秒, 上下线频率是指用户平均每秒上线和下线的次数。当每个用户好友的平均数量大约在几百个,高峰期同时在线用户数在百万数量级的时候,这种实现方法的效率简直低得无法忍受。
另外一个挑战是实时消息的发送。Facebook 采用的是客户端直接从服务器将新消息“拉”的方式,跟 Comet 的 XHR 长时间轮询 (Comet’s XHR Long Polling) 过程比较相似。
Facebook 的页面会加载一个 iframe 用于用户间消息的传递, 这个 iframe 中的 Javascript 代码发出一个 HTTP GET 请求,这个请求将建立与服务器的一个持久连接,直到有消息返回给用户为止。
Eugene 接着又提到了“大量长时间的同步请求使得 LAMP 组合中 Apache 这一部分成为不确定的实现因素”。在在集群和分区子系统上,Facebook 选择了 C++ 和 Erlang 的组合。C++ 模块用户用于记录聊天信息,而 Erlang 模块“将在线用户的对话保存在内存中并且对长时间轮询 (long-polled) 请求提供支持”。epoll,Linux 2.6 中出现的新系统调用,被用于驱动 Erlang 模块。Eugene 解释了决定选用 Erlang 的原因:
简单的说就是因为 Erlang 能很好地满足我们的要求。Erlang 是一种面向同步的函数式语言,它具有极其轻量级的用户空间“进程”,无共享的消息传递语义,内置的分布式系统和一个被二十多年实时软件系统实践所检验过的灾难恢复系统。
用于“跨语言可扩展服务部署”的开源框架 Thrift (Facebook 在去年愚人节发布)被用来将 Facebook Chat 中用到的各种技术结合起来,其中就包括 Erlang 的功能绑定。
启动这项服务的方式也比较有意思——利用所谓的“摸黑启动 (dark launch)”
一夜间就将客户数由零变为七千万的秘密就在于避免一步到位地完成这个过程。我们会首先模拟很多用户访问的场景,这是通过一个叫做“摸黑启动”的阶段实现的. 在这个阶段中 Facebook 的页面会在没有任何 UI 元素的情况下连接聊天服务器,询问在线信息和模拟信息发送过程。
Facebook 选用 Erlang 是对此语言认可和肯定,具有重大意义。Erlang 的资深布道使 Yariv Sadan 感慨道:
人们长久以来都认为 Erlang 只是一个构建可扩展实时应用程序的平台,Facebook 选用 Erlang 应该能消除人们这一偏见。
查看英文原文: Facebook Chat Architecture
评论