Pinterest架构之路-两年内从0到10亿月访问量

前言

Pinterest已经能够驾驭每2.5个月流量就翻一倍的指数增加,他们实现了在2年内每个月pv从0到10亿的结果。从2个创始人加1位工程师到超过40名工程师,从只有1台MySQL服务器到180台web服务器、240 API引擎、88个MYSQL DB和1个从库、110个Redis实例、200个Memcache实例。html

使人吃惊的增加!他们是如何作到的呢?1年半年Yashwanth Nelapati 和 Marty Weiner演讲过这个富有戏剧性的架构进化故事,当初为求快,选择又多,他们也作了不少错误的选择(接下来是教训与经验总结)。mysql

这是一个伟大的演讲,很是详情,但同时很接地气,架构的策略适合每一个普通的你我,强烈推荐!git

我从演讲中主要学到两条原则:github

1.架构是当业务增加时能够方便的添加一样的东西就搞定。若是你认为扩展架构是只要扔更多的钱、加更多服务器(Boxs)的话,但若是你的架构能作到,那就是金钱。web

2.当到达极限时全部的技术都会以自已特有的方式失败,这就引出咱们选型时的原则:成熟的、简单实用的、广为人知和喜欢的、社区支持友好的、性能向来表现优异的、尽量不会出现失效且是免费的。根据这些原则,他们选择了:MySQL、SolrMemcacheRedisCassandraMongoDB丢掉了。redis

这两条原则是互相关联的。依照原则2工具能够添加更多空间实现扩展,负载增加时成熟的工具将会有较少的问题,即便有问题也有社区帮助一块儿解决,若是你选的工具太稀少人用那就你可能就会撞到南墙了。算法

这也中我认为整个演讲中最好的之一,关于分片(sharding)比集群更好的讨论,体现了业务增加时只要添加更多资源、较少失效、成熟、简单、好的支持等特征。注意下全部的工具他们都选择可分片而不是集群,关于这部分的讨论颇有趣可能不少你以前也没考虑过。sql

好了,是否是火烧眉毛了,Let's go:)mongodb

术语表

  • 喜欢的图片(pins):是一张带信息图片,包含了描述、重要性、跟踪连接等。
    数据库

  • Pinterest:是图片SNS,包括关注的人和板块功能

  • 数据库Database:包括用户库-用户的板块和板块的大头针;关注和转贴(repin)关系、认证信息等。

2010年3月份项目启动 - 寻找自我

这时你甚至不知要建设一个什么样的产品,你有不少想法,但常常很快改变,最后只留下一些很奇怪的MySQL查询。
一些早期数据:

  • 2个创始人

  • 一个工程师

  • 托管在Rackspace

  • 一台小的web服务引擎

  • 一台小的MySQL数据库

2011年1月

仍在秘密开发,根据一些用户的反馈进行迭代。一些数据:

  • Amazon EC2 + S3 + CloudFront

  • 1 NGinX, 4 Web Engines (用来冗余, 并未在线使用)

  • 1 MySQL DB + 1只读库(防止主库DOWN掉)

  • 1 任务队列 + 2任务处理器

  • 1 MongoDB (用来作计数器)

  • 2 个工程师

直到2011年9月 - 试验阶段

疯狂的增加,每2个半月翻一倍。

  • 当你达到这个增加速度时,全部东东每一个晚上、每周都会掉链子

  • 这时,网上查了不少架构方案都只会说加服务器吧,加就加吧。同时又加了不少其它技术,但所有失效了。

  • 同时你看到你组更复杂的数据:

    • Amazon EC2 + S3 + CloudFront

    • 2 NGinX, 16 Web 引擎 + 2 API 引擎

    • 5 功能性 分片 MySQL DB + 9 只读从库

    • 4 Cassandra 节点

    • 15 Membase 节点 (3 独立集群)

    • 8 Memcache 节点

    • 10 Redis 节点

    • 3 任务路由 + 4 任务处理器

    • 4 Elastic Search 节点

    • 3 Mongo 集群

    • 3 工程师

  • 5个主要数据库单独存放本身的数据

  • 因增加太快MySQL也快顶不住了,全部技术都用到了极限

  • 当全部技术用到极限时都以本身的方式失效了

  • 开始摈弃一些技术,问问本身到底咱们要什么。而后是重构。。。重构。。。

