文档章节

支撑4.5亿活跃用户的WhatsApp架构概览

hmc0316
 hmc0316
发布于 2016/10/10 18:14
字数 5372
阅读 18
收藏 0

服务4.5亿用户的高可靠架构

信息源

需要注意的是, WhatsApp的整体架构并未公开,这里仅仅是从不同信息源中获取不同的片段。Rick Reed的讲座主要分享了使用Erlang实现单服务器200万连接数,虽然很有价值,但是并不是整个应用架构。

  • Rick Reed: 扩展到数百万并发连接数(2012, PPT)

  • Rick Reed: Erlang Factory(访谈)

  • Eugene Fooksman: WhatsApp的Erlang使用(访谈)

  • DLD14: 关于WhatsApp(Jan Koum和David Rowan)

  • Yowsup以前是WhatsApp的一个开源API,但是由于 弃用了DMCA当下已不可用,但是同样可以说明WhatsApp的一些内部工作机制。

  • 相关文章中列出的一些信息。

一、 统计

这些统计是当下系统的一些数据,更多针对数据存储、消息、meta-clustering以及新加入的BEAM/OTP补丁。

  • 4.5亿的活跃用户,并且是史上最快达到这个数字的公司

  • 32个工程师,平均每人支撑1400万活跃用户

  • 每天收发跨7个平台的500亿消息

  • 平均每天注册用户过百万

  • 0广告开销

  • 800万投资

  • 数百个节点

  • 8000+核心

  • 数百TB内存

  • 每秒Erlang消息超过7000万

  • 在2011年,WhatsApp单服务器取得 100万个tcp会话,同时还有内存和CPU剩余。在2012年,tcp会话发展到了200万。2013年WhatsApp 发表tweet声明,70亿消息入站,110亿消息出战,即每天处理180亿消息,伟大的2013!

二、 平台

后端

  • Erlang

  • FreeBSD

  • Yaws、lighttpd

  • PHP

  • BEAM定制补丁(BEAM类似于Java的JVM,但适用于Erlang)

  • 定制XMPP

前端

  • 7个客户端平台:iPhone、Android、Blackberry、Nokia Symbian 360、Nokia S40、Windows Phone和一个未知的

  • SQLite

三、 硬件

标准的面向用户服务器:

  • Dual Westmere Hex-core(24个逻辑CPU)

  • 100 GB RAM、SSD

  • Dual NIC(公共面向用户的网络、私有的后端 /分布)

四、 产品

  • 聚焦消息传递。连接来自世界各地的用户,忽视他们的地理位置,无需支付高额费用,创始人Jan Koum还经常提起1992年在世界各地与家里人联系是多么的难。

  • 隐私。由Jan Koum制定,消息不会在服务器上储存,聊天记录也不会储存,目的就是不去了解用户隐私。不会保存用户姓名及性别,聊天记录只存储在电话上。

五、通用

1. WhatsApp服务器基本上完全使用Erlang实现

  • 做后端消息路由的服务器系统使用Erlang实现

  • 值得炫耀的是,如此庞大数量的活跃用户只使用非常少的服务器来管理,团队一致认为这很大程度上归功于Erlang。

  • 值得注意的是,Facebook Chat就是在2009年使用Erlang开发,他们弃用Erlang的原因是难以招聘到优秀的程序员。

2. WhatsApp服务器最早从Ejabberd开始

  • Ejabberd是个非常出名的开源Jabber服务器,使用Erlang实现。

  • 最初选用它的原因是开放、广受开发者关注、易于开始以及Erlang在大型通信系统上的长期口碑。

  • 接下来的许多年一直从事Ejabberd的重写和修改,包括从XMPP转换到内部开发协议、调整代码库以及重设计一些核心组件,对Erlang VM做了大量的修改以获得高性能。

3. 为了应对每天500亿消息,工作重心被放到可靠系统的打造上,货币化对于我们来说还是件遥远的事情。

4. 系统的健康状况主要看队列的长度,每个节点上消息队列的长度都会被一直监控,超过预先设置的临界值则会发出提醒,多个警报发生则标志着系统进入了下一个瓶颈。

5. 通过上传图片、音频、视频到一个HTTP服务器上来发送多媒体消息,然后将链接与Base64编码的缩略图一起添加到内容(如果可用)。

6. 有些代码基本上每天都在变化,通常情况下是一天几次;当然,峰值期间必须避开的。Erlang非常适用于将修改或者是新功能添加到产品,热加载意味着无需重新启动就可以实现修改,错误可以很快的得到解决,同样通过热加载,系统变得更加松耦合,这可以让更新快速的发布。

