World

mixi.jp:使用开源软件搭建的可扩展SNS网站

于敦德 2006-6-27 Mixi目前是日本排名第三的网站,全球排名42,主要提供SNS服务:日记,群组,站内消息,评论,相册等等,是日本最大的SNS网站。Mixi从2003年12月份开始开发,由现在它的CTO – Batara Kesuma一个人焊,焊了四个月,在2004年2月份开始上线运行。两个月后就注册了1w用户,日访问量60wPV。在随后的一年里,用户增长到了21w,第二年,增长到了200w。到今年四月份已经增长到370w注册用户,并且还在以每天1.5w人的注册量增长。这些用户中70%是活跃用户(活跃用户:三天内至少登录一次的用户),平均每个用户每周在线时间为将近3个半小时。 下面我们来看它的技术架构。Mixi采用开源软件作为架构的基础:Linux 2.6,Apache 2.0,MySQL,Perl 5.8,memcached,Squid等等。到目前为止已经有100多台MySQL数据库服务器,并且在以每月10多台的速度增长。Mixi的数据库连接方式采用的是每次查询都进行连接,而不是持久连接。数据库大多数是以InnoDB方式运行。Mixi解决扩展问题主要依赖于对数据库的切分。 首先进行垂直切分,按照表的内容将不同的表划分到不同的数据库中。然后是水平切分,根据用户的ID将不同用户的内容再划分的不同的数据库中,这是比较通常的做法,也很管用。划分的关键还是在于应用中的实现,需要将操作封装在在数据层,而尽量不影响业务层。当然完全不改变逻辑层也不可能,这时候最能检验以前的设计是否到位,如果以前设计的不错,那创建连接的时候传个表名,用户ID进去差不多就解决问题了,而以前如果sql代码到处飞,或者数据层封装的不太好的话那就累了。 这样做了以后并不能从根本上解决问题,尤其是对于像mixi这种SNS网站,页面上往往需要引用大量的用户信息,好友信息,图片,文章信息,跨表,跨库操作相当多。这个时候就需要发挥memcached的作用了,用大内存把这些不变的数据全都缓存起来,而当修改时就通知cache过期,这样应用层基本上就可以解决大部分问题了,只会有很小一部分请求穿透应用层,用到数据库。Mixi的经验是平均每个页面的加载时间在0.02秒左右(当然根据页面大小情况不尽相似),可以说明这种做法是行之有效的。Mixi一共在32台机器上有缓存服务器,每个Cache Server 2G内存,这些Cache Server与App Server装在一起。因为Cache Server对CPU消耗不大,而有了Cache Server的支援,App Server对内存要求也不是太高,所以可以和平共处,更有效的利用资源。 图片的处理就显得相对简单的多了。对于mixi而言,图像主要有两部分:一部分是经常要使用到的,像用户头像,群组的头像等等,大概有100多GB,它们被Squid和CDN所缓存,命中率相对比较高;另一部分是用户上传的大量照片,它们的个体访问量相对而言比较小,命中率也比较低,使用Cache不划算,所以对于这些照片的策略是直接在用户上传的时候分发到到图片存储服务器上,在用户访问的时候直接进行访问,当然图片的位置需要在数据库中进行记录,不然找不到放在哪台服务器上就郁闷了。…

World

FeedBurner:基于MySQL和JAVA的可扩展Web应用