2012年1月 - 成熟期
所有重构后的系统是这样的:

  • Amazon EC2 + S3 + Akamai, ELB

  • 90 Web 引擎 + 50 API 引擎

  • 66 MySQL DBs (m1.xlarge) + 每台 1 从库

  • 59 Redis 实例

  • 51 Memcache 实例

  • 1 Redis 任务管理器 + 25 任务处理器

  • 分片的 Solr

  • 6 工程师

  • 如今都运行在分片的MySQL、Redis、Memcache和Solr上,就是这样,好处是技术简单又成熟。

  • 网站流量以一样的速度在增加,同是,iPhone的流量也开始增加了。

2012年10月12日 - 历史轮回

大概是1月份的4倍,数据是这样的:

  • Amazon EC2 + S3 + Edge Cast,Akamai, Level 3

  • 180 Web 引擎 + 240 API 引擎

  • 88 MySQL DBs (cc2.8xlarge) + 每一个配1 从库

  • 110 Redis 实例

  • 200 Memcache 实例

  • 4 Redis 任务管理器 + 80 任务处理器

  • 分片的 Solr

  • 40 工程师 (还在增加)

  • 注意到没有,架构很好用,扩展时只须要添加同样的东西,你想砸更多钱来扩展,仍是仅仅是添加空间容量?

  • 硬盘用SSD了

为什么选用Amazon EC2/S3?

  • 稳定性好。数据中虽也出过问题,添加了些风险,但总体还不错;

  • 很好的报告和支持。他们很懂架构知识问题在哪。

  • 很好的外围支持。当你快速增加时,你能够快速组织起缓存、负载均衡、map reduce、数据库等等你想要的,没必要什么都本身写,能够快速用他们的服务起动起来,当你有工程师再跟自已玩;

  • 新的实例只要几秒就可启动起来。这是云服务的力量。特别是当你只有两个工程师时,你没必要小心流量增加计划而耗费2周时间,10台缓存服务只要几分钟就搞定!

  • 弊端:选择有限。只到最近才可用SSD,尚未大内存可配置;

  • 优点:选择有限。你没必要终结于不一样服务器不一样的配置上

*国内貌似阿里云是个不错的选择(译者)。

为什么选用MySQL?

  • 真的很成熟。

  • 很坚固。从没当过机和丢失过数据。

  • 不少人可招募。

  • 响应时间和请求数是线性增加的。有些技术路线并非这样增加。

  • 很好的软件支持。XtraBackupinnotop,maatkit

  • 很好的社区支持。得到问题回答很容易。

  • 得到公司的支持也很容易,如 percona

  • 免费。刚开始时若是没有投资就很重要。

为什么选用Memcache?

  • 很成熟。

  • 很简单。它相似一个带socket的哈希表。

  • 性能一向很好

  • 广为人知且喜欢

  • 不会崩溃

  • 免费

为什么选用Redis?

  • 虽还不成熟,但很好用且简单。

  • 提供了多样的数据结构。

  • 有持久层和可复制,且能够选择如何实现。如你想要像MySQL同样保存也能够,若是你不想保存也能够,若是你想只保存3个小时也能够。说明:1.Redis的根种子(home seed)是每隔3小时保存一次,并无3小时复制功能,它只是每3时备份一次;2.若是你的服务器(box)保存不下数据了,那它只会备份几小时。这不是十分可靠,但还算简单。没必要把持久化和复制搞复杂了,这只是更简单和很廉价的架构方法。

  • 广为人知和喜欢。

  • 一向性能良好。

  • 不多失效。只有小数几个微妙的失效须要了解一下。这也是它成熟的缘由之一,只要学会了就能够搞定。

