Pinterest如何仅凭6名工程师实现1100万用户规模的增长
2012年1月,Pinterest的月独立用户达到1170万,仅有6名工程师。
自2010年3月推出以来,它是当时最快突破1000万月活用户的公司。
Pinterest是一个以图片为主的社交网络,用户可以将图片保存或“固定”到他们的画板上。
当我在下面提到“用户”时,我指的是“月活跃用户”(MAU)。
从Pinterest的扩展中学到的教训
-
使用已知、经过验证的技术。Pinterest在当时对较新的技术进行尝试导致了数据损坏等问题。
-
保持简单。(一个经常出现的主题!)
-
不要过于创造性。团队决定采用一种架构,可以添加更多相同的节点来进行扩展。
-
限制你的选择。
-
分片数据库>集群。它减少了节点间的数据传输,这是一件好事。
-
玩得开心!新工程师在他们的第一周会贡献代码。
Instagram团队在只有3名工程师的情况下,将用户规模扩大到了1400万人。
2010年3月:封闭测试启动,1名工程师
Pinterest于2010年3月推出,拥有1个小型MySQL数据库、1个小型Web服务器和1名工程师(以及2位联合创始人)。

2011年1月:10,000用户,2名工程师
2011年1月,经过九个月的发展,Pinterest的架构已经能够处理更多的用户。他们仍然只接受邀请,并有两名工程师。
他们有:
-
一个基本的网络服务器堆栈(Amazon EC2、S3和CloudFront)
-
Django(Python)用于后端
-
-
4个网络服务器以实现冗余
-
使用NGINX作为他们的反向代理和负载均衡器。
-
1个MySQL数据库此时 + 1个只读的次要数据库
-
MongoDB用于计数器
-
1个任务队列和2个任务处理器用于异步任务

2011年10月:320万用户,3名工程师
从2011年1月到2011年10月,Pinterest增长非常快,每个月和半个月用户数量翻倍。
他们在2011年3月推出的iPhone应用是推动这一增长的因素之一。
当事物发展迅速时,技术出现故障的频率往往超出你的预期。
Pinterest犯了一个错误:他们过于复杂化了他们的架构。
他们只有3名工程师,但使用了5种不同的数据库技术来处理数据。
他们都在手动分片他们的MySQL数据库,并使用Cassandra和Membase(现在是Couchbase)对数据进行集群化。
他们的“过于复杂的技术堆栈”
-
Web服务器堆栈(EC2 + S3 + CloudFront)
-
16个网络服务器
-
2个API引擎
-
2个NGINX代理
-
5个手动分片的MySQL数据库 + 9个只读的从数据库
-
4个Cassandra节点
-
15个Membase节点(3个独立集群)
-
8个Memcache节点
-
10个Redis节点
-
3个任务路由器 + 4个任务处理器
-
4个弹性搜索节点
-
3个Mongo集群

聚类出错了
数据库集群是将多个数据库服务器连接在一起,作为一个单一系统共同工作的过程。
理论上,集群可以自动扩展数据存储,提供高可用性、免费负载均衡,并且没有单点故障。
不幸的是,在实践中,集群化过于复杂,升级机制困难,并且存在一个巨大的单点故障。

每个数据库都有一个集群管理算法,用于从一个数据库路由到另一个数据库。
当数据库出现问题时,会添加一个新的数据库来替换它。
理论上,集群管理算法应该能够很好地处理这个问题。
实际上,Pinterest的集群管理算法存在一个错误,导致所有节点上的数据损坏,破坏了数据再平衡,并产生了一些无法修复的问题。

Pinterest的解决方案是?从系统中移除所有的聚类技术(Cassandra,Membase)。全面采用MySQL + Memcached(更为成熟的技术)。
MySQL和Memcached是经过充分验证的技术。Facebook使用这两种技术创建了世界上最大的Memcached系统,轻松处理了每秒数十亿次的请求。
2012年1月:1100万用户,6名工程师
2012年1月,Pinterest处理了大约1100万月活跃用户,每天用户数量在1200万到2100万之间。
在这一点上,Pinterest已经花时间简化他们的架构。
他们当时移除了一些不太被证实的想法,比如聚类和Cassandra,并用被证实有效的想法来替代,比如MySQL、Memcache和分片。
他们的简化堆栈
-
亚马逊EC2 + S3 + Akamai(替代了CloudFront)
-
90个网络引擎 + 50个API引擎(使用Flask)
-
66个MySQL数据库+66个从数据库
-
59个Redis实例
-
51个Memcache实例
-
Redis任务管理器+25个任务处理器
-
分片的Apache Solr(替代了Elasticsearch)
-
移除Cassanda、Membase、Elasticsearch、MongoDB、NGINX

Pinterest如何手动分片他们的数据库
数据库分片是将单个数据集分割成多个数据库的方法。
好处:高可用性、负载均衡、简单的数据放置算法、易于拆分数据库以增加容量、易于定位数据
当Pinterest首次分片他们的数据库时,他们进行了功能冻结。在几个月的时间里,他们逐步手动分片他们的数据库。
团队从数据库层面删除了表连接和复杂查询。他们增加了大量的缓存。
由于在多个数据库之间维护唯一约束需要额外的工作量,他们将用户名和电子邮件等数据存储在一个庞大的、未分片的数据库中。
所有的表都存在于所有的分片上。
手动分片的一个小例子
由于他们有数十亿个“pin”,他们的数据库索引耗尽了内存。
他们会将数据库中最大的表格移动到自己的数据库中。
然后,当那个数据库的空间用尽时,他们会进行分片。
2012年10月:2200万用户,40名工程师
2012年10月,Pinterest的月活跃用户约为2200万,但他们的工程团队已经增加到40名工程师。
这个建筑物是一样的。他们只是增加了更多相同的系统。
-
亚马逊EC2 + S3 + CDNs(EdgeCast,Akamai,Level 3)
-
180个Web服务器+240个API引擎(使用Flask)
-
88个MySQL数据库+每个数据库有88个从属数据库
-
110个Redis实例
-
200个Memcache实例
-
4个Redis任务管理器 + 80个任务处理器
-
分片的Apache Solr

他们开始从硬盘驱动器转向固态硬盘。
一个重要的教训是:有限而经过验证的选择是一件好事。
坚持使用EC2和S3意味着他们的配置选择有限,从而减少了烦恼,更加简单。
然而,新的实例可以在几秒钟内准备好。这意味着他们可以在几分钟内添加10个Memcache实例。
Pinterest的数据库结构化
IDs
像Instagram一样,Pinterest也有独特的ID结构,因为它们使用了分片数据库。
他们的64位ID看起来像:
分片ID:分片(16位)
类型:对象类型,例如引脚(10位)
本地ID:表中的位置(38位)
这些ID的查找结构是一个简单的Python字典。
表格
他们有对象表和映射表。
对象表用于存储针脚、板子、评论、用户等信息。它们具有与MySQL blob(类似JSON)映射的本地ID。
映射表用于对象之间的关系数据,例如将板块映射到用户或将喜欢映射到图钉。它们具有将完整ID映射到完整ID和时间戳的功能。
所有查询都是为了效率而进行的主键(PK)或索引查找。它们剔除了所有的JOIN操作。