于敦德 2006-6-27 FeedBurner(以下简称FB,呵呵)我想应该是大家耳熟能详的一个名字,在国内我们有一个同样的服务商,叫做FeedSky。在2004年7月份,FB的流量是300kbps,托管是5600个源,到2005年4月份,流量已经增长到5Mbps,托管了47700个源;到2005年9月份流量增长到20M,托管了109200个源,而到2006年4月份,流量已经到了115Mbps,270000个源,每天点击量一亿次。 FB的服务使用Java实现,使用了Mysql数据库。我们下面来看一下FB在发展的过程中碰到的问题,以及解决的方案。 在2004年8月份,FB的硬件设备包括3台Web服务器,3台应用服务器和两台数据库服务器,使用DNS轮循分布服务负载,将前端请求分布到三台Web服务器上。说实话,如果不考虑稳定性,给5600个源提供服务应该用不了这么多服务器。现在的问题是即使用了这么多服务器他们还是无法避免单点问题,单点问题将至少影响到1/3的用户。FB采用了监控的办法来解决,当监控到有问题出现时及时重启来避免更多用户受到影响。FB采用了Cacti(http://www.cacti.net)和Nagios(http://www.nagios.org)来做监控。 FB碰到的第二个问题是访问统计和管理。可以想象,每当我们在RSS阅读器里点击FB发布的内容,都需要做实时的统计,这个工作量是多么的巨大。大量写操作将导致系统的效率急剧下降,如果是Myisam表的话还会导致表的死锁。FB一方面采用异步写入机制,通过创建执行池来缓冲写操作;只对本日的数据进行实时统计,而以前的数据以统计结果形式存储,进而避免每次查看访问统计时的重复计算。所以每一天第一次访问统计信息时速度可能会慢,这个时候应该是FB在分析整理前一天的数据,而接下来的访问由于只针对当日数据进行分析,数据量小很多,当然也会快很多。FB的Presentation是这样写,但我发现好像我的FB里并没有今天实时的统计,也许是我观察的不够仔细-_-! 现在第三个问题出现了,由于大多数的操作都集中在主数据库上,数据库服务器的读写出现了冲突,前面提到过Myiasm类型的数据库在写入的时候会锁表,这样就导致了读写的冲突。在开始的时候由于读写操作比较少这个问题可能并不明显,但现在已经到了不能忽视的程度。解决方案是平衡读写的负载,以及扩展HibernateDaoSupport,区分只读与读写操作,以实现针对读写操作的不同处理。 现在是第四个问题:数据库全面负载过高。由于使用数据库做为缓存,同时数据库被所有的应用服务器共享,速度越来越慢,而这时数据库大小也到了Myisam的上限-4GB,FB的同学们自己都觉得自己有点懒。解决方案是使用内存做缓存,而非数据库,他们同样使用了我们前面推荐的memcached,同时他们还使用了Ehcache(http://ehcache.sourceforge.net/),一款基于Java的分布式缓存工具。 第五个问题:流行rss源带来大量重复请求,导致系统待处理请求的堆积。同时我们注意到在RSS源小图标有时候会显示有多少用户订阅了这一RSS源,这同样需要服务器去处理,而目前所有的订阅数都在同一时间进行计算,导致对系统资源的大量占用。解决方案,把计算时间错开,同时在晚间处理堆积下来的请求,但这仍然不够。 问题六:状态统计写入数据库又一次出问题了。越来越多的辅助数据(包括广告统计,文章点击统计,订阅统计)需要写入数据库,导致太多的写操作。解决方案:每天晚上处理完堆积下来的请求后对子表进行截断操作: – FLUSH TABLES; TRUNCATE TABLE ad_stats0; 这样的操作对Master数据库是成功的,但对Slave会失败,正确的截断子表方法是: – ALTER TABLE…

World

使用Red5和FFMpeg搭建在线Flash流媒体分享平台

最近视频的东西比较火,前些天我也稍微了解了一下使用开源软件建在线Flash流媒体播放平台的解决方案,还是有一些收获。 Red5是一款基于java的开源的Flash流媒体Server软件,可以作为取代Macromedia提供的商业版本FMS。Red5使用RSTP作为流媒体传输协议,内置了一些示例,这些示例实现了在线录制,flash流媒体播放,在线聊天,视频会议等一些基本的功能。由于系统本身是开源的,在碰到问题的时候也比较容易解决,大不了直接改代码,在成本方面也可以省下一笔不小的开销,为未来的功能扩展也提供了充分的空间。 如果仅仅是实现在线录制,在线播放,那么Red5也就差不多够了,但可能我们有时候还需要用户上传自己拍摄的视频文件,而要把这些视频文件转成可播放的flv文件就需要视频编码软件了。FFMpeg提供了录制,播放,视频流处理的完整解决方案。它自身也带了一个基于HTTP的流媒体广播程序以及其它几个实用的程序,但我们的重点还是它的视频转换程序,似乎Google Video也是用的它的程序作为视频转换工具。 我用FFMpeg转了几个视频,效果还可以,在声音上碰到了一些问题,在不添加参数的情况下,有一部分视频的声音会有问题,有的视频无论怎么添加参数,都出不来声音,报错提示的是不支持所带的声音采样格式,只支持几种固定的格式,我看了一下代码,确实是这样子,但理论上应该是能够解决的。FFMpeg自带的libavcodec是一套很牛的编码库,为了保证质量和性能,里面的很多codec都是从头开发的。 这两个加起来,实现一些简单的在线视频功能就差不多了。 PS:今天刚看到古永锵也开始做小视频分享网站:优酷。

World

使用开源软件,设计高性能可扩展网站

2006-6-17 于敦德 上次我们以LiveJournal为例详细分析了一个小网站在一步一步的发展成为大规模的网站中性能优化的方案,以解决在发展中由于负载增长而引起的性能问题,同时在设计网站架构的时候就从根本上避免或者解决这些问题。 今天我们来看一下在网站的设计上一些通常使用的解决大规模访问,高负载的方法。我们将主要涉及到以下几方面: 1、 前端负载 2、 业务逻辑层 3、 数据层 在LJ性能优化文章中我们提到对服务器分组是解决负载问题,实现无限扩展的解决方案。通常中我们会采用类似LDAP的方案来解决,这在邮件的服务器以及个人网站,博客的应用中都有使用,在Windows下面有类似的Active Directory解决方案。有的应用(例如博客或者个人网页)会要求在二级域名解析的时候就将用户定位到所属的服务器群组,这个时候请求还没到应用上面,我们需要在DNS里解决这个问题。这个时候可以用到一款软件bind dlz,这是bind的一个插件,用于取代bind的文本解析配置文件。它支持包括LDAP,BDB在内的多种数据存储方式,可以比较好的解决这个问题。 另外一种涉及到DNS的问题就是目前普遍存在的南北互联互通的问题,通过bind9内置的视图功能可以根据不同的IP来源解析出不同的结果,从而将南方的用户解析到南方的服务器,北方的用户解析到北方的服务器。这个过程中会碰到两个问题,一是取得南北IP的分布列表,二是保证南北服务器之间的通讯顺畅。第一个问题有个笨办法解决,从日志里取出所有的访问者IP,写一个脚本,从南北的服务器分别ping回去,然后分析结果,可以得到一个大致准确的列表,当然最好的办法还是直到从运营商那里拿到这份列表(update:参见这篇文章)。后一个问题解决办法比较多,最好的办法就是租用双线机房,同一台机器,双IP,南北同时接入,差一些的办法就是南北各自找机房,通过大量的测试找出中间通讯顺畅的两个机房,后一种通常来说成本较低,但效果较差,维护不便。 另外DNS负载均衡也是广泛使用的一种负载均衡方法,通过并列的多条A记录将访问随即的分布到多台前端服务器上,这种通常使用在静态页面居多的应用上,几大门户内容部分的前端很多都是用的这种方法。 用户被定位到正确的服务器群组后,应用程序就接手用户的请求,并开始沿着定义好的业务逻辑进行处理。这些请求主要包括两类静态文件(图片,js脚本,css等),动态请求。 静态请求一般使用squid进行缓存处理,可以根据应用的规模采用不同的缓存配置方案,可以是一级缓存,也可以是多级缓存,一般情况下cache的命中率可以达到70%左右,能够比较有效的提升服务器处理能力。Apache的deflate模块可以压缩传输数据,提高速度,2.0版本以后的cache模块也内置实现磁盘和内存的缓存,而不必要一定做反向代理。 动态请求目前一般有两种处理方式,一种是静态化,在页面发生变化时重新静态页面,现在大量的CMS,BBS都采用这种方案,加上cache,可以提供较快的访问速度。这种通常是写操作较少的应用比较适合的解决方案。 另一种解决办法是动态缓存,所有的访问都仍然通过应用处理,只是应用处理的时候会更多的使用内存,而不是数据库。通常访问数据库的操作是极慢的,而访问内存的操作很快,至少是一个数量级的差距,使用memcached可以实现这一解决方案,做的好的memcache甚至可以达到90%以上的缓存命中率。10年前我用的还是2M的内存,那时的一本杂事上曾经风趣的描述一对父子的对话: 儿子:爸爸,我想要1G的内存。…