Pinterest正经历了指数级曲线般的增长,每隔一个半月翻翻。在这两年里,Pinterest,从 每月PV量0增长到10亿,从两名成立者和一个工程师成长为四十个工程师,从一台MySQL 服务器增长到180台Web 服务器(Web Engine),240台接口服务器(API Engine), 88台MySQL 数据库 (cc2.8xlarge) ,并且每台DB有一个备份服务器,110台Redis 实例服务(Redis Instance),200台 Memcache 实例服务(Memcache Instance)。
令人叹为观止的增长。想一探Pinterest的传奇吗?我们请来了Pinterest的两位创立者Yashwanth Nelapati 和 Marty Weiner,他们将以 Scaling Pinterest为题讲述关于Pinterest架构的充满戏剧化的传奇故事。他们说如果能在一年半前飞速发展时能看到有人做类似题材的演讲的话,他们就会有更多的选择,以避免自己在这一年半里做出的很多错误的决定。
这是一个很不错的演讲,充满了令人惊讶的细节。同时这个演讲也是很务实的,归根结底,它带来了可让大家选择的策略。极度推荐!
这篇演讲中有两个我最为看重的经验:
1.强大的架构在处理增长时通过简单增加相同的东西(服务器)来应对,同时还能保证系统的正确性。当遇到某种(性能)问题时,你想通过砸钱来扩容指的是你可以简单增加服务器(boxes)。如果你的架构能够做到这一点,那它就如金子一般强大而珍贵!
2. 当某些(性能问题)快到极限时大多数技术都会以他们自己的方式失败。这导致他们在审核工具时要考虑以下一些特性:成熟,好且简单,有名气且用的人多,良好的支持,持续的优异性能,很少失败,开源。按照这样的标准,他们选择了:MySQL, Solr, Memcache, and Redis,放弃了Cassandra ,Mongo。
这两点经验是相互联系的。遵循(2)中提到的标准的工具可以在扩容时简单增加服务器(boxes).当负载增加了,成熟的产品更少会有问题。当你遇到问题时,你至少希望它的社区团队能够帮助解决。当你使用的工具过于技巧化和过于讲究时,你会发现你遇到一堵无法逾越的墙。
在这段演讲里,碎片化(sharding)优于集群(clusterting)的观点是我认为最好的一部分。为了应对增长,通过增加资源,更少失败的模式,成熟,简单,良好的支持,最终圆满完成。请注意他们选择的工具以sharding的方式增长,而不是clustering。关于他们为什么选择sharding和他们如何做sharding是很有趣的事,这很可能触及到你以前未考虑过的场景。
现在,让我们看看Pinterest如何扩容:
(本段有些术语黑话不是很明白,望纠错)
基本概念
- Pins是一幅关于其他信息的集合的图片,描述了为什么它对于用户来说很重要,可以链回到他们发现它的地方。
- Pinterest是一个社交网络。你可以追踪人或者板报(boards).
- Database:它包含了拥有pins的板报(boards)和拥有板报(boards)的人 ,可以追踪或重新建立(repin)联系,还包含认证信息。
启动于2010年三月--自我发现时期
此时此刻,你甚至不知道你在做的这个产品将要做什么。你有想法,迭代开发更新产品的频率很高。最终因遇到一些在现实生活中永远不会遇到的奇怪的简短的MySQL查询而结束。
早期的一些数字:
- 两个创始人
- 一个工程师
- Rackspace托管服务器
- 一个小型web引擎
- 一个小型MySQL数据库
011年1月
扔在潜伏前进中,产品得到了一些用户反馈。以下是数据:
- Amazon EC2 + S3 + CloudFront云服务
- 一台NGinX,4台Web 引擎(作冗余用,不是真正为了负载)
- 一台MySQL数据库+一台读备份服务器(防止主服务器宕机)
- 一个任务队列+两个任务处理
- 一台MongoDB(为了计数)
- 两个工程师
至2011年9月--试运行阶段
每一个半月翻翻的疯狂增长阶段。
- 当高速发展时每个晚上每个星期都会有技术失败的情况发生
- 这时,你阅读大量白皮书,它会告诉你把这个增加进来就行了。当他们添加了大量技术时,毫无例外都失败了。
- 最终你得到一个极为复杂的架构图:
- Amazon EC2 + S3 + CloudFront
- 2NGinX, 16 Web Engines + 2 API Engines
- 5 Functionally Sharged MySQL DB + 9 读备份
- 4 Cassandra 节点
- 15 Membase 节点(分成三个单独的集群)
- 8 Memcache 节点
- 10 Redis 节点
- 3 任务路由(Task Routers)+ 4 Task Processors
- 4 ElasticSearch 节点
- 3 Mongo集群
- 3名工程师
- 5种主要的数据库技术只为了应付他们自己的数据
- 增长极快以至MySQL负载很高,而其他一些技术都快到达极限
- 当你把某些技术的应用推至极限时,他们又以自己的方式宣告失败。
- 放弃一些技术并问它们到底能做什么。对每一件事情重新构架,海量工作量。
架构成熟 2012 1月
重新设计的系统架构如下:
- Amazon EC2 + S3 + Akamai, ELB
- 90 Web Engines + 50 API Engines
- 66 MySQL DBs (m1.xlarge) + 1 slave each
- 59 Redis Instances
- 51 Memcache Instances
- 1 Redis Task Manager + 25 Task Processors
- Sharded Solr
- 6 Engineers .使用Mysql,Redis,Memcache Solr,他们的优势是简单高效并且是成熟的技术。 随着Web流量增加,Iphone的流量也随之开始越来越大。
稳定期 2012 10月 12 仅仅在一月份以后,大概就有4倍的流量增长。 系统架构数据如下: The numbers now looks like:- Amazon EC2 + S3 + Edge Cast,Akamai, Level 3
- 180 Web Engines + 240 API Engines
- 88 MySQL DBs (cc2.8xlarge) + 1 slave each
- 110 Redis Instances
- 200 Memcache Instances
- 4 Redis Task Manager + 80 Task Processors
- Sharded Solr
- 40 Engineers (and growing)
注意到,此时的架构应该是合理的,只是通过增加更多的服务器。你认为此时通过更多的投入来应对这么大的规模的流量,投入更多的硬件来解决这个问题, 下一步 迁移到SSDs
ajavaloser
|
Solr
- 只需要几分钟的安装时间,就可以投入使用
- 不能扩展到多于一台的机器上(最新版本并非如此)
- 尝试弹性搜索,但是以Pinterest的规模来说,可能会因为零碎文件和查询太多而产生问题。
- 选择使用Websolr,但是Pinterest拥有搜索团队,将来可能会开发自己的版本。
集群vs.分片
- 在迅速扩展的过程中,Pinterest认识到每次负载的增加,都需要均匀的传播他们的数据。
- 针对问题先确定解决方案的范围,他们选择的范围是集群和分片之间的一系列解决方案。
分片(sharding) - 全凭人手
- 裁决: 分片是赢家。我觉得他们分片的方案与Flicker非常相似。
- 特点:
- 如果去掉集群方式下所有不好的特点,就得到了分片。
- 人工对数据进行分布。
- 不移动数据。
- 通过切分数据来分担负荷。
- 节点不知道其它节点的存在。某些主节点控制一切。
- 优点:
- 可以通过切分数据库来扩大容量。
- 在空间上分布数据。
- 高可用。
- 负载均衡。
- 放置数据的算法十分简单。这是最主要的原因。虽然存在单点(SPOF),但只是很小的一段代码,而不是复杂到爆的集群管理器。过了第一天就知道有没有问题。
- ID的生成很简单。
- 缺点:
- 无法执行大多数连接。
- 没有事务功能。可能会出现写入某个数据库失败、而写入其它库成功的情况。
- 许多约束只能转移到应用层实现。
- schema的修改需要更多的规划。
- 如果要出报表,必须在所有分片上分别执行查询,然后自己把结果合起来。
- 连接只能转移到应用层实现。
- 应用必须应付以上所有的问题。
何时选择分片?
- 当有几TB的数据时,应该尽快分片。
- 当Pin表行数达到几十亿,索引超出内存容量,被交换到磁盘时。
- 他们选出一个最大的表,放入单独的数据库。
- 单个数据库耗尽了空间。
- 然后,只能分片。
分片的过渡
- 过渡从一个特性的冻结开始。
- 确认分片该达到什么样的效果——希望尽少的执行查询以及最少数量的数据库去呈现一个页面。
- 剔除所有的MySQL join,将要做join的表格加载到一个单独的分片去做查询。
- 添加大量的缓存,基本上每个查询都需要被缓存。
- 这个步骤看起来像:
- 1 DB + Foreign Keys + Joins
- 1 DB + Denormalized + Cache
- 1 DB + Read Slaves + Cache
- Several functionally sharded DBs+Read Slaves+Cache
- ID sharded DBs + Backup slaves + cache
- 早期的只读奴节点一直都存在问题,因为存在slave lag。读任务分配给了奴节点,然而主节点并没有做任何的备份记录,这样就像一条记录丢失。之后Pinterest使用缓存解决了这个问题。
- Pinterest拥有后台脚本,数据库使用它来做备份。检查完整性约束、引用。
- 用户表并不进行分片。Pinterest只是使用了一个大型的数据库,并在电子邮件和用户名上做了相关的一致性约束。如果插入重复用户,会返回失败。然后他们对分片的数据库做大量的写操作。
如何进行分片?
- 可以参考Cassandra的ring模型、Membase以及Twitter的Gizzard。
- 坚信:节点间数据传输的越少,你的架构越稳定。
- Cassandra存在数据平衡和所有权问题,因为节点们不知道哪个节点保存了另一部分数据。Pinterest认为应用程序需要决定数据该分配到哪个节点,那么将永远不会存在问题。
- 预计5年内的增长,并且对其进行预分片思考。
- 初期可以建立一些虚拟分片。8个物理服务器,每个512DB。所有的数据库都装满表格。
- 为了高有效性,他们一直都运行着多主节点冗余模式。每个主节点都会分配给一个不同的可用性区域。在故障时,该主节点上的任务会分配给其它的主节点,并且重新部署一个主节点用以代替。
- 当数据库上的负载加重时:
- 先着眼节点的任务交付速度,可以清楚是否有问题发生,比如:新特性,缓存等带来的问题。
- 如果属于单纯的负载增加,Pinterest会分割数据库,并告诉应用程序该在何处寻找新的节点。
- 在分割数据库之前,Pinterest会给这些主节点加入一些奴节点。然后置换应用程序代码以匹配新的数据库,在过渡的几分钟之内,数据会同时写入到新旧节点,过渡结束后将切断节点之间的通道。
ID结构
- 一共64位
- 分片ID:16位
- Type:10位—— Board、User或者其它对象类型
- 本地ID——余下的位数用于表中ID,使用MySQL自动递增。
- Twitter使用一个映射表来为物理主机映射ID,这将需要备份;鉴于Pinterest使用AWS和MySQL查询,这个过程大约需要3毫秒。Pinterest并没有让这个额外的中间层参与工作,而是将位置信息构建在ID里。
- 用户被随机分配在分片中间。
- 每个用户的所有数据(pin、board等)都存放在同一个分片中,这将带来巨大的好处,避免了跨分片的查询可以显著的增加查询速度。