为什么是Solr?

  • 崛起中的伟大产品。安装只要几分钟,你就有一个搜索引擎了。

  • 不能跨服务器扩展(至少目前为止)。

  • 试过Elastic search搜索引擎,但扩展上有问题,特别是处理小文档上,并且查询太多。

  • 如今用的是Websolr,Pinterest有个搜索团队在支撑。

集群与分片到底哪一个好?

  • 随着业务的快速增加他们意识到须要把数据分散在不一样的区域保障将来的增加压力可控;

  • 关于集群好仍是分片好有一大堆讨论

集群 - 全部数据都是原子态的

  • 例如:CassandraMemBaseHBase

  • 选型结果:太可怕了,可能未来会用,但不是如今,他们太复杂,并且太多失效的状况。

  • 特性:数据自动分布式;数据可移动;从新均衡可分布负载;各节点可互相通信,不少交叉通信、协调。

  • 优劣:

    • 自动扩展数据库,至少白皮收是这样说的。

    • 容易安装。

    • 地理分布数据,你的数据中心能够在不一样地区。

    • 高可用性。

    • 负载均衡。

    • 无单点失效。

  • 劣势(来自第一手经验):

    • 仍十分年轻。

    • 基本上很复杂。一堆节点要协调,在生产环境很难排错。

    • 社区不多能够获得支持。因产品分割每一个阵营只有少许支持。

    • 困难和可怕的升级机制。

    • 集群管理的算法是:SPOF,若是某个节点挂了会影响全部节点,曾经挂过4次。

    • 集群管理复杂的代码透过全部节点,可能有如下几种失效的状况:1.数据再均衡中断。新装一个节点开始同步时卡住了怎么办?没人告诉你,就卡那了,最后回去用MySQL了。2.破坏的数据传染到全部节点。3.不正确的平衡也不容易修正。4.数据受权失败。

分片shard - 全手工

  • 选型结果:分片方案获胜!说明下,分片用得太广泛了,如 Flickr 的架构。

  • 特性:去掉了全部你不喜欢的集群的特性;数据分布是手工设的;数据不会迁移,虽然有人这么作,但争议很大。分割数据来分散负载;各节点之间不须要沟通,主节点控制了一切。

  • 优点:

    • 能够分割数据库来增长容量

    • 可地理分布与协调数据

    • 负载均衡

    • 数据的算法很简单。主要缘由,虽然也用了SPOF,但比复杂的集群方案它只有一半复杂,第1次用上就知道它是能工做仍是不能工做。

    • ID生成很简单。

  • 劣势:

    • 不能执行大多数的join操做

    • 不支持事务。写A库可能成功,写B库可能失败。

    • 不少约束限制要移到应用去实现。

    • (schema表)结构修改要更慎重

    • 查询报告须要在全部分片上运行,而后手工聚合

    • 聚合是在应用层完成的

    • 你的应用必须搞定上述这些问题:D

什么时候能够进行分片shard?

  • 若是你的项目只有几TB数据时,赶忙开始分片;

  • 当主要业务表行数达到几亿行时,建索引都内存溢出,或用上了交换分区时;

  • 须要把最大的表单独拿出来放到独立的数据库时;

  • 单个库已经把你的空间都用光时;

那,就要开始享受分片的好时光了:)

开始分片shard

  • 开始分片时先不要上新功能;

  • 再肯定如何分片。原则是,用最少些里查询及最小遍历几个数据库便可生成一个页面;

  • 去掉全部的Join操做。因表可能从不一样分区返回,join将没法工做;

  • 加了很是多的缓存。基本上每一个查询都有缓存。

  • 步骤就像:

    • 1 DB + Foreign Keys + Joins

    • 1 DB + 反范式Denormalized + 缓存

    • 1 DB + 只读从库 + 缓存

    • 几个分片库 +只读从库 + 缓存

    • ID 分片的数据库 + 备份从库 + 缓存

  • 提前从只读库获取数据可难会由于延时致使问题,一个对从库的读请求可能主库还没完成复制,看起来就像数据丢失了,绕开这个问题要用到缓存。

  • 用户表没有分片。只用到了一个超大的数据库而且name是惟一的,重复用户名将致使失败。大多写请求都写到分片的数据库里。

