Reddit月浏览量从百万扩容到十亿的陷阱和教训
英文原文:Reddit: Lessons Learned from Mistakes Made Scaling to 1 Billion Pageviews a Month
Reddit[1] 是一个社交新闻网站。用户可以将互联网上搜集或原创的图片或材料以帖子形式发布于网站上。而后其他用户可以投票,投票的结果将作为帖子排名的依据。
Reddit 网站的第一位领薪雇员杰里米·埃德伯格在 RAMP[2] 讨论会上做了一次出色的演讲 ,他教给我们很多关于如何创建一个成功的社交网站。杰里米使用一种美德和罪恶的方法,分享在扩展 Reddit 时的错误例子。事实证明,他们也做了很多好东西。不过有点令人吃惊的是,杰里米现在是 Netflix[3] 的可靠性架构师。所以我们在这篇文章中,也可免费得到一些 Netflix 的观点。
我完全认可的一些经验教训:
- 把 SSD[4] 看做是便宜的内存[5],而不是昂贵的硬盘。当 reddit 把数据库从旋转磁盘转移到 SSD 后,服务器数量从 12 个降低到 1 个,并且还有很多余量。SSD 虽贵了 4 倍,但是你会得到 16 倍的性能,这个花销值得。
- 给用户一点权力,看他们用来做什么,然后把好的东西转换成功能。对我最大的启示之一是 reddit 从它的用户学到了很多,网站能顺利运作,很大程度上依靠了用户。用户会告诉你很多你不知道事情。例如,reddit gold 在社区里以笑话开始,后来他们把它做成产品,并得到用户的喜爱。
- 没有必要从一开始就建立一个可扩展的架构。一开始时你不知道什么会是你的功能集,所以你也不知道你会有哪些扩展问题。随着你的网站增长,你可以了解哪里将是扩展问题。
- 把未登录用户当作二等公民。未登录的用户访问的缓存内容,Akamai[6] 抗住了着 reddit 的流量冲击。巨大的性能提升。
还有很多,这里是我谈话的注释,我们从早期扩展 reddit 的错误中学到许多经验教训:
数据统计
- 流量大约每 15 个月增加 1 倍。
- 上个月(8 月份),reddit 有来自 177 个不同国家的 73,293,644 名独立访客,查看了 4,885,611,148 个页面。在大约 10 亿次浏览量时结束了这次谈话。不清楚现在的架构有何不同。
- 28 名雇员。
- 每名雇员应对大约 240 万独立访客。(链接)
- 成千上万的志愿者版主
- 截至 2012 年,他们有 240 台服务器,支持每月 20 亿页面浏览量和 Postgres[7] 里的 2TB 数据。所有高流量的数据被移出 EBS[8],并上传至本地临时磁盘。
起源故事
- Reddit 始于 2005 年。他们带着通过文字来点餐的想法去了 Y Combinator[9],结果被拒绝了。回来跟保罗·格雷厄姆商讨,想建设互联网网页,这就是 reddit。那时他们并不知道 Digg[10]。
- 开始在数据中心,然后把功能部分转移到 EC2[11]。
- 最初在 2006 年开始使用 S3[12] 存储和供应标识。
- 2007 年为缩略图使用 S3。
- 2008 年使用 EC2 经由 V*N[13] 通道到数据中心进行批处理。
- 2009 年 EC2 用于整个网站。传输数据到 EC2 能让网站瘫痪一整天。稍后会谈到著名的数据重力例子。
EC2
- 迁移到 EC2 上的动机
- 堆叠机架不好玩。不想租用更多的机柜和购买更多的服务器。
- 增长过快的数据中心,在初期增长是不可预知的。
- 4 人一组的使用情况下成本是有效的。EC2 比在旧金山的数据中心便宜 29%。
- EC2 不是灵丹妙药。你要经受更高的网络延迟和嘈杂的邻居,所以计划好应对方案。好处是你可以按照你所需要的增长。
- 在 EC2 上跟踪资源限制
- 所有资源都有账户限制。
- 亚马逊甚至不知道他们的一些限制是什么。
- 跟踪限制,并在需要它们之前提出警示。
- 捕获异常去发现已达到异常。
架构
- Reddit 的架构很简单。用户连接到跟应用层对话的网络层。应用层跟 memcache[14],Cassandra[15],以及 Postgres 对话。Postgres 使用主从配置。批处理系统使用 Cassandra 和 Postgres。
- 相比之下,Netflix 使用面向服务的架构,组件间使用 REST[16] 应用程序接口相互交谈。
- 优点:更容易自动调节,因为只是服务有问题需要调节;更容易计划规模;更容易识别问题,因为它们在 REST 调用背后都是孤立的;缩小变动的影响;更有效的本地缓存。
- 缺点:需要多个开发团队或工作在多个服务上的开发者,因此你需要更多的人;需要一个共同的平台以防重复工作;对刚起步的小团队来说太多的间接支出。
- PostgreSQL 是一个出色数据库。它建立了一个美好的,真地很快的键值存储。
- 电子邮件是一个很难的问题。很难正确送达。从使用自己的电子邮件服务器开始,但是今天可能会去选择电子邮件服务提供商。
- 队列是个救世主。组件之间传递工作时,把它放到一个队列。你会得到一个不错的小缓冲区。(Reddit 使用 RabbitMQ[17] 作为消息队列。)
- 混合 HAProxy[18] 和 Nginx[19]。一些流量被引导到它们中的一个。在尝试 Niginx(遇到故障)后,负载均衡会选择 HAProxy。它进行 L7[20] 负载均衡。Nginx 仍被用来终止 SSL[21],并提供静态内容。
代码
- 框架。从开始使用一个基于 Python 架构的 Pylons[22](Django[23]太慢了)。Pylons 很容易上手,不过最终因为跟用例不匹配,失败了。对 Pylon 做了很大改动,结果最后使得它难以升级到新版本(现在修复了)。会将再次使用金字塔的(Pylons 的新名字)。
- 基于线程的事件?基于线程可以提前以排列大小,但大小可能是错误的。基于事件可以处理更多连接。但是当你碰壁时就只能碰壁。你想花更多时间来规划你得线程池大小,还是就突然碰壁?
- 开源很不错。Reddit 建立在开源基础上。不用为软件付钱很不错,特别是在起步阶段。
数据
- 数据是公司最重要的资产。非死book,Google 和 Flickr[24] 等公司建立在数据之上。
- 数据重力。你把数据放在将需要的地方,接近你的应用。思路是把所有你想要的应用围绕在数据周围。数据创建一个重力井,其他东西需要在它附近,因为数据是最难移动的。数据集越大就越难移动。目前移出 EC2 的成本太大了。这就是为什么 EC2 允许你免费导入数据,当你导出时向你收费。他们希望你把你所有的数据放在云中。
- 关系与非关系。Reddit 里的大部分数据是以键值方式存储在 Postgres。为了处理和更容易分析,一切涉及金钱交易的数据被保存在关系数据库。
- Postgres 很稳定。它坚如磐石,他们从未有过自身问题。如果他们有问题,那也是它周围事物的问题,例如用 Python 编写的应用系统。(所以)很难找到 Postgres 专家。
- Postgres 被选为键值存储,因为当时还木有 Cassandra。另外,Postgres 的速度非常快,而且现在原生地支持键值(KV)。
- 分区。写入被分割的四个主数据库:链接,帐户,subreddits[25],评论,投票,以及杂项。
- 每个都有从属。表决数据库有一个主数据库,一个从属数据库。注释数据库有一个主数据库和 12 个从属数据库。
- 如果可能的话避免从主数据库读取,而是直接从从属数据库读取,以保持主数据库专门进行写操作。
- 客户端库将在从属数据库之间进行负载平衡,如果一个从属数据库处于忙状态,则尝试新的一个。
- 写数据库访问层叫做“事情”。
- 这种方法工作了很长一段时间。分片相结合的数据库,读取从属,跟踪阅读从属的负载均衡性能。
- Cassandra。
- 快速写入,快速反查询,简单的增量可扩展性,无单点故障。
- 在 Netflix 数据被分布在三个不同的区域。所有数据的副本在所有三个区域。即使一个区域丢失了,它们仍然可以运行。
- 在 Cassandra,切换投票数据是 reddit 的一个巨大成功。Cassandra 的布隆过滤器(Bloom Filters[26])真正激活快速反查询。它能很快识别哪个评论你没有投票,所以否定的回答很快回来。(更多关于这个话题)
社交
- 2008年 reddit 是开源的
- 用户可以读取代码,得知他们没有篡改投票。
- 用户可以添加他们总是想添加的功能,reddit 会接受它。这个行不通,因为人们并不真的想写代码。
- 招聘。其他人知道这代码,所以更容易雇人。
- 蠕虫事件。有人想出了如何通过注入额外的 JavaScript 页面编写一个蠕虫病毒。它确实无意,但是失控了。在创始人之一结婚的当天,整个团队乘一架飞机从婚礼回来。但一个用户已经回应了一个补丁,将中止蠕虫蔓延。代码开源,让社区在危机时刻帮了忙。
Reddit 如何挣钱?
- 侧栏广告,自助式广告,商品,reddit gold,市场。
- 需要注意的是 reddit 是尚未盈利(链接)。这带来了一个问题,像 reddit 这样的网站,什么时候能在云端盈利?
- 还要注意的是,reddit 已不属于 Condé Nast[27] 了,所以它是独立的。(链接)
错误
- 没有考虑到迁移到 EC2 后增加的延迟。在数据中心,他们有亚毫秒级的机器之间访问,所以进行 1000 次调用来 memache 一个页面负载时可行的。在 EC2 上并非如此。 Memcache 访问时间增加了 10 倍到毫秒级,使他们的老办法也不用上了。修复方法就是批量调用以 Memcache 一个请求内如此大量的服务。
- 只是承诺。亚马逊并不总是兑现承诺,并围绕承诺工作。绕过故障,而不是试图解决这些问题的设计。 (这里没有提到,也许 EBS?)
- 在生产中使用尖端产品。Cassandra 仍在其开发早期就被使用。现在真的是出色,但那时它是有问题的。
- 本应该更早卸载很多工作给客户端。服务器做了很多的页面渲染,本应该交给客户端去做。 非死book 是这方面的大师。你得到一个有很多分区的矩形,API 被调用来填充所有分区。这就是他们起初所希望的 reddit。它本可以扩展得更好。它还有助于调试,因为很容易确定哪个 API 调用出了问题。
- 不具备足够的监控性,使用的监控系统的虚拟化不够友好。一开始用的是 Ganglia[28],倒是有很好的图形界面,但很难使用,而且变化太快。
- 数据没有过期期限。 你可以在 reddit 挖坟看早期的评论回复。他们已经开始限制,所以你不能给旧评论投票,或给旧帖添加评论。否则会导致数据随着时间的推移不断增长,使得在数据库保存热点数据的难度越来越大。
- 没有使用一致的哈希。当哈希到一个缓存,问题是如果你需要添加更多的缓存,你会被卡住,因为所有的数据是在一个或者许多你正在哈希的缓存。当增加缓存时你无法在此平衡。一致的哈希是一种解决这个问题的方法。迁移到 Cassandra 解决了它。
经验教训
- 扩展的关键是在你的用户之前找到瓶颈。
- 使用代理是扩展的巨大福音。用户可以根据他们击中的 URL 被路由。 Reddit 有一个系统,监控每个 URL 用多久得到服务。人们被放进不同的线路。慢流量去一个地方,快的去另一个。基于平均响应速度的流量分割是一个巨大的促进。
- 所有的事情自动化。如果你对待你的基础设施如同对待你的代码,你的生活会容易得多。一切都应该自动开启,并自动进行配置。
- 没有必要从一开始就建立一个可扩展的架构。一开始时你不知道什么会是你的功能集,所以你也不知道你有会有哪些扩展问题。随着你的网站增长,你可以了解哪里将是扩展问题。
- 刚起步时不要使用面向服务的架构。记住,当发展到中等规模时你可以去实现它;否则只会有太多的开销。
- 不要跟随潮流。有时候跟潮流是对的,例如 node.js。
- 给所有东西加个限制。给反复发生的事情设置一个上限,并根据需要提高或降低限制。如果超过限制,阻止用户以保护正常服务。例如为 subreddits 上传文件标识。用户想到了他们可以上传真正的大文件,这会损害系统。也不要接受巨大的文本。会有人 hi 想给你发送 5GB 的文本。
- 长远计划。在设计时总是假设将有一大堆你在做的。应用服务器,数据库,缓存。总是假定你打算从一开始有一个以上的。这将在未来更容易横向扩展。
- 用C重写 Python 函数。在 reddit 扩展中为获取速度,他们找出 Python 代码里最重复的函数,并用C重写。特别是过滤器,markdown 渲染,memcache 调用。Python 的好处是容易和高效地调用C。
- 尽可能保持无结构模式。这样的话,可以很容易地增加新的功能。你所要做的就是添加新的属性,而无需改变表格。
- 数据过期。锁定旧帖和创建一个完全渲染的页面并缓存它。这是如何应对有可能要淹没你的数据库的所有旧数据。同时,不要允许在旧的评论上投票,或给旧帖添加评论。用户很少会注意到。
- 把 SSD 当作便宜的内存,而不是昂贵的磁盘。 当 reddit 的数据库从旋转磁盘转到 SSD 时,服务器的数量从 12 个减少到 1 个,还有很大的余量。SSD 是贵了 4 倍,但你会得到 16 倍的性能,物有所值。在 Netflix 和 Reddit 上一些最大的 Cassandra 节点都是在 SSD 上,这作出了巨大的改善。
- 每个工具都有不同的使用情况。Memcache 没有保证持久性,但是非常快,所以投票数据存储在那里,以使渲染页面尽可能的快。Cassandra 持久,快速,并能提供快速的反查询,因为其布隆过滤器,所以它适合存储不在 memchche 里的持久投票数据副本。 Postgres 是坚如磐石而且是关系型的,所以这是一个很好的地方作为备份 Cassandra 投票(如果需要,Cassandra 中的所有数据可以从 Postgres 生成),也做批量处理,有时这需要关系的能力。
- 将未登录用户当作二等公民。未登录用户登占据约 80% 的流量,现在是接近 50%。总是给未登录用户缓存内容,Akamai 承受了 Reddit 流量的消耗。有了巨大的性能改进。附带的好处是如果 reddit 宕机,你不登录的话,你可能永远不会知道。
- 把一切都放入一个队列。投票,评论,创建缩略图,预计算查询,邮件处理和更正。队列通过监控队列长度允许你知道什么时候有一个问题。附带的好处是队列隐藏用户的问题,因为诸如投票请求的事情都在排队,如果它们不被立即应用无人注意。
- 在多个可用区保存数据。
- 避免在单一实例上保存状态。
- 得频繁快照 EBS 磁盘。
- 不要在实例上保存密钥。亚马逊现在服务向你提供实例键。
- 基于安全组分解功能。
- 提供 API。程序员将会在你的平台上做东西。例如,reddit 的 iPhone 应用程序,就是其他人用公开的 API 制作的。
- 在自己的社区活跃。Reddit 的用户喜欢 reddit 的管理员在自己网站上活跃,并与他们互动。
- 让用户为你工作。有用户输入的网站的问题总是有作弊、垃圾邮件和欺诈。Reddit 大部分管理的工作是由成千上万的志愿者来完成的,比如他们处理大多数的垃圾邮件问题。这种方式工作得非常好,是 reddit 的可以保持小团队的原因之一。
- 给用户一点权利,看他们用它做什么,把好东西变成功能。例如,当添加了给 subreddits 增加 CSS 的能力时,他们看到人们在做什么,增加了许多通用的东西作为大家的功能。这也使得用户能在 Reddit 上做东西而兴奋,因为他们喜欢那种操控感。有很多其他的例子。
- 倾听你的用户。用户会告诉你很多你不知道但是你可能想知道的东西。例如,reddit gold 在社区里以一个笑话开始。后来他们把它做成了产品,用户也很喜欢。
译注:
1. Reddit 是一家美国社交新闻网站 Reddit.com。
2. RAMP 是一个所有创业者在扩大经营规模前想要参加的讨论会。
3. Netflix 是一家美国公司,提供互联网随选流媒体播放、在线出租业务。
4. SSD 即 Solid State Disk 固态硬盘。
5. RAM 即 Random Access Memory 随机访问存储器。
6. Akamai 是一家美国内容分发网络(CDN)服务商。
7. Postgres 即 PostgreSQL, 是一个自由的对象-关系数据库服务器(数据库管理系统)。
8. EBS 即 exclusion basis system,动态密钥管理方法。
9. Y Combinator 是一家以投资种子阶段初创公司为业务的创投公司。
10. Digg 即“掘客”,或者“顶格”,美国公司,2012 年被纽约科技开发公司 Betaworks 收购。
11. EC2 即亚马逊弹性计算云(Elastic Compute Cloud),是一个让使用者可以租用云端电脑运行所需应用的系统。
12. S3 即亚马逊简易存储服务(Simple Storage Service),由亚马逊网络服务系统提供的在线存储服务。
13. V*N 即虚拟专用网络(Virtual Private Network),是在公用网络上建立专用网络的技术。
14. Memcache 是一个高性能的分布式的内存对象缓存系统。
15. Cassandra 是一套开源分布式 NoSQL 数据库系统。
16. REST 即表征状态转移(Representational State Transfer)是 Roy Fielding 博士在 2000 年博士论文中提出来的一种软件架构风格。
18. HAProxy 提供高可用性、负载均衡以及基于 TCP 和 HTTP 应用的代理。
19. Nginx 即 engine x,是一个高性能的 HTTP 和反向代理服务器。
21. SSL 即 Secure Sockets Layer 安全套接层,是为网络通信提供安全及数据完整性的一种安全协议。
22. Pylons 是一个开放源代码的 Web 应用框架,使用 python 语言编写。
23. Django 是一个开放源代码的 Web 应用框架,使用 python 语言编写。
25. Subreddit 是 reddit 上一个定制的子论坛。
26. Bloom Filter 即布隆过滤器,是一个很长的二进制向量和一系列随机映射函数。
27. Condé Nast 即康泰纳仕,是一个总部位于美国纽约市的国际期刊出版集团。