当达到这个数字时,myspace数据库服务器遇到了I/O瓶颈,即他们存取数据的速度跟不上了。而这时据他们第一个架构只要5个月。有人花5分钟都无法完成留言,很多用户认为myspace完蛋了。
这个时候新的架构被快速提出来了,这一次他们把数据库架构按照分割模式设计,以网站功能分出多种,如登陆、现实用户资料、博客信息、等分门别类存储在不同的数据库服务器里。这种垂直分割策略利于多个数据库分担访问压力(天涯曾经就这么做过)。后来myspace从存储设备与数据库服务器直接交互的方式SAN(用高带宽和专门设计的网络将大量磁盘存储设备链接在一起,而数据库链接到SAN)。
3、300万用户
到300万用户时,这种架构开始也不行了,因为每个数据库都必须有每个用户表副本,意识是一个用户注册后,他的信息会分别存在每个数据库中,但这种做法有可能某台数据库服务器挂掉了,用户使用一些服务可能会有问题。另一个问题是比如博客信息增长太快,专门为他服务的数据库的压力过大,而其他一些功能很少被使用又在闲置。这就好像有人忙的要死,有人闲的要死。
于是他们购买了更好更贵的服务器来解决管理更大数据库的问题。但专家预测他们即使昂贵专业的服务器到最后也会不堪重负,他们必须调整架构而不是掏钱买更好的服务器。于是他们的第三代架构出现了。分布式计算架构,他们分布众多服务器,但从逻辑上看成是一台服务器。拿数据库来说,不能再按功能拆分了,看成只有一个数据库服务器。数据库模型中维护一个用户表、博客信息表、等等同看作在一个数据库服务器中。
然后他们开始把用户按每百万一组分割,每一组的用户访问指定的数据库服务器。另外一个特殊服务器保存所有用户的帐号和密码。他们的设计师说如果按照这种模式以更小粒度划分架构是可以进一步优化负荷负担的(50万用户为一组或者更少)。
4、900万-1700万用户
myspace在这个时候把网站代码全部改为.net语言,事实证明网站跑的比以前快了很多、执行用户的请求消耗非常少的资源,后来他们把所有的程序都改成.net了。但问题到1000万时还是出来了。
用户注册量太快,按每100万分割数据库的策略不是那么完美,比如他们的第7台数据库服务器上线仅仅7天就被塞满了。主要原因是佛罗里达一个乐队的歌迷疯狂注册。而且某台数据库服务器可以在任何原因任何时候遭遇特别大的负荷。他们的解决办法是人工把崩溃的数据库里的用户迁移走。但这不是一个好办法。
这个时候myspace购买了3PAdata设备,他的牛逼之处是真正把所有的数据库看成一个整体。他会根据情况把负荷平均分配出去,比如当用户提交一个信息,他会看哪个数据区域空闲然后分配给他,然后会在其他多处地方留有副本,不会出现一台数据库服务器崩溃,而这台数据库里的信息没有办法读取的情况,这样做看起来好极了。
另外他们增加了缓存层,以前用户查询一个信息,就请求一次数据库,现在当一个用户请求数据库后,缓存层就会保留下来一个副本,当其他用户再访问时就不需要再请求数据库了,直接请求缓存就够了。
5、2600万用户
他们把服务器更换到运行64位的服务器,这样服务器上可最多挂上32G内存,这无疑有提升了网站性能,用户感觉这个网站开始稳定快起来了。但一个新问题意外出现了。他们放数据库服务中心的洛杉矶全市停电了。这导致整个系统停止运行长达12个小时。
这时他们实现了在地理上分布多个数据中心以防止洛杉矶事件再次出现,在几个重要城市的数据中心的部署可以防止某一处出现故障,整个系统照样提供服务,如果几个地方都出现故障,那么这就意味着国家出现了重大灾难,这种几率是非常低的。
6、总结
这个架构变化升级相当有意思,架构随着用户量的提升作仓促的变化,但又恰到好处,看来MySpace又验证了一句古话“有压力才会有动力”。同时他给我们后人的启示是要尽早发现系统的瓶颈,设计师在设计时要有前瞻思想,否则今后有可能也要这样仓促的升级你的产品。
2、Flickr网站架构总结
Flickr.com是网上最受欢迎的照片共享网站之一,还记得那位给WindowsVista拍摄壁纸的HamadDarwish吗?他就是将照片上传到Flickr,后而被微软看中成为Vista壁纸御用摄影师。
--PairofServerIron's做负载均衡
--Squid做html和照片的缓存
--Memcached做数据缓存
--尤其是mysql数据库采用master-slave和shards技术实现了mysql数据库的负载均衡,解决了数据库的瓶颈,达到了数据库横向扩展的目标。
Flickr.com是最初由位于温哥华的Ludicorp公司开发设计并于2004年2月正式发布的,由于大量应用了WEB2.0技术,注重用户体验,使得其迅速获得了大量的用户,2007年11月,Flickr迎来了第20亿张照片,一年后,这个数字就达到了30亿,并且还在以加速度增长。2005年3月,雅虎公司以3千500万美元收购了Ludicorp公司和Flickr.com。虽然Flickr并不是最大的照片共享网站(Facebook以超过100亿张照片排名第一),但这笔收购仍然被认为是WEB2.0浪潮中最精明的收购,因为仅仅一年后,Google就以16亿美元的高价收购了YouTube,而2007年10月,微软斥资2.4亿美元收购Facebook1.6%股份,此举使Facebook估值高达150亿美元。估计Ludicorp公司的创始人StewartButterfield和CaterinaFake夫妇现在还在后悔吧。
Flickr整体框架图
数据库最初的扩展-Replication
Flickr网站的架构,需要一次大的变化来解决长期持续扩展的问题。
Shard-大型网站数据库扩展的终极武器?
而应用的主要修改在于要添加一个Lookup访问层,例如将以下的代码:
Memcached的应用和争论
对于读操作:
复制滞后和同步问题的解决
3、YouTube架构总结
这个貌似在国内是被和谐的,要fanqiang才能访问(不知到底何故)。看看他的架构:--NetScaler用于负载均衡和静态内容缓存
--CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
--使用Google的BigTable,一个分布式数据存储、数据库分成shards,不同的用户指定到不同的shards、使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的
4、PlentyOfFish架构总结
这个我觉的最神奇了,一个人每天花2个小时,可以维护一个每天3000WPV的,而且是基于.NET的(呵呵,终于给我们.net程序员一个好榜样了)。简述他的架构:--用MicrosoftWindows操作系统作为服务器
--使用ASP.NET技术
--使用IIS作为Web容器
--用AkamaiCDN来缓存网页
--用FoundryServerIron来做负载均衡
--sqlserver采用master-slave架构,两台负责read操作,master那台负责写操作
--所有的request数据都使用了gzip压缩
中国的经济环境持续向好,所以很多公司的IT部门都得到了更多的预算,但这些预算被合理的使用了吗?这些预算往往被用来采购更好的服务器硬件,更新的操作系统和数据库软件,还有各式各样的行业应用。倒不是说这些部署不好,只是说我们的IT部署一定要以实用为出发点,少做一些可有可无的投资。我们要多向POF学习,其实稳定、快速、便捷才是制胜的关键。正如POF站长一再强调的简单哲学,所有复杂的东西都尽量不去使用。
5、WikiPedia架构总结
维基百科(Wikipedia)是一个基于Wiki技术的全球性多语言百科全书协作计划,同时也是一部在网际网路上呈现的网路百科全书,其目标及宗旨是为全人类提供自由的百科全书──用他们所选择的语言来书写而成的,是一个动态的、可自由和的全球知识体。
--GeoDNS让用户能够访问离他地域最近的Web服务器
--用LVS实现负载均衡
--使用MediaWiki软件
--大量缓存(Cache),Squid作为反向代理,Memcached做数据缓存
--用Mysql数据库集群
来点直接的数据:
在我写的这些网站架构的Blog中,GeoDNS第一次出现,这东西是啥"A40-linepatchforBINDtoaddgeographicalfilterssupporttotheexistentviewsinBIND",把用户带到最近的服务器。GeoDNS在WikiPedia架构中担当重任当然是由WikiPedia的内容性质决定的--面向各个国家,各个地域。
维基百科网站成功的第一关键要素就是Cache了。CDN(其实也算是Cache)做内容分发到不同的大洲、Squid作为反向代理.数据库Cache用Memcached,30台,每台2G。对所有可能的数据尽可能的Cache,但他们也提醒了Cache的开销并非永远都是最小的,尽可能使用,但不能过度使用。
运营这样的站点,WikiPedia每年的开支是200万美元,技术人员只有6个,惊人的高效。
先暂时总结这么多吧,欢迎大家点评。
1、Google架构
老大当然要放第一位,Google的架构非我们这些平凡之辈一两天能够了解的,这里也只是大概地整理一下:
--GFS,Google的强有力的面向大规模数据密集型应用的、可伸缩的分布式文件系统
--MapReduce,Google的分布式并行计算系统,GFS存储数据,而MapReduce则是以最快最可靠的方式处理数据。
--BigTable,Google基于GFS和MapReduce之上的用来存储结构化数据的解决方案,有了它,不仅可以存储结构化的数据,而且可以更好的管理和做出负载均衡决策。
2、如果喜欢本文的朋友可以以任何形式转载,开心的话留个链接,不开心就算了,因为文中很多资料也是来自网络的。
Google主要以GFS、MapReduce、BigTable这三大平台来支撑其庞大的业务系统,我称他们为Google三剑客,网上也有说是Google的三架马车。
一、GFS(GoogleFileSystem)
这是Google独特的一个面向大规模数据密集型应用的、可伸缩的分布式文件系统,由于这个文件系统是通过软件调度来实现的,所以Google可以把GFS部署在很多廉价的PC机上,来达到用昂贵服务器一样的效果。
下面是一张GoogleGFS的架构图:
从上图我们可看到Google的GFS主要由一个master和很多chunkserver组成,master主要是负责维护系统中的名字空间、访问控制信息、从文件到块的映射以及块的当前位置等元素据,并通过心跳信号与chunkserver通信,搜集并保存chunkserver的状态信息。chunkserver主要是用来存储数据块,google把每个数据块的大小设计成64M,至于为什么这么大后面会提到,每个chunk是由master分配的chunk-handle来标识的,为了提高系统的可靠性,每个chunk会被复制3个副本放到不同的chunkserver中。
当然这样的单master设计也会带来单点故障问题和性能瓶颈问题,Google是通过减少client与master的交互来解决的,client均是直接与chunkserver通信,master仅仅提供查询数据块所在的chunkserver以及详细位置。下面是在GFS上查询的一般流程:
1、client使用固定的块大小将应用程序指定的文件名和字节偏移转换成文件的一个块索引(chunkindex)。2、给master发送一个包含文件名和块索引的请求。3、master回应对应的chunkhandle和副本的位置(多个副本)。4、client以文件名和块索引为键缓存这些信息。(handle和副本的位置)。5、Client向其中一个副本发送一个请求,很可能是最近的一个副本。请求指定了chunkhandle(chunkserver以chunkhandle标识chunk)和块内的一个字节区间。6、除非缓存的信息不再有效(cacheforalimitedtime)或文件被重新打开,否则以后对同一个块的读操作不再需要client和master间的交互。
不过我还是有疑问,google可以通过减少client与master通信来解决性能瓶颈问题,但单点问题呢,一台master挂掉岂不是完蛋了,总感觉不太放心,可能是我了解不够透彻,不知道哪位朋友能解释一下,谢谢:)
二、MapReduce,Google的分布式并行计算系统
Map即映射,Reduce即规约,由master服务器把map和reduce任务分发到各自worker服务器中运行计算,最后把结果规约合并后返回给用户。这个过程可以由下图来说明。
按照自己的理解,简单对上图加点说明:
1、首先把用户请求的数据文件切割成多份,每一份(即每一个split)被拷贝在集群中不同机器上,然后由集群启动程序中的多份拷贝。
2、master把map和reduce任务交给相对空闲的worker处理,并阻塞等待处理结果。
3、处理map任务的worker接到任务后,把以key/value形式的输入数据传递给map函数进行处理,并将处理结果也以key/value的形式输出,并保存在内存中。
4、上一步内存中的结果是要进行reduce的,于是这些mapworker就把这些数据的位置返回给master,这样master知道数据位置就可以继续分配reduce任务,起到了连接map和reduce函数的作用。
5、reduceworker知道这些数据的位置后就去相应位置读取这些数据,并对这些数据按key进行排序。将排序后的数据序列放入reduce函数中进行合并和规约,最后每个reduce任务输出一个结果文件。
6、任务结束,master解除阻塞,唤醒用户。
以上是个人的一些理解,有不对的地方请指出。
三、BigTable,分布式的结构化数据存储系统?
BigTable是基于GFS和MapReduce之上的,那么google既然已经有了GFS,为何还要有BigTable呢(也是我原先的一个疑问)?后来想想这和已经有操作系统文件系统为何还要有SQLSERVER数据库一样的道理,GFS是更底层的文件系统,而BigTable建立在其上面,不仅可以存储结构化的数据,而且可以更好的管理和做出负载均衡决策。
以下是BigTable的架构图:
它完全是一个基于key/value的数据库,和一般的关系型数据库不同,google之所以采用BigTable,因为它在满足需求的同时简化了系统,比如去掉了事务、死锁检测等模块,让系统更高效。更重要的一点是在BigTable中数据是没有格式的,它仅仅是一个个key/value的pairs,用户可以自己去定义数据的格式,这也大大提高了BigTable的灵活性和扩展性。
四、总结
2、优酷网架构
在国内,上不了YouTube,只能看看优酷了,说实在优酷在国内算是做的不错了,视频加载速度明显比土豆什么的要快,那就看看他的架构吧:
--自建的一个模块化的CMS系统,前端十分灵活
--mysql数据库从单台MySQL服务器(JustRunning)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库,解决数据库服务器的灵活横向扩展。
--为了避免内存拷贝和内存锁,没有(很少)用内容缓存。
--最核心的是构建了比较完善的CDN网络,就近原则,让你看视频时从离你最近的服务器上获取视频信息,所以我们看优酷比土豆要快,原因就在这里。
一、网站基本数据概览
二、网站前端框架
从一开始,优酷网就自建了一套CMS来解决前端的页面显示,各个模块之间分离得比较恰当,前端可扩展性很好,UI的分离,让开发与维护变得十分简单和灵活,下图是优酷前端的模块调用关系:
这样,就根据module、method及params来确定调用相对独立的模块,显得非常简洁。下面附一张优酷的前端局部架构图:
三、数据库架构
1、简单的MySQL主从复制:
MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其原来图如下:
其主从复制的过程如下图所示:
但是,主从复制也带来其他一系列性能瓶颈问题:
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
2、MySQL垂直分区
如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:
3、MySQL水平分片(Sharding)
这是一个非常好的思路,将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:
但是,优酷是如何解决跨shard的查询呢,这个是个难点,据介绍优酷是尽量不跨shard查询,实在不行通过多维分片索引、分布式搜索引擎,下策是分布式数据库查询(这个非常麻烦而且耗性能)
四、缓存策略
但为何我们访问优酷会如此流畅,与土豆相比优酷的视频加载速度略胜一筹?这个要归功于优酷建立的比较完善的内容分发网络(CDN),它通过多种方式保证分布在全国各地的用户进行就近访问——用户点击视频请求后,优酷网将根据用户所处地区位置,将离用户最近、服务状况最好的视频服务器地址传送给用户,从而保证用户可以得到快速的视频体验。这就是CDN带来的优势,就近访问,有关CDN的更多内容,请大家Google一下。
3、Twitter架构
twitter,怎么说呢,说他简单么还真简单,但又是那么复杂,真是纠结。话说这140个字的鼻祖让国内的某某某非常风骚,算了不跑题了,说说他的架构吧:
--平台比较广泛:
--细化memcached,同时建立向量缓存VectorCache、行缓存RowCache、碎片缓存FragmengCache、缓存池PageCache
--给力的消息队列,用Ruby写的一个分布式队列Starling
作为140个字的缔造者,twitter太简单了,又太复杂了,简单是因为仅仅用140个字居然使有几次世界性事件的传播速度超过任何媒体,复杂是因为要为2亿用户提供这看似简单的140个字的服务,这真的是因为简单,所以复杂。可是比较遗憾的是目前在中国大陆twitter是无法访问的,但作为一个爱好架构的程序猿,这道墙是必须得翻的,墙外的世界更精彩。今天就结合网络上的一些资料,来浅谈一下我对twitter网站架构的学习体会,希望给路过的朋友一点启示.......
一、twitter网站基本情况概览
下图是twitter的整体架构设计图:
二、twitter的平台
twitter平台大致由twitter.com、手机以及第三方应用构成,如下图所示:
三、缓存
讲着讲着就又说到缓存了,确实,缓存在大型web项目中起到了举足轻重的作用,毕竟数据越靠近CPU存取速度越快。下图是twitter的缓存架构图:
大量使用memcached作缓存
在memcached缓存策略中,又有所改进,如下所述:
1、创建一个直写式向量缓存VectorCache,包含了一个tweetID的数组,tweetID是序列化的64位整数,命中率是99%
2、加入一个直写式行缓存RowCache,它包含了数据库记录:用户和tweets。这一缓存有着95%的命中率。
3、引入了一个直读式的碎片缓存FragmengCache,它包含了通过API客户端访问到的sweets序列化版本,这些sweets可以被打包成json、xml或者Atom格式,同样也有着95%的命中率。
4、为页面缓存创建一个单独的缓存池PageCache。该页面缓存池使用了一个分代的键模式,而不是直接的实效。
四、消息队列
一个试图做国内最好的图片服务提供商,虽然和Flickr还有点差距,但也不错了,话说搞图片和视频的是很烧服务器和带宽的,在国内这么贵的带宽也挺不容易的,好了,一起看看他的架构吧:
--Squid,这个貌似做图片缓存挺好使的,而且还是分布式的,可以硬盘命中和内存命中,速度都还不错。
--MogileFS图片存储
--mysql分库设计,垂直分库,水平sharding,跨库关联查询
--透明的缓存设计
一、先来看看Yupoo网站的基本信息:
其他:Python,Java,MogileFS、ImageMagick等
其架构图如下:
对于应用服务器层的Tomcat,现在Yupoo!技术人员也在逐渐用其他轻量级的东西替代,而YPWS/YPFS现在已经用Python进行开发了。
名次解释:
接下来的ImageProcessServer负责处理用户上传的图片。使用的软件包也是ImageMagick,在上次存储升级的同时,对于锐化的比率也调整过了(我个人感觉,效果的确好了很多)。”Magickd“是图像处理的一个远程接口服务,可以安装在任何有空闲CPU资源的机器上,类似Memcached的服务方式。
原来Yupoo!的存储采用了磁盘阵列柜,基于NFS方式的,随着数据量的增大,”Yupoo!开发部从07年6月份就开始着手研究一套大容量的、能满足Yupoo!今后发展需要的、安全可靠的存储系统“,看来Yupoo!系统比较有信心,也是满怀期待的,毕竟这要支撑以TB计算的海量图片的存储和管理。我们知道,一张图片除了原图外,还有不同尺寸的,这些图片统一存储在MogileFS中。
和很多使用MySQL的2.0站点一样,又拍网的MySQL集群经历了从最初的一个主库一个从库、到一个主库多个从库、然后到多个主库多个从库的一个发展过程。
图3:数据库的进化过程
最初是由一台主库和一台从库组成,当时从库只用作备份和容灾,当主库出现故障时,从库就手动变成主库,一般情况下,从库不作读写操作(同步除外)。随着压力的增加,我们加上了memcached,当时只用其缓存单行数据。但是,单行数据的缓存并不能很好地解决压力问题,因为单行数据的查询通常很快。所以我们把一些实时性要求不高的Query放到从库去执行。后面又通过添加多个从库来分流查询压力,不过随着数据量的增加,主库的写压力也越来越大。
水平拆分:而水平拆分是将同一个表的数据进行分块保存到不同的数据库中,这些数据库中的表结构完全相同。
拆分方式
一般都会先进行垂直拆分,因为这种方式拆分方式实现起来比较简单,根据表名访问不同的数据库就可以了。但是垂直拆分方式并不能彻底解决所有压力问题,另外,也要看应用类型是否合适这种拆分方式。如果合适的话,也能很好的起到分散数据库压力的作用。比如对于豆瓣我觉得比较适合采用垂直拆分,因为豆瓣的各核心业务/模块(书籍、电影、音乐)相对独立,数据的增加速度也比较平稳。不同的是,又拍网的核心业务对象是用户上传的照片,而照片数据的增加速度随着用户量的增加越来越快。压力基本上都在照片表上,显然垂直拆分并不能从根本上解决我们的问题,所以,我们采用水平拆分的方式。
拆分规则
那么,怎么样对应用户和数据库呢?我们有这些选择:
按算法对应
最简单的算法是按用户ID的奇偶性来对应,将奇数ID的用户对应到数据库A,而偶数ID的用户则对应到数据库B。这个方法的最大问题是,只能分成两个库。另一个算法是按用户ID所在区间对应,比如ID在0-10000之间的用户对应到数据库A,ID在10000-20000这个范围的对应到数据库B,以此类推。按算法分实现起来比较方便,也比较高效,但是不能满足后续的伸缩性要求,如果需要增加数据库节点,必需调整算法或移动很大的数据集,比较难做到在不停止服务的前提下进行扩充数据库节点。
按索引/映射表对应
这种方法是指建立一个索引表,保存每个用户的ID和数据库ID的对应关系,每次读写用户数据时先从这个表获取对应数据库。新用户注册后,在所有可用的数据库中随机挑选一个为其建立索引。这种方法比较灵活,有很好的伸缩性。一个缺点是增加了一次数据库访问,所以性能上没有按算法对应好。
比较之后,我们采用的是索引表的方式,我们愿意为其灵活性损失一些性能,更何况我们还有memcached,因为索引数据基本不会改变的缘故,缓存命中率非常高。所以能很大程度上减少了性能损失。
图4:数据访问过程
索引表的方式能够比较方便地添加数据库节点,在增加节点时,只要将其添加到可用数据库列表里即可。当然如果需要平衡各个节点的压力的话,还是需要进行数据的迁移,但是这个时候的迁移是少量的,可以逐步进行。要迁移用户A的数据,首先要将其状态置为迁移数据中,这个状态的用户不能进行写操作,并在页面上进行提示。然后将用户A的数据全部复制到新增加的节点上后,更新映射表,然后将用户A的状态置为正常,最后将原来对应的数据库上的数据删除。这个过程通常会在临晨进行,所以,所以很少会有用户碰到迁移数据中的情况。
当然,有些数据是不属于某个用户的,比如系统消息、配置等等,我们把这些数据保存在一个全局库中。
问题
分库会给你在应用的开发和部署上都带来很多麻烦。
不能执行跨库的关联查询
不能保证数据的一致/完整性
所有查询必须提供数据库线索
比如要查看一张照片,仅凭一个照片ID是不够的,还必须提供上传这张照片的用户的ID(也就是数据库线索),才能找到它实际的存放位置。因此,我们必须重新设计很多URL地址,而有些老的地址我们又必须保证其仍然有效。我们把照片地址改成/photos/{username}/{photo_id}/的形式,然后对于系统升级前上传的照片ID,我们又增加一张映射表,保存photo_id和user_id的对应关系。当访问老的照片地址时,我们通过查询这张表获得用户信息,然后再重定向到新的地址。
自增ID
实现
图6:数据库布局
前面提到过添加服务器时,为了保证负载的平衡,我们需要迁移一部分数据到新的服务器上。为了避免短期内迁移的必要,我们在实际部署的时候,每台机器上部署了8个逻辑数据库,添加服务器后,我们只要将这些逻辑数据库迁移到新服务器就可以了。最好是每次添加一倍的服务器,然后将每台的1/2逻辑数据迁移到一台新服务器上,这样能很好的平衡负载。当然,最后到了每台上只有一个逻辑库时,迁移就无法避免了,不过那应该是比较久远的事情了。
我们把分库逻辑都封装在我们的PHP框架里了,开发人员基本上不需要被这些繁琐的事情困扰。下面是使用我们的框架进行照片数据的读写的一些例子:
如果我们要访问全局库中的数据,我们需要定义一个DBTable对象。
我们的框架提供了缓存功能,对开发人员是透明的。
revision信息也是存放在缓存里的,Key为Photos-revision。这样做看起来不错,但是好像列表缓存的利用率不会太高。因为我们是以整个数据类型的revision为缓存Key的后缀,显然这个revision更新的非常频繁,任何一个用户修改或上传了照片都会导致它的更新,哪怕那个用户根本不在我们要查询的Shard里。要隔离用户的动作对其他用户的影响,我们可以通过缩小revision的作用范围来达到这个目的。所以revision的缓存Key变成Photos-{shard_key}-revision,这样的话当ID为1的用户修改了他的照片信息时,只会更新Photos-1-revision这个Key所对应的revision。
因为全局库没有shard_key,所以修改了全局库中的表的一行数据,还是会导致整个表的缓存失效。但是大部分情况下,数据都是有区域范围的,比如我们的帮助论坛的主题帖子,帖子属于主题。修改了其中一个主题的一个帖子,没必要使所有主题的帖子缓存都失效。所以我们在DBTable上增加了一个叫isolate_key的属性。
ShardedDBTable继承自DBTable,所以也可以指定isolate_key。ShardedDBTable指定了isolate_key的话,能够更大幅度缩小revision的作用范围。比如相册和照片的关联表yp_album_photos,当用户往他的其中一个相册里添加了新的照片时,会导致其它相册的照片列表缓存也失效。如果我指定这张表的isolate_key为album_id的话,我们就把这种影响限制在了本相册内。
我们的缓存分为两级,第一级只是一个PHP数组,有效范围是Request。而第二级是memcached。这么做的原因是,很多数据在一个Request周期内需要加载多次,这样可以减少memcached的网络请求。另外我们的框架也会尽可能的发送memcached的gets命令来获取数据,从而减少网络请求。
5、Amazon网站架构
这个Amazon从小书店开始现在成了全球商品品种最多的网上零售商和全球第2大互联网公司,貌似很风光嘛,那架构一定很犀利的,下面一起来看看:
--平台,Linux、oracle、C++、Perl、Mason、Java、Jboss、Servlets
好了,先就介绍这几个,有空再找几个看看,说实在看架构比看阿凡达刺激,多看看有益身心健康。
一、平台以及状态
Linux、oracle、C++、Perl、Mason、Java、Jboss、Servlets
--超过5500万活动顾客帐号
--世界范围内超过100万活动零售合作商
--构建一个页面所需访问的服务介于100至150个之间
二、架构概述
l我们说的可伸缩性到底意味着什么?对于一个服务来说,当我们增加为其分配的系统资源之后,它的性能增长能够与投入的资源按比例提升,我们就说这个服务具有可伸缩性。通常意义上的性能提升,意味着能够提供更多的服务单元,也可以为更大的工作单元提供服务,比如增长的数据集等。
lAmazon的架构经历了巨大的变化,从一开始时的两层架构,转向了分布式的、去中心化的服务平台,提供许多种不同的应用。
l最开始只有一个应用来和后端交互,是用C++来完成的。
l数据库逐渐演变成共享资源,这样就很难再在全部业务的基础之上进行增容操作了。前端与后端处理的演进受到很大限制,因为他们被太多不同的团队和流程所共享了。
l他们的架构是松散耦合的的,并且围绕着服务进行构建。面向服务的架构提供给他们的隔离特性,让他们能够快速、独立地完成许多软件组件的开发。
l逐渐地,Amazon拥有了数百个服务,并有若干应用服务器,从服务中聚合信息。生成Amazon.com站点页面的应用就位于这样的一台应用服务器之上。提供web服务接口、顾客服务应用以及卖家接口的应用也都是类似的情况。
l许多第三方的技术难以适用Amazon这种网站的规模,特别是通讯基础架构技术。它们在一定范围内工作的很好,但是如果范围再扩大的话,它们就不适用了。因此,Amazon只好自己开发相应的基础技术。
l不在一种技术上"吊死"。Amazon在有的地方使用jboss/java,不过只是使用servlets,并没有完全使用j2ee中所涉及到的技术。
lC++开发的程序被用来处理请求。Perl/Mason开发的程序用来生成页面中的内容。
lAmazon不喜欢采用中间件技术,因为它看起来更像一种框架而不是一个工具。如果采用了某种中间件,那么就会被那种中间件所采用的软件模式所困扰。你也就只能选用他们的软件。如果你想采用不同的软件几乎是不可能的。你被困住了!经常发生的情况就是消息中间件,数据持久层中间件,Ajax等等。它们都太复杂了。如果中间件能够以更小的组件的方式提供,更像一个工具而不是框架,或许对我们的吸引力会更大一些。
lAmazon提供SOAP和REST这两种Web服务。大概有30%的用户采用SOAP这种WebServices。他们看起来似乎是Java和.NET的用户,而且使用WSDL来生成远程对象接口。大概有70%的用户使用REST。他们看起来似乎是PHP和PERL的用户。
l无论采用SOAP还是REST,开发人员都可以得到访问Amazon的对象接口。开发人员想要的是把工作完成,而不需要关心网线上传输的是什么东西。
lAmazon想要围绕他们的服务构建一个开放的社区。他们之所以选择WebServices是因为它的简单。事实上它是一个面向服务的体系架构。简单来说,你只有通过接口才能访问到需要的数据,这些接口是用WSDL描述的,不过它们采用自己的封装和传输机制。
l架构开发团队都是小规模团队,而且都是围绕不同的服务进行组织。
--在Amazon服务是独立的功能交付单元。这也是Amazon如何组织他的内部团队的。
--如果你有一个新的业务建议,或者想解决一个问题,你就可以组织一个团队。由于沟通上的成本,每个团队都限制到8~10个人。他们被称为twopizzateams。因为用两个比萨饼,就可以让团队成员每个人都吃饱了。
--例如,他们创建了这样一个团队,其功能是在一本书中查找特有的文字和短语。这个团队为那个功能创建了一个独立的服务接口,而且有权做任何他们认为需要做的事情。
l部署
--他们创建了一个特殊的基础设施,来完成对依赖性的管理和对完成服务的部署。
--目标是让所有正确的服务可以在一个主机中部署。所有的应用代码、监控机制、许可证机制等都应该在一个“主机”中。
--每个人都有一个自己的系统来解决这些问题。
--部署进程的输出是一个虚拟机,你可以用EC2来运行他们。
l为了验证新服务的效果,从客户的角度去看待服务,这样做是值得的。
--从客户的角度去看待服务,聚焦于你想交付给用户的价值。
--从用户将要看到的简要特性开始,再从客户考虑的角度检查你构建的服务是否有价值。
--以最小化的设计来结束设计过程。如果想要构建一个很大的分布式系统,简单性是关键。
l对于大型可伸缩系统来说状态管理是核心问题
--内部而言,他们可以提供无限存储空间。
--并不是所有的操作是有状态的。结账的步骤是有状态的。
--通过分析最近点击过的页面的SessionID,这种服务可以为用户提供推荐商品建议。
--他们追踪、保存着所有的数据,所以保持状态不是一个问题。有一些分离的状态需要为一个session来保持。提供的服务们会一直保留信息,所以你只要使用这些服务就可以了。
lEricBrewers'CAP理论——或称为系统的三个属性
--系统的三个属性:一致性,可用性,网络分区容忍度。
--对于任何一个共享数据的系统都至少具备这三个属性中的两个。
--网络分区容忍度:把节点分割成一些小的分组,它们可以看到其他的分组但是无法看到其他全部节点。
--一致性:写入一个值然后再读出来,你得到的返回值应该和写入的是同一个值。在一个分区系统中有些情况并非如此。
--可用性:并非总是可读或者可写。系统可能会告诉你无法写入数据因为需要保持数据的一致性。
--为了可伸缩性,你必须对系统进行分区,因此针对特定的系统,你要在高一致性或者高可用性之间做出选择。你必须找到可用性和一致性的恰当重叠部分。
--基于服务的需要来选择特定的实现方法。
--对于结账的过程,你总是想让更多的物品放入顾客的购物车,因为这样可以产生收入。在这种情况下你需要选择高可用性。错误对顾客是隐藏的,过后才会被拿出来分析。
下面是一张Amazon的DynamoKey-Value存储架构图:
按分布式系统常用的哈希算法切分数据,分放在不同的node上。Read操作时,也是根据key的哈希值寻找对应的node。Dynamo使用了ConsistentHashing算法,node对应的不再是一个确定的hash值,而是一个hash值范围,key的hash值落在这个范围内,则顺时针沿ring找,碰到的第一个node即为所需。
Dynamo对ConsistentHashing算法的改进在于:它放在环上作为一个node的是一组机器(而不是memcached把一台机器作为node),这一组机器是通过同步机制保证数据一致的。
Amazon的云架构图如下:
以下是运行原理:
好了,有关Amazon架构就介绍到这里,希望能给路过的朋友一点启发,谢谢阅读!