如何分片Shard?

  • 看看Cassandra的环模式(Ring Model),还有Membase和Twitter的Gizzard(已经废弃 -译者)。

  • 策略:最少的数据漫延等于最大的稳定性。

  • Cassadra有个数据均衡和受权问题:它并不知道谁拥有哪块数据。Pinterest的作法是在应用层决定数据去向何方,因此这永远不是一个问题。

  • 对未来5次分片已经计划好了。

  • 一开始就建立了不少虚拟分片。8台服务器、每台有512个数据库,每一个数据库拥有全部的表。

  • 为了高可用性,他们架构了多主库复制模式。每一个主库分配到不一样地区,一个失效能够切换到全新的替换库上。

  • 当数据库压力增加时:

    • 查看提交的新代码是否有新功能、缓存问题或其它问题发生。

    • 若是只是负载增加,他们只是分割数据而后告诉应用层去一个新的数据中心获取数据。

    • 分割数据前,先启动这些主库的从库,而后切换应用层代码访问新库,有几分钟的时间数据仍写到旧库(同时会复制到新的从库了),最后撤掉旧库(应用层代码此时只访问新的从库--这时变成主库了)。

ID的结构

  • 64位

    • 分片ID:16位

    • 类型:10位-大头针(pin)、版块、用户和其它对象

    • 本地ID:其它 位 用于本地表自增id。

  • Twitter用了一个映射表来映射ID到物理主机,这就须要一次查询,由于Pinterest运行在AWS上,MySQL查询一次须要3为毫秒,他们这种额外间接的开销接受不了,全部把位置(库、表所在的服务器地址信息)也定义到ID里了。

  • 新注册的用户是随机分配了分片的服务器上。

  • 全部的数据(包括Pin、版本等)都分配到同一个分片上。这点带来极大的好处,例如生成一个用户信息页,就不须要跨越多个不一样的分片,这样更快。

  • ID的设计足够用到65536个分片使用。但开始只用到了4096,之后还能够水平扩展,当用户库快满了,再开放更多的分片,而后新用户就会分配到新的分片上。

