Archive for the ‘Arch’ Category
Friday, April 24th, 2009
不知大家有没有发现,就算你选择了"记录登录状态",下次访问kaixin001.com的时候还是官方静态首页,过一会才跳转到个人首页,这样的用户体验反正我是不太舒服,查看kaixin001首页源代码,发现个中蹊跷:
function _bodyonload()
{
....
var v_kx = getCookie('_kx');
if (v_kx.length)
{
....
v_timeid = setTimeout("gotohome()", 2000);
}
}
function gotohome()
{
if ...
Posted in Arch | 14 Comments »
Friday, April 10th, 2009
Web2.0网站,数据内容以几何级数增长,尤其是那些小文件,几K~几百K不等,数量巨多,传统的文件系统处理起来很是吃力,很多网站在scaling的过程中都遇到了这样的问题:磁盘IO过高;备份困难;单点问题,容量和读写无法水平扩展,还存在故障的可能。
YouTube也碰到这样的问题,每一个视频有4个缩微图,这样的话缩微图数量是视频数量的四倍,想象一下YouTube有多少视频,看一下他们遇到的问题:
大量的磁盘寻址,在操作系统层面出现inodes cache和page cache的问题
单个目录文件数限制,尤其是Ext3文件系统,采用目录分级的做法,最新的Linux Kernel 2.6优化了Ext3文件系统,单目录能存储的文件数提高了100倍,但是把所有的文件存一个目录不是一个好的方法
高RPS(requests per second每秒请求数),因为一个页面可能要显示60个缩微图
高负载下Apache性能差
Apache前面加一层Squid,能抗一会,但负载上来之后,性能下降厉害,由300RPS降到20RPS
尝试lighttpd,但是lighttpd是单线程,多线程的话也有问题,线程之间缓存不能共享
加一台服务器的话需要24小时,因为文件数太多了
存在“冷却”的问题,重启服务器后需要6~10个小时才能缓存好
YouTube的解决方案是Google的BigTable,一般人没戏。(原文参见:http://www.hfadeel.com/Blog/?p=127)
Facebook也遇到了同样的问题,他们的方案参见:http://www.dbanotes.net/arch/facebook_photos_arch.html,他们经历了三个阶段:
NFS共享,挂一个盘阵,APP服务器通过NFS读写
加一个中间层Cachr:eventHttp + memcached(lighttpd + mod_memcache实现同样的功能),后端还是通过NFS连盘阵
Haystacks,详细的去读这里(E文)。
对于一般的网站来说,实用的方案有哪些呢?
一、NFS共享
是的,这个有很多问题,但实施成本低,很多公司都在用(我们也在用),在不是那么多文件,不是那么高并发的情况下还是很不错的,设置Hash目录,不要让一个目录下文件数过多,对于一般的网站来说足够用了。
备份确实是一个问题,如果不是海量的话,根据文件更新时间每天增量备份+周期性的全量备份应该可以。
二、文件存数据库
真有人这么做,手机之家用MySQL建了256个表来存储超过1T的文件,前端加一个多级缓存(具体未知,也许就是memcached也许还是文件),数据库做数据备份用,他们用起来觉得还不错。
或者觉得MySQL太重,试试key->value的数据库,比如BDB,Tokyo Cabinet等。
三、分布式文件系统
开源的很多,好看簿用的是MogileFS,与memcached师出同门。傲游用MFS来存储用户的收藏夹文件,详细文章参见:分布式文件系统MFS(moosefs)实现存储共享(一) 、(二),据说数百万轻松处理。
分布式文件系统好处是可以均衡读写压力,数据可靠性大大增加,某个数据节点挂了也没事。
还不行?自己DIY一个去吧,豆瓣就这么做的,TokyoCabinet做为底层存储,封装了一个memcached协议接口(与Tokyo Tyrant何异?),一致性哈希,应用程序根据哈希规则在node中读写数据:
DoubanFS结构图,版权由charlee所有
Posted in Arch | 7 Comments »
Thursday, February 12th, 2009
前言:
关于Digg的架构,之前Fenng已经写过一篇Digg 网站架构的文章,Fenng在文章开头说“越来越发现其实都是自我重复的劳动,后续的信息都是嚼别人剩下的甘蔗。”,其实是Fenng过谦了,我就是从DBA notes一点一滴开始学习的。
原文在Scaling Digg and Other Web Applications,Todd Hoff总能给我们带来一些有意思的文章。这里既不直译也不全译,保持原文骨干加上肤浅的理解。
Digg用户在3000W左右,网站每秒请求数达到13000个,规模算是很大了,Lamp(Linux+Apache+MySQL+PHP)结构,Web2.0网站中钟情PHP的不少,国外的Facebook、Digg、Flickr...,国内的新浪博客、开心网、51.com等等,扩展的不是编程语言而是网站架构,因为编程语言从来都不会是网站瓶颈,每种语言都有自己适合做和不适合做的事情。喜欢比较语言快慢的可以看看http://shootout.alioth.debian.org/,看看而已不要用速度去衡量编程语言的优劣。
Digg的扩展战略:
扩展是有特殊性的,当已有的方案不能满足需求时,你需要根据自己的特殊需求来建立方案。要熟悉自己的业务需求,找出系统的短板,解决问题,避免过度优化。
编程语言不需要扩展,因为语言从来都不是瓶颈,把PHP提速300%不会是什么大问题。
去中心化,分布式处理高并发请求。
水平扩展,用更多更便宜的机器代替更高效更昂贵的机器。
数据库驱动的网站需要作水平分区和垂直分区扩展,水平分区就是把数据放到不同的机器上,比如按照时间划分:2009年的数据一组服务器,2009年的数据一组服务器,或者按照用户ID划分:每200W用户一组服务器;垂直分区把一个表分成多个表,每个表只包含一部分字段,可以按照业务分或者常用的“动静分离”,比如对文章计数的字段大可以和文章内容字段分开。
建立数据应用层,程序不要直接操作数据库分区,这样可以保持好的扩展性。这一点非常重要,如果没有数据应用层API,一旦对数据库分区做了修改,你的程序就需要大改了。程序的稳定性和持续性就不能保证。比较常见的MVC开发模式,数据层和逻辑层分开,一旦数据库底层改变了,只需要对数据层做简单的修改,不影响既有业务。
一致性、高可用性、分区容忍性(Partition Tolerance)三者只能取其二,具体的阅读http://camelcase.blogspot.com/2007/08/cap-theorem.html,一致性:每个人看到的都一样,哪怕当时就有更新;高可用性:部分故障不影响使用;分区容忍性:数据分区还能保持系统所有属性。
数据分区要求反常规化,这是在Digg是大问题,同样的数据要复制到多个对象上去,而且还好保持同步。
采用异步的队列架构,把任务放到队列中交由多台机器处理,而不是一次同步处理,关于异步任务处理可以阅读 Flickr - Do the Essential Work Up-front and Queue the Rest和The Canonical Cloud Architecture
icons和图片采用MogileFS存储,MogileFS是一个分布式的文件系统,由memcached作者开发,国内的好看簿也有使用MogileFS。
采用APC作为PHP加速器,Facebook用的也是这个,PHP5.30以后将自带APC加速器,同样的产品还有eAccelerator和Xcache,国内可能用eAccelerator的比较多,windows的版本我一般用这个网站编译的
缓存策略:永久性缓存和失效期缓存;基本不更新的内容采用文件缓存;动态缓存采用memcached;极少修改的数据采用APC缓存,APC不是分布式缓存,直接缓存的机器内存中,所以速度更快,适合缓存那些配置文件,比如MySQL的配置信息;缓存采用链责任模式,首先看PHP全局变量,如果没有就查APC,再没有就查memcached,最后没有就查数据库,这个觉得不太必要,你的缓存存在哪来你自己还不清楚阿。
Digg的推荐引擎是一个自定义的图形数据库,数据库最终保证一致性,先写如一个分区,然后再逐步写到其他的分区。在更新的过程中,可能取出来的数据不一致,是因为有不同的数据库分区处理,最终将会是一致。
MemcacheDB:性能革命性的一步
想象一下Kevin Rose,Digg的创建者,当前有4000个追随者,如果Kevin Rose一天digg一次,将会有4000个写操作,最热门的digg有最多的追随者,这会导致巨大的性能瓶颈:
你不能同时更新4000个追随者的帐号信息,幸运的是我们可以通过前面提到的异步队列方式解决。
Digg面临的海量写操作,如果平均每个人有100个追随者,一天就有3亿条写操作,平均到每秒有3000个写操作,每天有5GB的数据存储,在50~60台服务器之间有5TB的数据交换。
如果是MySQL的话估计早就挂了,Digg在笔记本上的测试是memcachedb每秒可以处理15000个写操作,memcachedb的测试结果表明每秒可以支持23000个写操作或者64000个读操作,足以应付Digg洪水般的请求。
memcachedb是一个分布式的kye-value型数据持久化解决方案,提供兼容memcached协议接口,由Sina工程师Steve Chu开发。
提到Digg为什么采用memcachedb,Digg的工程师给出的理由是:需要持久化缓存数据,与memcached协议兼容,Digg已经有很多业务应用了memcached,可以很方便的切换到memcachedb上去,开源。
后记:
很高兴的看到除了Sina,memcachedb又有一个超重量级的应用了,性能和可靠性都得到了极大的检验,大可放心应用生产环境中。我还说今年有空写个玩具版的类memcachedb项目,还是不要了,有时间还是去做些更有意义的事情,无谓重复发明。
Posted in Arch, PHP | No Comments »
Saturday, January 10th, 2009
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2009/01/cu-net-opt-salon/
特意把调休放在1.9,主要是想去听听CU组织的网络优化论坛,报名的时候有点意外,貌似丢失了报名信息,和组织者沟通了一下,感谢周平同学的热心帮助,说到的时候找他就可以,去的时候其实也没有查邀请函什么的,还给了件CU的T-Shirt,甚是感谢,一般这种开源技术研讨会都是很开放的。
首先是TOM网的曹刚带来的“浅析系统架构”,主要讲的是Myspace和SOHU社区架构的演变过程,基本的内容可以参考构建可扩展网络应用的七个步骤,一般他们的历程都是从第一步到第四步,大体上差不多,我这里列举这个关键词:
64位:Myspace为了让服务器管理更多的内容,操作系统由32位升级到64位,我们都知道32位的操作系统最多支持4G内存(当然有方法可以实现超过4G,不推荐。),64位操作系统理论上支持4G个G,估计我是看不到用完的那天,这里要注意的是32位操作系统下,一个处理器最多处理2G内存,所以如果是Memcached服务器,不要一个进程给超过2G内存,浪费。好的做法是多开几个服务,或者直接把Memcached服务器和APP服务器合二为一,很多公司都这样。
分表:论坛的特点是数据一般是按照板块分组,所以对于论坛这样的应用来说,最好是按照板块ID分表甚至分库分机器。
板块帖子列表页:论坛的特性是新帖子、新更新的帖子排在最前面,所以可能的情况是每次刷新的时候页面都在变,SOHU社区的做法是把板块新帖子保持在一个链表里面,链表的特点是插入和删除都很快,问题是查询的时候只能遍历。
其实对于一个论坛板块来说,热门的帖子不会太多,估计大家也就翻前几页,大可以把这个数据放进缓存中,比如维护一个队列,最新的500个帖子ID,帖子Title,新帖子放在最前面,自动顶掉最后一个,大可以用数组而不用链表,虽然插入的时候慢点,读取的时候却不用遍历链表。
对于跟帖数据,一般都是按照时间顺序排列,新增加的帖子自动在最后,压力不会很大。
google去搜一下Carp算法,一致性哈希算法consistent hashing(可以参考http://tech.idv2.com/2008/08/17/memcached-pdf/),Amazon S3 环形算法(是不是就是consistent hashing?不知)。
曹刚最后做了个总结,个人觉得:熟悉业务需求应该是核心。
第二位演讲者是来自占座网的吴炳锡,讲的是LVS和Nginx的负载均衡,这块以前只是从资料上看过,接触比较少,不过炳锡的介绍深入浅出,以前觉得LVS晦涩难懂,不敢动手,听完之后无知者无畏了,有机会试试看去。其实很多事情都这样,看上去挺难,做起来就容易了,下面是几个关键字:
DR模式:LVS有NAT、TUN、DR模式,推荐使用DR模式,更多的信息去google吧。
LVS->Nginx->Squid:组合的模式,LVS是四层的转发,Nginx是七层的转发,可以支持URL规则的转发,组合起来用就可以随心所欲了。
性能:Nginx的性能和LVS NAT模式相当,都是很好的解决方案,熟悉哪个就用哪个吧,性能都不是问题。
keepalived:LVS居家旅行、杀人灭口必配武器。
搜房网:搜房网前端采用LVS做负载均衡,中间用Nginx做URL负载均衡,动态的URL跳到App服务器,静态的URL跳转到Squid服务器。
第三位演讲者来自某个赞助商,感谢他们对活动的赞助,就不做广告了,一句话概括:适合钱多人傻。
第四位演讲者来自SOHU的MySQL DBA叶金荣,报告的内容网上大多有,这里也列出一些关键字:
发现问题:系统响应慢、load avg >=5、IO wait >= 10、swap使用情况、mysql status、mysql report、mysql 5.1 profline
xfs:如果可能,mysql数据文件系统分区采用xfs,效果高30%~50%
innodb_buffer_pool_size:如果是专用的数据库服务器,设定为内存的80%吧
MyIsam适合低并发、低更新、高读取的需求,InnoDB适合高并发、高更新、高读取的需求,MyIsam读取的速度比InnoDB快许多。
Explain:查询检查、查询优化
联合索引:貌似MySQL一次查询只用到一个索引,联合索引要注意先后顺序的问题,“左派”比较吃香。
字段按需配置,能用TinyINT的不用INT,字段越短越好,具体差别可以参见:http://chaoqun.17348.com/2008/11/mysql-data-types-int/
把大表拆成小表,如果表字段里面有Text,尽量拆开吧。
缩短事务周期
字符型的字段,最好采用前缀索引。
复杂的查询拆成小的简单的查询,比如用循环查询替代。这点不敢苟同,还是按照自己的业务测试一下吧。一条sql语句总比N条要快吧,除非有问题。
left join:把条目数少的放左边,如果你了解left join的话,这个是肯定的。
实时备份:用slave做实时备份吧,一个slave就是一个备份。
第五个演讲最为精彩,走了的人实在可惜,掌声和笑声不断,田逸这个家伙说话太有意思的,有机会要认识一下。讲的是CDN方面的事情,关键字:策略,技术很重要,策略更重要。
昨天的网络优化论坛受益匪浅,演讲者都有丰富的经验,其实网站架构就那么点事情,多分享才能共同进步,不过从互动环节可以看出国内做技术的对这方面关注还是比较少,有些问题比较原始,多关注一些就不会那样了。
PS:报告盖茨:我上周四叛逃到Linux了。
Posted in Arch, Open Source | 3 Comments »
Monday, October 20th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/10/qclub-ruby-on-rails/
周日(2008-10-19)下午,去听了听QClub组织的Ruby网站架构案例分享──财帮子&FreeWheel,本意是冲着架构案例分享去的,对Ruby On Rails知之甚少,很久以前和BLUG的一位外国朋友聊天,他说是做Ruby的,我说Ruby是日本人开发的语言,还没等我说完,这位外国的朋友说:It's just a language,nothin to do with Japanese,其实我的本意是这是日本人开发的语言,国际化方面可能会差一些,比如最原始的文档应该是日文的吧。看来我们总是被人误会啊。
首先是财帮子的Robin Lu(陆亦斌)给我们分享了一下他们的建站经历,先介绍一下财帮子的基本情况:
财帮子目前大概是100万PV/天,注册用户大概十几万
人均访问PV大概在15~20个左右
网站访问的峰值大约在基金净值出来之后,最高大概是430 Rec/Sec
最开始只有一台1U的服务器,应用和数据库都在上面,现在两台1U的服务器,应用服务一台,数据库一台
系统构建在Ruby On Rails上
使用lighttpd做负载均衡,30个左右mongrel实例
使用Munin和monit做服务器监控,跑了一些的cron任务(如数据备份)
他们遇到的第一个问题是前端负载均衡效率不高,最开始用apache的mod_proxy_balancer,发现有阻塞的情况存在,现在用的是lighttpd做负载均衡,他们觉得效果不错,据说还毙掉了nginx的方案,由于久做PHP,印象中前端负载均衡应该是把请求均衡到多台服务器上,初一听他们的负载均衡是把请求均衡到多个实例上,觉得甚是费解,一打听才知道mongrel一次大概只能处理一个请求,不太了解,不好评论。
他们的第二个问题是发现Ruby On Rails里面的数据库操作有大的瓶颈,大概是对数据库的操作始终在一个事务中,不到最后不commit,所以导致死锁的情况屡有发生。这让我想起Rasmus Lerdorf老大对PHP Framework的批判Simple is Hard(用IE会被鄙视的),Framework大大提高了开发的效率,却捆住了我们的双手。如果想要高的效率,那么就让ORM见鬼去吧。
他们还有一个好的建议是把动态内容和静态文件分开处理(当然这个建议已经被无数人说过了),这个确实非常有必要。
听完报告,问了下财帮子目前的瓶颈在什么地方,答曰:内存缺乏,跑了30个mongrel直接就吃掉了2G多的内存,确实够凶猛。这方面PHP算是不错了。
另外报告中还提到他们每天需要2~3小时去处理用户的账单,比如基金净值出来了,然后他们会计算每个用户的账单情况,这种做法不太看好,想想现在十几万用户可以算出来,将来多了呢?多台服务器并行计算?可计算成本呢?提前计算网站的活跃用户足够了,那些几百年才来一次的用户或者注册了再也不上的用户大可不必,等他们访问的时候再实时计算吧。
后面分享的FreeWheel讲的大多是项目开发方面的经验,我倒是觉得FreeWheel的做法不错,各种Framewok适合快速开发网站,不见得适合开发快速的网站。
感谢财帮子和FreeWheel的分享,技术其实就那么点事,还是开放一点好。
对Ruby On Rails实在了解甚少,上述内容如有不到之处,请不吝赐教。
Posted in Arch | No Comments »
Wednesday, October 15th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/10/another-way-of-sync-distributed-data-center/
通过Google Reader好友共享看到这篇文章:横向扩展(Facebook),之前看过英文原文,不过仅粗读了一下未求甚解,感谢译者的辛勤劳动。
看完全文,大意是Facebook为了解决跨地域的网络延迟问题,在东海岸新建了一个数据中心,可新的问题随之而来,MySQL数据库复制延迟、memcache缓存不同步,Facebook的工程师通过改进MySQL复制机制,在传递binlog的同时传递memcache更新指令。这样数据库同步了,memcache也更新了。
我将我的名字从"Jason"改为"Monkey"。
我将"Monkey"写入加利福尼亚的主数据库并从加利福尼亚的memcache中删除我的名字,但不包括弗吉尼亚的memcache。
某个人在弗吉尼亚访问了我信息。在memcache中找到了我的名字,并返回"Jason"。(注意这里,其他用户看到了过时的信息)
同步复制到了之后,将从数据库中我的名字更新为"Monkey"。还需要从弗吉尼亚的memcache中删除我的名字因为缓存对象出现在同步复制流中了。
另一个人在弗吉尼亚访问了我的信息,没有在memcache中找到我的名字,所以从从数据库读出名字,得到了"Monkey"。
关键的地方就在这里,Facebook有能力对MySQL进行改造,相信一般的公司是不敢的。其实也还有另外一种方式来实现,MySQL引入了一种叫做MySQL UDF(user defined function)的机制,有人也写了个Memcached Functions for MySQL的东东(基于libmemcached,我想应该是稳定高效吧),我们大可以在从服务器上创建触发器,这样一旦有数据更新,调用Memcached Functions for MySQL更新memcached缓存(如果写操作频繁的话,估计触发器也是瓶颈)。
文章的另一个核心是“页面路径选择”,Facebook约定了更新只在主服务器上(西海岸数据中心),东海岸的数据中心数据库服务器全部以slave形式工作,Facebook在最前端有一组负载均衡服务器,更加用户访问的URL来判断是否有写操作,如果有的话直接连接到主服务器上,如果只是页面显示则导向到从服务器上(也许是西海岸服务器),为了解决数据延迟而造成混乱的问题,Facebook在有更新的用户cookie里面加入一个标记,该标记创建后20秒内,都连主服务器(20秒足够对付延迟了吧)。
这是很有意思的一个设计,利用cookie标记用户是否更新过。但问题就是只是自己看到自己最新的数据,其他人有个20秒看到的是过时的数据。
其实是不是可以试试把标记信息放服务器端(如DNS解析部分),比如A用户更新了某些数据,在服务器端做下标记,20秒内请求到这些资源的时候走主服务器。标记大可以用bdb存储,效率就不是问题了。下面是流程:
我将我的名字从"Jason"改为"Monkey"。
我将"Monkey"写入加利福尼亚的主数据库并从加利福尼亚的memcache中删除我的名字,但不包括弗吉尼亚的memcache。
在服务器端标记我的名字改变了。
某个人访问了我信息,查出我的信息更改过,走主服务器。
同步复制到了之后,将从数据库中我的名字更新为"Monkey",触发器工作,删除相应memcache缓存。
20秒后,负载均衡端标记失效,另一个人在弗吉尼亚访问了我的信息,没有在memcache中找到我的名字,所以从从数据库读出名字,得到了"Monkey"。
也是很折腾的一种方案,我这里没有那样的环境,所以也只是理论上的思考,有条件的可以试试看效果如何。
Posted in Arch, 默认分类 | 1 Comment »
Saturday, September 27th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/09/7-stages-scaling-of-web-apps/
几天前看到The 7 Stages of Scaling Web Apps,觉得很是不错,想写点什么,奈何一直很忙,整天忙着那些quick&dirty的项目,让人也堕落了许多。
今天找到报告的原文看了一下,内容丰满了许多。
要构建一个可扩展的网络应用,大多是数据库分表分库、分布式缓存、负载均衡、统一存储,诸如此类,前面我也翻译了一些国外网站架构文章,John Engales的文章高明之处是分7个步骤阐述了一个网络应用从简单到高度可扩展的构建过程。对比这七个步骤,想想我们的应用处在第几步呢?
报告的一开始解释了Performance(性能)和Scalability(扩展性)的区别,里面有两幅图片很好的诠释了,高性能就是买个好车(高配服务器)在高速公路(充足带宽)跑,高扩展性是一堆车跑在立交桥N通道上,不一定跑的很快,至少不会堵车。
第一步:开始阶段
简单的结构:防火墙+负载均衡、一对服务器、数据库服务器、内部存储,结构简单,没有冗余,维护成本低,很是适合开始阶段。
这样的应用结构应该撑个50W~100W的访问没问题吧,一般的应用话。
很多的应用可能还不到这个水平,一台服务器扔在托管机房里,应用和数据库跑在同一台服务器上,这样的应该是“第零步”吧,如果要扩展这样的应用,升级到第一步吧,应该对程序和数据库不需要怎么修改,效果可能还会不错(如果你的应用不是特别大的话)。
第二步:和第一步一样,只是规模大了些
应用很成功,加更多防火墙、负载均衡,增加更多的应用服务器,找个DBA来优化一下数据库,增加数据库存储备份,把数据库存到SAN或者DAS(这个不太赞同,有几个有这个钱的啊),仍然是个简单的应用。
第二步也很有用,估计能撑到300W左右。如果钱能解决的问题,都不是问题,访问量大了,有钱了,多买点服务器能解决问题何乐而不为?
第三步:痛苦的开始
访问量大了,加个Squid或者Varnish做反向代理吧,或者更高级的负载均衡,以缓存静态内容。加更多的应用服务器,数据库做个Master-Slave,一台Master负责写操作,N台Slave负责读操作,可能会需要做一些代码修改。
到这一步就有点像模像样了,这应该是硬件方面能做到的极限吧,估计撑了500W左右问题不大。
第四步:更加痛苦了
访问量更大了,做个memcache分布式缓存吧,数据库主从复制出现问题了,大量的写堆积到一台服务器上,复制时间过长(数据库从服务器不能即时同步),然后可以做做数据库分区(或者分表),内容统一存储,需要大量重构应用和数据库结构。
终于引入memcache了,可以大大减轻服务器硬盘读取的负载,当数据库(数据库表)变的过大的时候,再多服务器都不管用,想想你的一个数据表有100G,索引有10个G,服务器内存才4个G,光放索引都放不下。这个时候分表会是一个不错的选择,简单的分表可以自定义一个hash函数或者按照ID主键分表,只是这种固定的分表方法将来数据迁移会费事很多,还是推荐Flickr的中心数据库做法,后面会讲到。
到第四步的规模,估计1000W问题不大了
第五步:真正的痛苦开始了
开始恐慌了,开始考虑整个应用模式了,仅仅是通过业务分区还不够,可以通过地理位置啊(比如北方的用户都用北京的服务器),用户ID啊什么的分服务器分区,建立服务器集群,对于每个集群,所有功能都是可用的(这样可以很好的做数据迁移以及冗余),使用一个hash结构或者主服务器来判断用户属于哪个服务器集群(^_^中心数据库)
第五步?估计很多应用都到不了这一步,已经分完善了,估计5000W左右都没问题。
第六步:一点点痛苦
扩展应用和数据库架构,提高性能,增加新功能,优化代码,访问还在增长,但是可控。
比较惬意的阶段了,1个亿的访问量轻松应对吧。
第七步:进入未知的领域
开始找系统的瓶颈了,电源、存储、CDN什么的,更多的数据中心,可能难题是夸地区的数据复制。
呵呵,这个应该是Google考虑的问题了.
想想我们的应用瓶颈在那里,不要一下子什么都想想全了,一步到位的做法是不存在的,知道那里不足,解决它,发现其他的不足,再解决,无休止的循环,直到你失业(什么问题都没有,还要你做什么啊)或者退休(该歇歇了)。
Posted in Arch, 默认分类 | 1 Comment »
Tuesday, August 12th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/08/memcached_work_with_mysql
这次是Fotolog的经验,传说中比Flickr更大的网站,Fotolog在21台服务器上部署了51个memcached实例,总计有254G缓存空间可用,缓存了多达175G的内容,这个数量比很多网站的数据库都要大的多,原文是A Bunch of Great Strategies for Using Memcached and MySQL Better Together,我这里还是选择性的翻译以及按照我的理解补充,感谢Todd Hoff,总能给我们一些学习的案例,从这里也能看出国外技术的开放态度,不似我们,其实就那么点小九九还藏着掖着,好了,进入正题。
一、关于memcached
还不知道这个?那你去面试的时候要吃亏了,赶紧去官方网站看一下http://www.danga.com/memcached/,另外google一下用法,硬盘总是太慢,把数据存在内存里面吧,如果你只有一台服务器,推荐用一下APC(Facebook在用)或者eaccelerator或者Xcache(国人开发的),这些产品单机效果更好,如果你需要分布式的缓存方案,那么用memcached吧。
二、memcached如何与mysql并肩作战?
通过数据库分片来解决数据库写扩展的问题把数据库分片,部署到不同的服务器上,免得只有一个主服务器,写操作成为瓶颈以及可能有的“单点故障”,一般的数据库分片主要是按照业务来分,尽可能的拆分业务,不相干的都独立起来做成服务也好
前端mysql和一堆memcached服务器来应付读的问题应用程序首先从memcached中获取数据,获取不到再从数据库中获得并保存在memcached中,以前看过一篇文章说好的应用95%的数据从memcache的中获得,3%的数据从mysql的query cache中获得,剩下2%才去查表,对比一下你的应用,差距有多远?
通过mysql复制(master-slave)来解决读的问题
首先mysql数据库通过master-slave读写分离,多个slave来应对应用程序读的操作。
三、为什么不用mysql的query cache?
我们都知道mysql有个query cache,可以缓存上次查询的结果,可实际上帮不上太多的忙,下面是mysql quety cache的不足:
只能有一个实例
意味着你能存储内容的上限就是你服务器的可用内存,一台服务器能有多少内存?你又能存多少呢?
只要有写操作,mysql的query cache就失效
只要数据库内容稍有改变,那怕改变的是其他行,mysql的query cache也会失效
mysql的query cache只能缓存数据库数据行
意味着其他内容都不行,比如数组,比如对象,而memcached理论上可以缓存任何内容,甚至文件^_^
四、Fotolog的缓存技术
非确定性缓存你不确定你要的数据缓存中有没有,你也不知道是不是过期了,于是你就试探性的问memcached,我要的什么什么数据你那有吗?我可不要过期的数据啊,memcached告诉你说有并且给你,你就开心了,如果没有呢,你就要从数据库或者别的地方去获取了,这是memcached典型的应用。主要应用在:
1.复杂的数据需要多次读取,你的数据库做了分片处理,从多个数据库中获取数据并组合起来是一个非常大的开销,你大可以把这些数据取出来之后存到memcached中
2.mysql query cache的一个好的替代方案,这样数据库其他部门改变了,只要自己没改变就没问题(注意数据库更新的问题,后面会提到)
3.把关系或者列表缓存起来,比如某个栏目下的多篇文章列表
4.被多个页面调用并且获取起来很慢的数据,或者是更新很慢的数据,比如文章浏览排行榜
5.如果cache的开销超过重新获取的开销,那么不要缓存它吧
6.标签云和自动建议(类似google sugest)
例如:当一个用户上传一个图片,这个用户的好友页面上都要列出这张图片来,那么把它缓存起来吧。
潜在问题:
memcached消耗的主要是服务器内存,对CPU消耗很小,所以Fotolog把memcached部署在他们的应用服务器上(貌似我们也是这样),他们遇到了CPU搞到90%的使用率(怎么会那么高?哪出问题了吧)、内存回收(这是个大问题)等等问题。
状态缓存把应用服务的当前状态存在memcached中主要应用在:
1.“昂贵”的操作,开销大的操作
2.sessions会话,Flickr把session存在数据库中,个人感觉还是存memcached比较“便宜”些,如果memecached服务器down掉了,那么重新登录吧。
3.记录用户在线信息(我们也是这样做的)
确定性缓存对于某些特定数据库的全部内容,都缓存到memcached,有一个专门的应用服务来保障你要的数据都在memcached中,其他应用服务直接从memcached中获取数据而不去取数据库,因为数据库已经全部保存到memcached中并保持同步。主要应用在:
1.读取伸展,所有的读取都从memcached中获得,数据库没有负载
2.”永不过期“(相对的)的数据,比如行政规划数据,变动很小吧
3.经常调用的内容
4.用户的认证信息
5.用户的概要信息
6.用户的参数设置
7.用户当前常用的媒体文件列表,比如用户的图片
8.用户登录,不走数据库,只走memcached(个人觉得这个不太好,登录信息还是需要持久化的,用类似BDB这样效果也不错)
使用方式:
1.多个专门的缓存池而不是一个大的缓存服务器,多个缓存池保障了高可用性,一个缓存实例挂掉了走其他的缓存实例,所有的缓存实例挂掉了,走数据库(估计数据库抗不住^_^)
2.所有的缓存池都用程序来维护,比如数据库有更新时,程序自动把更新后的内容同步到多个缓存实例中
3.服务器重启之后,缓存要比网站先启动,这就意味着当网站已经启动了,所有的缓存都可用
4.读取的请求可以负载均衡到多个缓存实例中去,高性能,高可靠性
潜在的问题:
1.你需要足够多的内存来存储那么多的数据
2.数据以行记录数据,而memcached以对象来存储数据,你的逻辑要把行列的数据转换成缓存对象
3.要维护多个缓存实例非常麻烦,Fotolog用Java/Hibernate,他们自己写了个客户端来轮询
4.管理多个缓存实例会增加应用程序的许多开销,但这些开销相对于多个缓存得到的好处来说算不了什么
主动缓存数据魔法般的出现在缓存中,当数据库中有更新的时候,缓存立马填充,更新的数据被调用的可能性更高(比如一篇新文章,看的的人当然多),是非确定性缓存的一种变形(原文是It's non-deterministic caching with a twist.我觉得这样翻译怪怪的)。主要应用在:
1.预填充缓存:让memcached尽可能的少调用mysql如果内容不展现的话。
2.“预热”缓存:当你需要跨数据中心复制的时候
使用步骤:
1.解析数据库更新的二进制日志,发现数据库更新时对memcached也进行同样的更新
2.执行用户自定义函数,设置触发器调用UDF更新,具体参考http://tangent.org/586/Memcached_Functions_for_MySQL.html
3.使用BLACKHOLE策略,传说中Facebook也用mysql的Blackhole存储引擎来填充缓存,写到Blackhole的数据复制到缓存中,Facebook用这来设置数据作废以及跨国界的复制,好处是数据库的复制不走mysql,这就意味着没有二进制日志以及对CPU使用不那么多(啊?难道通过memcached存储二进制日志,然后复制到不同的数据库?有经验的同志在这个话题上可以补充。)
文件系统缓存把文件直接缓存在memcached中,哇,够BT的,减轻NFS的负担,估计只缓存那些过于热门的图片吧。
部分页面内容缓存如果页面的某些部分获取起来非常费劲,以其缓存页面的原始数据还不如把页面的部分内容直接缓存起来直接调用
应用程序级别的复制通过API来更新缓存,API的执行细节如下:1.一个应用把数据写到某个缓存实例,这个缓存实例把内容复制到其他缓存实例(memcached同步)
2.自动获得缓存池地址以及实例个数
3.同时对多个缓存实例更新
4.如果某个缓存实例down掉了,跳到下一个实例,直到更新成功
整个过程非常高效以及低开销
其他技巧1.多节点以应对"单点故障"2.使用热备技术,当某个节点down掉了,另外一台服务自动替换成它的IP,这样客户端不用更新memcached的IP地址
3.memcached可以通过TCP/UDP访问,持续连接可以减轻负载,系统设计成可同时承受1000个连接
4.不同的应用服务,不同的缓存服务器群
5.检查一下你的数据大小是否匹配你分配的缓存,更多请参考http://download.tangent.org/talks/Memcached%20Study.pdf
6.不要考虑数据行缓存,缓存复杂的对象
7.不要在你的数据库服务器上跑memcached,两个都是吃内存的怪兽
8.不要被TCP延迟困扰,本地的TCP/IP对内存复制是做了优化的
9.尽可能的并行处理数据
10.并不是所有的memcached的客户端都是一样的,仔细研究你用的语言所对应的(好像php和memcached配合的不错)
11.尽可能的是数据过期而不是使数据无效,memcached可以设定过期时间
12.选择一个好的缓存标识key,比如更新的时候加上版本号
13.把版本号存储在memcached中
作者最后的感言我就不翻译了,貌似mysql proxy正在做一个项目,自动同步mysql以及memcached,更多参考http://jan.kneschke.de/2008/5/18/mysql-proxy-replicating-into-memcache
后记:前几天,把Flickr架构(一)这篇文章发在PHPChina那的原创板块,居然被管理员当成软文给删掉了,难道就因为我保留了版权信息?匪夷所思。
Posted in Arch, MySQL, PHP | 2 Comments »
Wednesday, August 6th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/08/flickr_architecture_part_ii/
Flickr的架构不能说是完美的,没有完美的架构,ebay对于扩展有以下建议:
不要预先去为性能扩展,出现问题之后找到问题再寻扩展;
不要想寻找到一个一劳永逸的方案,因为你不知道下一个瓶颈在哪里;
访问量大了,出了问题,修改架构,稳定运行,访问量再大了,又出问题了,再修改,这个是解决问题的唯一方案。
Flickr是Lamp架构比较成功的案例之一,抛出Flickr的架构是因为看到国内很多的架构设计盲目、迷信以及短视,不过相对于架构来说,程序的结构更让人担忧,后面的我会写一些关于程序结构的文章,希望能和大家一起讨论成长,好了,我们继续Flickr的架构。
"Statelessness"设计,@fininan提示是“无状态”设计,比我开始译的达意许多,不过还是不太明白具体细节,原文"Statelessness means they can bounce people around servers and it's easier to make their APIs.",希望懂得朋友补充。
通过master-save的设计能解决一部分问题,但很快你就会发现不行了,常见的master-slave只能解决读的问题,但存在单点失败故障,而且当负载比较重的时候会存在复制延迟的问题,很多公司都会碰到。
搜索功能由专门的服务器群来支持,通过复制需要搜索的内容到搜索服务器去搜索,和App servers分开。
集群
1、分表:按照一定主键拆分数据表,比如按照用户划分;
2、一个用户的所有信息在同一组服务器上
3、数据能够在不同的服务器组上迁移(Statelessness)
4、一组中心服务器负责查询,比如定位某个用户在哪个服务器组
5、不要以用户ID作为分组的依据(Non-Statelessness)
服务器组中每台服务保持50%的负载,当某台服务器down机或者维护时,另外一台服务器100%负载
访问高峰时,每台服务器的负载可能高于50%,现在Flickr通过增加服务器来让服务器负载在50%以下
每个页面大概有27~35个mysql query(够高的),点击数统计、API调用数据库都是实时的(太恐怖了,估计只有Dathan Pattishall会这么变态的使用mysql)
每组服务器处理40万+的用户数据,很多数据存储了双份,比如A用户对B用户的博客进行了评论,那么评论的数据在A的数据表里面和B的数据表里面都存储了一份,Flickr通过事务来保证同步。(这样做的目的是保证同一个用户的数据都存放在同一组服务器上,省去复制的成本。)
Flickr的硬件设置:Intel EMT64处理器/红帽RHEL4/16GB内存/6块15000转的硬盘做RAID-10/12TB用户数据(仅仅是数据库而不是图片)/2U服务器,每个服务大概有120GB数据
备份:每天不同时刻跑cron,每天晚上做数据库快照,专门的服务组来备份(和线上业务分开),交叉备份(比如每天、每周、每月)
每张图片都有自己的档案,档案包括大小、尺寸、像素等等,储存在数据中
每组服务器最多400个连接,45个线程缓存
Tag标签,Flickr发现常见的数据库结构不能很好的处理巨大的标签库,他们采用的是类似倒排索引以及大量的缓存来处理,并且Tag标签不是实时的,他们会在线下进行统计
Flickr目标是所有的事务都做成实时的,没有延迟(个人觉得倒是没有这个必要)
Todd Hoff总结的经验:
不要把你的应用简单的看成一个Web应用,可能会有REST APIs, SOAP APIs, RSS feeds, Atom feeds等等的应用
无“状态”设计,不要把你的用户死死的绑定在某个服务器上
产品设计时需要做扩容的计划以及预算
慢慢来,不要一开始就买一堆服务器
实地考察,不要臆想,获得实际数据之后再做决定
内建日志系统,记录服务器和应用日志
Cache,缓存是必不可少的
抽象层,由于你的架构随时可能变,架构的变化必定要带来底层的变化,这就需要你在底层的基础上根据业务封装一层中间层,这样底层的改动不至于影响业务(这个太重要了,不要因为扩展把原来的程序推倒重来)
迭代开发,随时改进
忘记那些调优的小技巧吧,比如很多人对与PHP里面的require和require_once的性能差别,这些性能的差异和架构上的短板比起来根本不足为道
在线上测试你的效果
忘记用工具测试出来的结果,这些结果只能给你一个大概的印象而已
找出你的系统短板,一台服务器的最大处理能力是多少?现在离最大负载还有多远?mysql的瓶颈在哪里?是不是磁盘IO?memcache的瓶颈在哪里?CPU还是网络传输?
注意你的用户使用规律,比如Flickr发现每年的第一个工作日比平时多20%~40%的上传量,周日的访问量比平时要多40%~50%
要注意指数型的增长
你的计划是为你访问的峰值设计的
补充:阅读完原文的评论,有一个评论翻译出来给大家分享:
Flickr如何存储图片的呢?
标准的Flickr图片Url是这样的http://farm1.static.flickr.com/104/301293250_dc284905d0_m.jpg,其中farm1是Flickr的服务器群,static.flickr.com是Flickr静态图片服务器,104是服务器ID,301293250是图片ID,dc284905d0是Flickr的加密串,防止盗链,m表示图片的尺寸。m表示中等尺寸
后记:
终于“翻译”(姑且用这个词)完了,看到原文的一个评论是"Hmm... i can not beleive flickr written on php...",借用好像也是Flickr的人说的一句话:扩展的不是语言,而是架构。国内很多大的企业都在用PHP(比如我所在的sina),PHP总给人是草根语言的感觉,是因为没有人肯分享自己的架构,以及程序员写程序的时候不注意自己的结构(设计模式),好的架构只能让你的程序跑的更快,好的结构让你的程序更易于维护,更容易让别人看的懂,更容易团队合作。
Posted in Arch | 3 Comments »
Monday, August 4th, 2008
本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2008/08/flickr_architecture_part_i/
Flickr(http://www.flickr.com/)是国外一个领先的图片分享网站,现在应该在yahoo门下,感觉yahoo还是有很多好东西,奈何资本要抛弃他了。这个轮回其实挺有意思的,起先是做实业被microsoft郁闷了,说软件是虚的值不能那么多钱,然后microsoft被yahoo郁闷了,说互联网是虚的不值那么多钱,然后是yahoo被google郁闷了,yahoo比较厚道没说什么,现在microsoft要收购yahoo了(折腾好久了,估计要落听了吧),不知道google将来要被谁郁闷了。成功建立在相同的失败上,反过来失败都是建立在相同的成功上也成立,进入正题吧。
原文地址是http://highscalability.com/flickr-architecture,本文不是原文的严谨翻译,带有我的理解以及补充,由于水平有限,文中的错误请各位斧正。
Flickr处理的数据:
多达40亿次的请求(http request or database query?不知道了,不管是哪个,都够大的吧。)
squid总计约有3500万张图片(硬盘+内存)
squid内存中约有200万张图片
总计有大约4亿7000万张图片,每张图片大概4~5MB
每秒3,8000次请求 (存储了1200万对象在里面)
2 PB 存储(星期天要消费~1.5TB)
每天新增图片超过 400,000
吓死人不偿命....
Flickr用到的技术:
PHP
MySQL
Shards
Memcached 作为中间缓存层,memcached在web2.0网站中可能是引用最广泛的产品之一,开源&强大.
Squid 作反向代理服务器(reverse-proxy for html and images).
Linux (RedHat),如果你想用RedHat企业版又不想付费,试试这个CentOS,基本上100%克隆RedHat企业版(估计传说中1%的RedHat代码没有),我用的就是这个。
Smarty 作为模板解析,很多人在讨论smarty这不好那不好,但是大网站都在用,稳定而且功能强大,系统的瓶颈从来不会再smarty这里,我保证。
Perl 估计用perl做一些系统层面的东西吧,比如日志处理(猜测)
PEAR 做XML和Email解析,和我们一样,Flickr用的也是PHP4,不过新项目还是用PHP5吧
ImageMagick 图像处理的不二选择
Java, for the node service,Java就不太了解了,希望读者补充
Apache 大家都在用,尝鲜的用户nginx或者lighttpd(适合静态文件,youtube用它做媒体文件服务器),出了问题你会抓狂的。
SystemImager 作为服务器部署
Ganglia 分布式系统监控,或者你可以试试nagios,据我所知也很多公司在用
Subcon 用SVN维护服务器配置文件并且可以部署不同的配置文件到服务器集群中去(这个我没用过,系统运维的可能会喜欢)
Cvsup 文件分发,是否类似rsync?
Wackamole前端负载均衡,类似的产品有http://haproxy.1wt.eu/
Flickr架构
常见的Squid反向代理、PHP App Servers、Net App's、Storage Manager我在这里就不讲,我们关注一些让人兴奋的特征:
Mysql的Master-Master结构,mysql的常见的master-slave结构,大家都知道存在"single point of failure"(单点故障的问题),且只对读操作有好处,对于写频繁的网站却不是一个好的解决方案,Flickr的双master方案据我推测用的就是这个http://code.google.com/p/mysql-master-master/,原理就是master轮询,保证同时只有一个master负责写,解决了单点故障的问题。
Dual Tree Structure,看看下面的图就知道什么是“双树结构”(姑且这么翻译)
示例图中上方的2台机器为master,下方的4台为slave,这种“双树结构”的设计保证一个slave只有一台master,易于扩展也不会形成环路。原文中说这种设计是1+1=200%的设计,简单高效。为了防止自增长冲突,数据表中无自增长列。
补充:对于大型应用的分表设计,防止自增长冲突是个问题,有个简单的方案:比如分3张表,可以设第一张表从1开始以3跳跃递增,那么第一张表存储的序列为1,4,7,10……,第二张表从2开始也以3跳跃递增,第二张表存储的序列为2,5,8,11……,第三张表从3开始以3跳跃递增,第三张表存储的序列为3,6,9,12……,保证不会有重复的序号,但这种方案的缺点是如果数据爆炸,3张表不够,你分4张表呢?需要手工迁移数据,如果程序写的不好,底层又要大动了。
Flickr采用的方案是一个中心'users' table(用户表),记录的信息是用户主键以及此用户对以的数据库片区(有点类似Key->Value的设计,这样的数据结构查询起来是非常迅速的,据说Google的用户登录数据用的就是这样的设计,通过改进版的BDB数据库存储用户名和密码,这样登录起来就不用去查那个大表了),从中心用户表中查出用户数据所在位置,然后直接从目标位置中取出数据。
用专门的服务器存储静态内容,这个容易做到,比如专门的图片服务器。
"Use a share nothing architecture"这个比较费解了,字面上的意思是使用一个无共享的架构,其实就是解除架构上的依赖,类似我们写程序解耦合一样。
除图片外,所有的数据都存在数据库中,这里他们提到了PHP session,我们知道php的session是存储在服务器文件系统的,而且默认没有做hash目录,这就意味着如果你的网站访问量大,比如有10万个人在线,你的session目录下就有10万个文件,如果你的文件格式是NTFS(windows)或者Ext3(Linux),你要定位到某个文件,系统基本上会假死,有个好的建议是不要在一个文件夹下放超过1000个文件。使用默认的php session还有另外一个问题:服务器session同步,用户在A服务器登录后,session存储在A服务器上,然后应用跳转到B服务器,B服务器上的session没有同步就出问题了,当然解决这个问题的方法很多,比如统一存储session,所有服务器的session都存储在一个vfs设备上,或者通过cookie重新生成一个session在B服务器上
写一篇这样的文章非常的辛苦,第一部分就先写到这里,待续……
Posted in Arch, 默认分类 | 5 Comments »