7. WhatsApp使用了什么样的协议?WhatsApp服务器池使用了SSL Socket,在客户端重新连接对消息进行检索之前,所有消息都会在服务器上排队。消息的成功检索会发回给WhatsApp服务器,它将会被重新转发给原始发送者;一旦客户端成功接收这条消息,它就会在服务器存储中擦除。

8. WhatsApp注册程序的内部工作机制是什么样的?WhasApp依赖电话IMEI号码来建立用户名/密码,这点在最近已经修改。WhatsApp现在会让应用发送一个包含5位数Pin的一般请求,然后给这个电话号码发送一个SMS,这意味着WhatsApp客户端不再受限于某台手机。基于Pin的号码,应用会从WhatsApp请求一个唯一的键,这个键将作为未来的使用密码,这同样意味着在新的设备上注册后会无效原有设备上的键。

9. 在Android上使用了Google的推送服务。

10. 在Android上有更多的客户。与Android打交道更让大家愉快,开发者能够快速的基于一个特性构建原型,并以最短的时间推出,如果存在问题的话也可以快速修复,iOS则不行。

六、单服务器上200万连接数的探索

1. 虽然用户增长是喜闻乐见的,但是它同样意味着你得投入更多钱去购买硬件;同时,机器数量的增加也大幅增加了管理和运维复杂性。

2. 需要为流量的起伏做规划,例子就是西班牙的足球比赛和墨西哥的地震。这些现实世界中发生的大事件造成了非常高的流量峰值,因此需要有足够的剩余容量来应对流量高峰+突发事件,比如一场近期的足球比赛产生了当天35%的出站消息。

3. 初始的服务器负载是每个服务器20万并发连接。

  • 预期将会添加大量的服务器来维持用户增加。

  • 服务器会因为负载的爆发而宕机,网络及其它的故障也会发生。这时候需要做一些组件的解耦,这样一来可以添加容量以应对峰值。

  • 目标是单服务器支撑百万连接数,这个目标在只有20万连接数时已经制定。动态的容量规划以应对世界级事件、硬件故障及其它类型的小故障,系统需要足够的弹性去应对高使用率和故障。

七、用来增强可扩展性的工具和技术

1. 编写系统活动报告工具(wsar):

  • 记录整个系统状态,包括OS状态、硬件状态、BEAM状态。这是为了便于从其他系统获取状态信息,如虚拟内存。跟踪记录CPU利用率、系统整体利用率、用户时间、系统时间、中断时间、上下文切换、系统调用、traps、数据包发送和接收、所有进程队列中总消息数、繁忙的端口事件、通信速率、字节输入/输出、调度状态,垃圾回收状态等。

  • 最初一分钟运行一次,当系统运行变得困难时,时间段将降为1秒钟一次,因为一分钟无法运行的情况很少发生。了解所有系统运行情况需要非常细粒度的统计数据。

2. CPU(pmcstat)中的硬件性能计数器:

通过查看CPU时间占用百分比,可以了解正在执行的模拟器(emulator)周期时间。假如是16%,说明只有16%的时间执行模拟代码,所以即使你能消除所有Erlang代码的执行时间,也只能节省总运行时间16%,这意味着你应该将重点放在其他方面以提高系统的效率。

3. dtrace、 内核锁计数、fprof

  • Dtrace是主要用于调试,而不是提高性能。

  • 在FreeBSD上给BEAM打补丁加入CPU时间戳。

  • 写脚本创建所有进程的聚合视图,查看哪些程序一直在占用系统资源。

  • 最大的胜利是给模拟器启用锁计数。

4. 一些问题:

  • 早期发现很多时间花在了垃圾回收程序上,这个问题已经被解决了。

  • 发现一些网络堆栈的问题,后来堆栈被调走了。

  • 大多数问题是关于模拟器的锁冲突,主要体现在锁计数的输出上。