查询

  • 假设若是有50个查询,Pinterest会根据id进行分割,全部并发的查询,延时便是最长一个的等待时间。

  • 每一个应用都有一个配置文件,映射分片区间到一个物理主机

    • “sharddb001a”: : (1, 512)(译者:貌似他们是按字节来计算,一个字节8位最大值是256,两字节x2=512 ;也有多是写死映射关系的

    • “sharddb001b”: : (513, 1024) - 备份热主库

  • 若是要查的某用户ID在sharddb003a:

    • 分解ID

    • 在分片映射中查询

    • 链接分片所在的服务器,根据类型选择数据库,用本地ID再查正确的用户,返回序列化的数据

对象和映射

  • 全部的数据或者是一个对象(Pin、版块、用户、评论)或是一个映射(用户的版块、喜欢的图片Pin)

  • 是对象的话,一个本地ID映射到MySQL的blob(译者:或Longtext),blob块格式是json但返回昌序列化的thrift(参考Fackbook thrift)。

  • 若是是映射,就是一个映射表,能够查询用户的版块,ID包含了时间戳,能够据此按事件顺序排序。

    • Pinterest还维护了一个反射映射表,多对多的表,用来回答这类型的查询问题:关注个人用户。

    • 表名是这样纸滴:名词动词名词,如userlikepings,pinslikeuser。

  • 查询都是按主键或索引键查询(没有join)

  • 数据不会像集群同样处处飞。一旦一个用户分配到第20个分片,那他全部的数据都会在这台分片上,永远不会飞到别的地方去。64位ID包括了分片id,全部不会变化了。你能够移动物理数据到另一台数据库,但他们仍然关连着同一个分片。

  • 全部的表在全部分片都同样(数据是不一样的)。没有特殊的分片。不会遇到像用户表这个大表检测用户名冲突的问题。

  • 不须要改表结构和新索引(最神奇的地方!看他们是怎么作到的)

    • 由于表结构大可能是key=>value形式,value只是一个blob,能够随意添加字段而不用改表结构了。还有个version字段,代表blob的版本,这样应用层能够检测是否要修改blob的结构,全部的数据不须要当即更新,会在用户查询时自动升级。

    • 由于修改大表的结构有时会花费数小时甚至是成天,这样的表结构颇有优点。若是你想加个新的索引,你只要建立一个新表,而后迁移数据,当你不要时时人干掉它就好了(没提到这种更新是否事务安全)。

实战举例-生成一个用户我的信息页面

  • 从ULR获得用户名,从巨大的单个用户表查表用户id

  • 分析(分割)用户ID

  • 选择分片,链接分片

  • SELECT body from users WHERE id = userid>

  • SELECT boardid FROM userhasboards WHERE userid=id>

  • SELECT body FROM boards WHERE id IN (ids>)

  • SELECT pinid FROM boardhaspins WHERE boardid=id>

  • SELECT body FROM pins WHERE id IN (pinids)

  • 大多请求是从缓存返回  (memcache or redis), 实践中没有多少流量去掉数据库.

割接过程及脚本

  • 当迁移到一个分片的架构时,你此时有新、旧两套架构,脚本是用来迁移到新架构的代码

  • Pinterest迁移过5亿条Pins和1.6亿关注等

  • 低估了迁移的成本,开始他们认为须要2个月,事实上花了4-5个月,注意哦,是在冻结新功能上线的时候。

  • 应用层必须同时往新、旧两套架构写数据

  • 一旦确认全部的数据已经转到新架构了,而后就逐步切割请求到新的架构,逐步增长同时测试后台

  • 多搞一些脚本,多投些人力来完成切割。

  • 搞个Pyres,一个用Python写的访问Github的Resque队列的工具,一个创建在Redis的队列服务,支持优先及和重试,比起CeleryRabbitMQ好多了。

  • 割接中犯了不少错误。像用户没有了版块,只有重复搞了几遍确保没错。

开发

  • 开始尝试给每位开始配了一个系统的基本环境,都有独立的MySQL,但业务发展太快,没有做用;

  • 学Facebook的方法,都在生产环境开发,但必须很是当心;

将来的方向

SOA

  • 他们注意到,当数据库负载升高时,若是加应用服务和一堆服务器,全部的服务都连着MySQL和Memcache,意味着3万个链接到memcache时内存将达到上G,这时memcache会使用交换分区。

  • 转到SOA架构是一个办法。如,搞一个“关注”服务,只作“关注”的查询,这样能够隔离链接到30个,这样压力就能够接受。

  • SOA还能够帮助隔离功能。根据服务配置项目组及支持组和安全组。

学到的知识点

  • 什么事均可能会失败。必定要注意简单。

  • 让事情颇有趣。

  • 用到极限什么东东都会挂掉。

  • 构架是只要添加复制同样的东东就能扩展容量。好的架构也是金钱。

  • 集群管理算法是SPOF,若是有一个BUG将与每一个节点冲突,就这,挂过4次。

  • 分散数据来分散负载

  • 越少分散数据你的架构就越稳定,这也是为什么pinterest选择分片而不是集群的缘由。

  • SOA的守则:功能隔离。能够帮助减小连结、组织团队、组织支持、提高安全。

  • 问问自已到底要什么?不要管技术也要符合你的有所愿景(或叫商业模式),即便你要所有重构。

  • 不要惧怕丢掉一点点数据。pinterest保存用户数据在内存而后周期性的写到数据库,丢失只意味了几个小时的数据没了,但系统会很简单高效,这才是更重要的。

相关文章

英文原文 http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html

<翻译:朱淦 350050183@qq.com 2015.7.27>

相关文章
相关标签/搜索