出处http://web.itivy.com/article-531-1.htmlphp
本文出自澳大利亚一位ID为Dodgy Coder的程序员2012年4月的博客文章。他从High Scalability上整理和总结了Google、YouTube、Twitter、Amazon、Ebay、Facebook和Instagram等7家知名互联网的系统扩展经验。值得注意的是,有些资料时过境迁,已经再也不反映最新状况,可是核心的理念和许多具体经验仍是很是宝贵的学习资料,值得一读。html
不难发现,这7个公司都有如下共同的6大理念:前端
下面来分别看一下7大公司的经验吧。java
1、 Googlepython
可靠的存储(Reliable Storage)nginx
可靠、可扩展的存储基本上是任何应用程序的核心。GFS(Google File System)是Google的核心存储平台——它是一个大型分布式结构化的日志文件系统,Google在其中存放了大量的数据。为何会自建系统,而不是使用其余已有的产品?由于Google须要对系统有绝对的掌控力,同时这个平台也正是Google之因此成为Google的地方。GFS使他们得到了跨数据中心的高可靠性、扩展到数以千计个节点的能力、提供巨大的读写带宽、支持以GB为单位的大数据块处理和跨节点分布操做以下降瓶颈的高效技术。git
基础设施成为竞争优点程序员
Google能够更快、更便宜而且在规模上罕有匹敌地发布新的互联网服务。许多公司与Google的想法并不相同,他们把基础设施当作负担,花钱的事儿。新旧两类公司使用的技术彻底不一样,在系统开发上也少有共识。github
在平台的基础上构建应用程序web
大平台方式有一个常常被忽略的优点,就是初级开发者也能很快并自信地开发健壮的应用程序。若是每一个项目都须要创建分布式基础设施,那么你很快将会陷入困境,由于懂得这么去作的开发者很是少。协同效应并不老是空谈,从整个系统上着眼改善,能够帮助到创建在这个系统上的全部应用程序或项目。好比:改善了文件系统就可让全部项目都当即并且透明地(指上层开发者和使用者都无需操心)获益。若是每一个项目都使用不一样的文件系统,那么在整个技术栈上的改进将不会带来持续不断的增益。
自动化和恢复
创建自管理系统,让工做不须要停机进行。这样容许你更容易地进行如下操做:在多台服务器间从新调配资源、动态添加容量、将机器下线以及从容地处理升级。
创建不断进化的基础设施
并行地执行一个耗时(CPU绑定的)操做,并取优胜者。这尤为适合在CPU富余而IO不足的状况。
不要忽视学术界
学术界有不少很棒的思想,只不过尚未进入生产环境。你如今看到Google所作的事情其实都并不新鲜,只是没有大规模部署而已。
考虑数据压缩
当由许多机器组成的大型集群受限于IO时,压缩不失为一良策。
2、 YouTube
越简单越好
寻找问题领域的最简解决方案。这里存在许多复杂的问题,可是选择解决方案的首要前提就是不能复杂。随着时间的发展,复杂性会一直存在,而最简单和最松散的解决方案是始终适用的。这样作的缘由是保持解决问题的灵活性,反之你则会把本身逼入角落。你将会失去对程序的控制,一样当你试图解决时,问题将变的愈来愈复杂,你会变得无路可走。
欺骗:知晓如何在数据上做假
最快的函数调用就是根本上没有发生。当你须要作一个持续增长的计数器时,好比说一个浏览计数,你须要为每次的更改作数据库调用。或者你能够每隔一段的时间作一次调用,或者是一个随机数量作更改——可是人们可能就会认为它是实时显示的。你必需要知道如何在数据上做假。
抖动(Jitter)
若是你的系统不存在抖动,将会由于用户在同一时间对同一个资源进行请求产生Thundering Herd(“惊群效应”)。对于一个流行的视频,YouTube会尽量的为其作缓冲。最流行的视频可能会缓冲24小时。若是全部缓存同时到期,将会形成上面所说的Thundering Herd。经过抖动,你能够设置随机的时间(18-30小时)。这将阻止事情在同一个时间发生,而且保证很长时间内请求的顺利完成。
近似正确
用户所见就是你系统的状态。若是用户看不到你系统中存在的偏移和不一致,那么这些问题从本质上来讲根本“不存在”。若是你正在一个页面上发布评论,而这时候某些用户恰好打开了这个页面,那么这些用户在半秒内可能根本看不到你的评论,然而那些阅读这个页面的用户根本不会在乎这个事情。这种状况就容许你稍微的进行“做弊”,由于你的评论并无达到全局一致性。若是真的去作这个全局上的一致性,那将会投入大量的开销,一样也是牛刀杀鸡——由于你并非在作金融系统,因此你能够做弊。
3、 Twitter
实现API
Twitter的API流量是Twitter网站的10倍,API是Twitter增加用户数量最重要的手段。保持服务的简单,容许开发者在本身基础设施上创建服务,而且想出比Twitter本身更好的应用程序点子。所谓众人拾柴火焰高,集思广益才能作更好的创新。因此开放你的应用,而且让其保持简单,这样就能够和其余人的应用程序进行整合。(固然,后来在赢利压力下,Twitter过河拆桥,将有史以来最有活力的API生态链生生干掉了。)
使用你清楚的东西
Twitter使用了一堆消息传送。对用户发布的消息进行排队,而后分发给指定的用户。Twitter最主要的功能就是扮演消息传递的桥梁,架起不一样格式(SMS、Web、IM等等)之间的消息传送。在后台同步发送消息去清除朋友的缓存,而不是单独的进行。Twitter开发者对Ruby最为熟悉,因此他们抛弃DRb转至Starling(一个Ruby编写的分布式队列系统)。分布式队列系统将队列写入磁盘,以防止系统崩溃。以Twitter的经验,大部分的性能提高不是语言的选择而是应用程序的设计。(这一点也不彻底正确了,Twitter由于性能,后来从Ruby整个迁移到了Scala/JVM。)
知道什么时候进行缓存以及缓存什么
举个例子,得到你朋友的状态是很复杂的,包括了安全等多个隐患。因此,取代对数据库进行查询,朋友的状态将会被放入缓存。永远都不会接触到数据库。90%的请求都是API请求,因此他们在前端基本上不作任何页面缓存。由于Twitter的页面都对时间敏感,这样作(缓存页面)没有任何好处。
4、 Amazon
使用SOA
Amazon的架构都是松耦合的,而且围绕着服务创建。一个面向服务的体系结构(SOA),基于他们能够快速及独立的创建软件的多个组件,容许他们更快的向市场上投放。Amazon.com Web页就是一个相似的应用程序服务器。这样的话这个应用程序同时服务了网络服务接口、用户服务应用程序以及卖方接口。
使用API打造你的系统,你将围绕你的应用程序创建起一整套的生态系统。围绕着服务展开将给你更高的灵活性——你能够并行的进行操做,由于全部的输出都是一项服务。禁止客户端直接对数据库进行访问,由于不会涉及到客户端,因此你的服务将拥有更好的扩展性和可靠性。这点很像谷歌的改变某个组件让创建在整个系统或平台上的应用程序都获益。
根据场景在数据的一致性和数据的可用性之间作取舍
既然扩展你就必须作分片,因此你必须为特定的系统作高一致性或者高可用性的选择。你必须发现有效性和一致性上的重叠部分,根据服务的需求选择一个合适的方案。举个结帐系统的用例:你老是但愿将请求做为购物车的添加项,由于它产生了收入。在这个用例中,你就选择了高可用性。错误就隐藏在了客户方面,而且由其提出:当客户进行提交时,你必须对一致性进行重点对待,由于不一样的服务(信用卡处理、运输、操做、报告)都将同时访问数据,而且每一个都有各自数据一致性的需求。
拥抱失败
对失败抱日常心,它可能会常常出现,因此拥抱它。好比,使用一个快速重启和快速恢复方案。选用一个合适的数据传输,服务正常运行的概率将接近100%。创建一个自我修复、自我组织、无人值守类型的操做。
只用你须要的
让设计保持简单,肯定设计中没有隐藏的需求及依赖性。将技术程度降到最低,你只须要一些解决问题的必须技术。确保这些技术不会带来更多的复杂性,慎重甚至是不选择一些特定的方法或者技术堆栈。有些地方他们使用jboss/JAVA,但他们只选用Servlet,而不使用余下的几个J2EE框架。使用C++来处理请求,使用Perl/Mason来创建目录。
根据客户的反馈来指定决策
使用测量和客观的讨论去区分好坏。给客户一个切实的选择来测试哪一个更好,而且经过这些测试制定决策。这点一般使用相似A/B测试和Web Analytics等技术实现。若是你产生决策上的问题,那么将其编码,让更多的人使用,从而清楚哪一个选择才是你真正想要的。
扩展性即竞争优点
和Google同样,基础设施一样是Amazon竞争优点所在。他们能够简单的在原始服务上创建很是复杂的应用程序。他们能够独立的进行扩展操做,保持无与伦比的系统可用性,在不须要大规模的重配置下就能够快速的推出新服务。
5、 eBay
切分一切
若是你不能对其进行切分,那么你就不能对其进行扩展。经过功能和数据,将全部东西都切割成容易控制的组块。
到处异步
经过事件驱动队列和传输管道,链接起全部的组件。
拥抱故障
监视全部发生的事情,别间断服务——即便有些部分开始发生故障。最小化和控制依赖性,使用抽象的接口和虚拟化技术,组件中包含一个SLA,用户从SLA违规中恢复。自动化全部事情,组件须要自动调整,而系统则须要自我调节和完善。
拥抱不一致
在须要使用CAP原理的地方挑选好每一个特征,若是选择非分布式事务,不一致性能够经过操做顺序来最小化,经过异步恢复和调整实现最终一致性。
保存全部的数据
数据驱动最佳的机遇、预测和推荐的发现,因此保存全部。清楚哪些数据是有权威的,哪些数据没有,进行不一样的对待。
基础设施:给指定的工做分配合适的工具
须要最大化的使用每一个资源:数据(内存)、处理(CPU)、时钟时间(延时)等。没有通吃的策略,区分规模对待。由商用、工业服务器共同组成。
6、 Facebook
扩展须要屡次的迭代
解决方案一般是在工做的开始时提出,然而随着发展你必须对其进行修改——已经使用了一年的方案,之后可能再也不适用。一个好的例子就是图片,Facebook如今(文章撰写时)每秒须要服务12亿张图片。第一代的思想就很是简单,没有考虑到扩展到如此规模,只注重功能上的实现。Uploader会将文件储存为NFS格式,而原数据将会保存在MySQL中。这个方案只用了3个月,可是这并不重要,在上市时间上他们赢得了巨大的竞争优点,一样功能上的特色比深思扩展方案来的更加剧要。第二代则使用了不一样的访问方式对其进行优化,鉴于较小的图片访问频度会比较高,因此对其使用了缓存,他们一样开始使用CDN(内容分发网络)。第三代则是一个overlay系统,让Facebook能够在原有的文件系统上使用BLOB存储。图片被存储到一个二进制的BLOB,由于你清楚BLOB中图片的字节偏移量,因此每张图片对磁盘只进行一次IO操做。
不要重复设计一个方案,让其保持简单
在你对系统进行横向扩展时,只使用你须要用到的。找到方案中须要重作的地方,进行优化,或者着手从新创建堆栈中须要修改的部分。Facebook花费了大把的时间去优化PHP,最终完成了HipHop的编写,完成了PHP到C++的转换,这为他们节省了大量的内存和CPU开销。然而你不须要从第一天就着手作这个事情,在彻底重写一门语言以前你须要作的是聚焦产品的特性。
针对工做选用正确的工具,而且接受这个选择所带来的开销
若是你须要使用Python,并选择了它进行开发,可是必需要认识到这个选择是有开销的:一般是部署、监视、运营等方面。若是选择了一个面向服务的体系结构(SOA),你必须本身动手创建大部分所需的后端,这须要大把的时间。经过LAMP你能够省下许多开销,可是一旦你真的选择了LAMP堆栈,相似服务的配置以及监视将是随之要面对的问题。随着你对这个服务了解的加深,你一定会自费力气作重复的工做。
正确的公司文化
创建一个能够促进生产的内部环境,并根据需求不断的进行完善。在进行正确的编码和作出正确的产品以前,你首先须要定义正确的公司文化;没有一个正确的文化,公司将不会获得发展。
7、 Instagram
利用现有的云基础设施
不要去作重复的事情,你可使用可靠而且获得证明的技术。Instagram在Amazon的EC2云计算基础设施上运行了100多个Ubuntu 11.04实例,他们一样还使用了Amazon ELB,其中包括3个nginx实例以及自动的故障恢复(撰稿日期)。图片被储存在Amazon S3上,他们还使用了Amazon CloudFront做为CDN,这么作能够有助于世界各地的图片加载时间。
异步的任务队列
当一个用户决定将Instagram上的图片分享到Twitter或者Facebook时,或者当他们须要给发布的图片发送一个实时的通告,他们把任务推送给开源的Gearman任务管理框架。使用异步队列意味着当“重载”在后台进行时,媒体上传能够快速完成。大约有200个工做者(Python编写)忙于任务队列的处理,处理服务中本身分割的份额。
推送通知
他们使用一个开源Apple Push Notification Service(APNS)提供程序pyapns(基于Twisted),天天稳定地为Instagram解决10亿推送消息的任务。
实时的系统级监控
对于拥有100多个EC2实例的Instagram来讲,对系统进行实时的全方位监控无疑是重中之重。他们使用Munin进行系统级监视,这个监视工具在系统任何操做超过正常范围时都会发出警报。他们开发了Munin的定制插件,基于Python-Munin之上,监视非系统级事件。他们使用Pingdom进行服务的外部监视,而且使用PagerDuty处理通知和事件。而Python的错误报告,他们使用Sentry,一个开源的Django应用。在任何给定的时间,他们能够实时地登陆并了解系统中出现了什么错误。
选择性使用NoSQL技术(好比Redis)
Redis驱动了主feed,活动feed、会话系统(会话系统后端代码见这里)以及其余相关系统。Redis全部的数据都须要写入内存,因此他们在EC2上为Redis运行了几个Quadruple Extra-Large Memory实例,而且不按期给任何给定系统作跨Redis的分片。