5. 度量

  • 综合的工作负载,这意味着从你自己的测试脚本中生成流量,这对极限规模下面向用户系统调优没有价值。

  • 对于用户表这样简单的接口效果不错,生成接入然后尽可能快地读取。

  • 假如在一台服务器只支持100万连接,那么整个系统将需要30台这样的主机去打开足够的IP端口,生成足够多的连接;然而,这么多的开销仅仅可以测试一台服务器。对于测试200万个连接的服务器需要用到60个主机,生成这样的规模真的很难。

  • 很难生成生产环境下的那种流量。在正常的工作量下还可以估算,但在现实中看到的那些网络事件、世界事件,这主要因为多平台上客户端的不同用户行为,而且不同国家之间也有差异。

  • Tee’d 工作负载

  • 采用正常生产环境流量,然后把它放到一个单独的系统中。

  • 这对系统非常有用,因为产生的副作用会受到限制。不想看到网络拥堵,或者对用户造成影响。

  • Erlang支持热加载,所以可以在完整生产负荷下产生想法、编译,在程序运行时加载变化,而且能即时看到变化的好坏。

  • 添加旋钮动态调节生产加载,观察它对性能的影响。观察特征输出,比如CPU使用率、VM 使用率、监听队列溢出并调节旋钮,看看系统会有怎样的反应。

  • 真正的生产负载

  • 最终测试。输入工作和输出工作都要测试。

  • 多次将服务器放入DNS中,使其得到正常情况两倍或三倍的流量。TTL事务会产生问题,因为客户端不会遵守DNS TTL,而且这里还会有延迟,因此无法快速做出反应以获得更多可以被处理的流量。

  • IPFW. 将一台服务器的流量转移给另一台,这样可以使主机的连接数达到理想的水平。内核如果因为有个Bug就奔溃是不行的。

    6. 结果

    • 开始时每个服务器有20万个并发连接。

    • 第一个瓶颈出现每台服务器42.5万个连接的时候。系统遇到了很多冲突,工作停止了。安装调度器检测有多少有用的任务被停止、睡眠,或回转了。在加载时,它开始遇到睡眠锁,整个系统只用35-45%的CPU利用率,但调度程序的CPU利用率却达到了95%。

    • 第一轮修复使连接数超过100万个。

    • VM利用率为76%,CPU利用率为73%,BEAM模拟器利用率为45%,与用户百分比很吻合,这是件好事,因为模拟器得和用户一样。

    • 通常CPU利用率并不是好的评估方法,因为可能由于调度程序使用CPU导致系统看起来很忙。

    • 一个月以后解决了瓶颈,每个服务器连接数达到200万个。

    • BEAM利用率为80%,与FreeBSD开始分页的情况接近。CPU利用率大致相同,有两倍的连接数。调度程序遇到了冲突,但运行得很好。

    • 看来测试可以暂停了,这时开始分析Erlang代码。

    • 最初每个连接有两个Erlang进程,消减为一个。

    • 用计时器完成一些工作。

    • 在每个服务器有280万连接时达到顶峰

    • 571k pkts/sec, >200k dist msgs/sec

    • 做一些内存优化,VM加载下降到70%。

    • 尝试过将连接数增加到300万,但没有成功。

    • 当系统遇到故障时,查看长消息队列(单个消息队列或消息队列总和)。

    • 将每个进程的消息队列统计添加到BEAM设备上。包括发送/接收了多少条消息以及发送/接收的速度。

    • 每10秒取样一次,可以看到一个进程有60万条消息,每15秒延迟出列4万条消息。预计完全出列时间是41秒。

      7. 一些发现:

      • Erlang + BEAM + 它们的补丁——可以具有接近线性的SMP可扩展性。在24路服务器上运行系统,CPU利用率达到85%,持续运行负载——它可以像这样运行一整天。

      • Erlang程序模型的证明。

      • 服务器使用的时间越长,其积累长时间运行连接就越多,但不是每个连接都很忙碌,其中大多数是闲置的,所以服务器使用时间越长能够处理的连接数也就越多。

      • 冲突是最大的问题。

      • Erlang代码中的一些修复可以减少BEAM的冲突问题。

      • 向BEAM添加一些补丁。

      • 分区负载工作不需要频繁跨处理器运行。

      • Time-of-day锁。每次从一个端口发送消息都会针对所有调度程序产生一个Time-of-day锁,这意味着所有的CPU都会遇到同一个锁。

      • 优化计数器的使用,移除bif计数器

      • 发现IO时间表算术增长。创建VM抖动使哈希表在不同的时间点重新分配,改进使用几何分配表。

      • 通过你已经打开的端口添加写入文件,以减少端口冲突。

      • Mseg分配是所有分配器冲突的交点,因此创建好每一个调度程序。

      • 获得一个连接时会有很多端口事务,设置选项降低昂贵的端口交互。

      • 当消息队列积压太多的话,垃圾回收会破坏系统稳定性。所以暂停 GC,直到队列收缩。

      • 避免一些不必要的麻烦。

      • 从FreeBSD 9移植一个TSE计时器到FreeBSD 8。读取计时器开销更小,快速时间,比读取芯片还要便宜。

      • 从FreeBSD 9移植igp网络驱动程序,因为多个队列会因为NIC锁定出问题。

      • 增加文件和套接字的数目。

      • Pmcstat显示很多时间被用来在网络堆栈中查找PCB,所以扩大哈希表让查询更快些。

      • BEAM补丁

      • 之前提到过的设备补丁。植入设备调度程序用来获取使用信息、信息队列统计信息、sleep数、发送率、消息数等。可以在Erlang代码中使用procinfo(任务管理)实现,但有100万的连接时,这一过程会变得非常慢。

      • 统计数据收集非常高效,所以它们可以在生产中运行。

      • 统计数据保持3个不同衰变间隔:1秒、10秒和100秒。允许随时观测发生的问题。

      • 让锁计数为更大的异步线程计数工作。

      • 为调试锁计数器添加调试选项。

      • 调试

      • 设置低调度程序的唤醒值,因为调度程序一旦进入睡眠就再也无法唤醒。

      • mseg分配器优于malloc。

      • 每个调度程序每个实例都有个分配器。

      • 配置大的carrier,而且还会越来越大。导致FreeBSD使用超级页,降低 TLB thrash比率,并为相同的CPU提高了吞吐量。

      • 以实时优先级运行BEAM,这样其他的东西比如cron作业就不会打断调度程序。防止小故障导致重要用户通信的阻塞。

      • 打补丁下调spin数,从而使调度程序不会spin。

      • Mnesia

      • 相比erlang:now,更喜欢os:timestamp。

      • 不使用事务,用远程的备份,并行复制每个表以提高吞吐量。

      • 事实上还对许多地方进行了修改。

          八、经验总结

          1. 优化是件非常艰辛的事情,也只有工程师去做。Rick在回顾大量的修改后(使每个服务器连接数达到200),更觉得头皮发麻。大量的工作包括编写工具、运行测试、增加补丁、把让人眼花缭乱的方法添加到堆栈的每一层、调试系统、寻找蛛丝马迹,每一个细节都不能放过,你需要努力让一切都在掌握之中。只有这样才能消除瓶颈,提高性能以及最大程度地实现可扩展性。

          2. 获取你需要的数据;编写工具;为工具添加补丁;添加调控旋钮。扩展系统获取更多数据是Ken不懈的追求,为了获取他们需要的数据,需要不停地编写工具、脚本来管理和优化系统。为了数据,不惜一切代价。

          3. 度量;消除瓶颈;测试;不断重复这样的过程。枯燥无聊,但你需要这样做。

          4. Erlang很给力!Erlang继续证明其作为一个多用途、可靠、高性能平台的优良品质。虽然Erlang也需要大量的调整和修补,这些工作难免会让人对Erlang产生质疑。

          5. 破解病毒式代码,获得利润。“病毒式”现在是优良品质的代名词,就像WhatsApp那样,只要你真得做到了,那意味着你得到了很多很多钱。

          6. 价值和员工数现在已经没有直接联系了。如今,员工的数量并不能说明什么。先进的世界级电信基础设施使WhatsApp这样的应用程序成为可能。如果WhatsApp还需要做网络或手机等设备,那可能根本就不会有WhatsApp这样的公司存在。功能强大、价格廉价的硬件和开源的软件也无疑使WhatsApp的成功事半功倍。换句话说WhatsApp的成功在于它在正确的地点、时间为正确的用户提供了正确的产品。

          7. 能够重视用户想法是很了不起的。WhatsApp 将自身定位成一个简单的消息传递应用,而不是游戏网络、广告网络或者已经面临消亡的照片网络,这一点很重要。这样的定位使他们没有在应用中添加广告,他们努力保持应用简单的同时添加新功能,傻瓜型操作方式使WhatsApp适用于每一个用户。

          8. 考虑到简单性,有一些限制是允许的。你的身份被绑定到电话号码,所以如果你更改了电话号码你的身份就失效了。这和一般的应用程序确实有点不太一样,但却使整个系统在设计上变得更加简单了。

          9. 年龄上的歧视。2009年,因为年龄歧视,WhatsApp创始人Brian Acton在Twitter和Facebook连一份工作都找不到,那就让它们后悔去吧。

          10. 先从简单的开始然后再深度定制。聊天刚推出时,服务器端基于jabberd,现在它已经被完全重写,但那个确实是Erlang方向上的第一步。Erlang初次使用时就体现出的可扩展性、可靠性和可操作性,这使得到了越来越广泛的应用。

          11. 保持低的服务器数量。努力让服务器尽可能的少,同时为短暂高峰期预留足够的上升空间。分析并优化直到达到收益递减点,然后再部署更多的硬件。

          12. 有目的地增加冗余服务器。这可以确保在公司放假时也能为用户提供不间断的服务,员工可以享受假期而不用花时间修复过载问题。

          13. 赚钱时也要考虑公司的成长。WhatsApp免费时成长是最快的,早期每天都有1万次的下载量。然后转向付费时,下载量下降至每天1000次。在年底增加了图片消息后,他们就把按下载次数付费改成了按年收费。

          14. 灵感总来自最意想不到的地方。忘记Skype用户名和密码的经历无疑给WhatsApp带来了灵感。

          © 著作权归作者所有

          hmc0316
          粉丝 1
          博文 49
          码字总数 55901
          作品 0
          台北
          程序员
          私信 提问
          WhatsApp爆安全漏洞,或被NSA利用

          IT经理网点评:Facebook收购WhatsApp近日成为业界的焦点话题,争论的焦点是WhatsApp到底值不值190亿美元,但是人们忽略了一点,作为拥有4.5亿活跃用户的创业公司,WhatsApp具有快速发展的创业...

          Cashcow
          2014/02/24
          0
          0
          为什么我要选择erlang+go进行服务器架构

          服务器非业余研究http://blog.csdn.net/erlib 作者Sunface 估计很多同学看到这里都会觉得迷惑,go的大名已经如雷贯耳了,但是erlang?这个东东是神马?难道是编程语言?怎么从来没听说过。 ...

          robslove
          2015/02/23
          546
          1
          Facebook创始人扎克伯格长文阐述战略转移区块链,暂放弃中国市场

          来源:区块链世界 昨天,FB的CEO小扎发一口气发了3200字的长文阐述FB将会战略转移的事情。看到最后,微信们可以松一口气了,Facebook放弃中国市场。 Facebook的社交媒体战略“由城市的数字广...

          来源:
          03/08
          0
          0
          USDT再度“暴雷”,带来市场短期回暖假象。

          继18年10月15号之后,2019年4月26号再度”暴雷”,Bitfinex交易所和稳定币发行公司Tether存在“内幕交易”,被纽约州总检察长起诉欺诈行为,大概的情况是Bitfinex出现了8.5亿美金的亏损。随后...

          第九区情报局
          04/27
          0
          0
          BTC短期仍陷无序震荡,让我们放大周期拨开迷雾见趋势!

          “第一条:保住本金最重要。第二条:永远不要忘记第一条” ————沃伦·巴菲特 今日闲谈:全球最大的社交软件facebook正在布局它的加密货币世界,准备在今年上半年发行一款“数字货币”。深...

          K线中有杀气
          03/08
          0
          0

          没有更多内容

          加载失败,请刷新页面

          加载更多

          Replugin借助“UI进程”来快速释放Dex

          public static boolean preload(PluginInfo pi) { if (pi == null) { return false; } // 借助“UI进程”来快速释放Dex(见PluginFastInstallProviderProxy的说明) return PluginFastInsta......

          Gemini-Lin
          46分钟前
          4
          0
          Hibernate 5 的模块/包(modules/artifacts)

          Hibernate 的功能被拆分成一系列的模块/包(modules/artifacts),其目的是为了对依赖进行独立(模块化)。 模块名称 说明 hibernate-core 这个是 Hibernate 的主要(main (core))模块。定义...

          honeymoose
          今天
          4
          0
          CSS--属性

          一、溢出 当内容多,元素区域小的时候,就会产生溢出效果,默认是纵向溢出 横向溢出:在内容和容器之间再套一层容器,并且内部容器要比外部容器宽 属性:overflow/overflow-x/overflow-y 取值...

          wytao1995
          今天
          4
          0
          精华帖

          第一章 jQuery简介 jQuery是一个JavaScript库 jQuery具备简洁的语法和跨平台的兼容性 简化了JavaScript的操作。 在页面中引入jQuery jQuery是一个JavaScript脚本库,不需要特别的安装,只需要...

          流川偑
          今天
          7
          0
          语音对话英语翻译在线翻译成中文哪个方法好用

          想要进行将中文翻译成英文,或者将英文翻译成中文的操作,其实有一个非常简单的工具就能够帮助完成将语音进行翻译转换的软件。 在应用市场或者百度手机助手等各大应用渠道里面就能够找到一款...

          401恶户
          今天
          3
          0

          没有更多内容

          加载失败,请刷新页面

          加载更多

          返回顶部
          顶部