YouTube的成长速度惊人,目前每天视频访问量已达1亿,但站点维护人员很少。他们是如何管理,以实现如此强大供应能力的?被Google收购后,又在走什么样的发展道路呢?
平台
l Apache
l Python
l Linux (SuSe版本)
l MySQL
l psyco(python->C动态编译器)
l lighttpd(取代Apache作为视频服务器)
统计数据
l 每天高达1亿的视频访问量。
l 创建于2005年2月。
l 2006年3月,每日视频访问量达到3千万。
l 2006年7月,每日视频访问量达到1亿。
l 2个系统管理员,2个系统扩展架构师。
l 2个产品功能开发人员,2个网络工程师,1个DBA。
性能监控手段
网站维护人员每天多次重复的工作,类似于执行下面这段代码。
while (true)
{
identify_and_fix_bottlenecks();
drink();
sleep();
notice_new_bottleneck();
}
Web服务器
l NetScalar用于实现负载均衡和对静态内容的缓存。
l Apache运行于mod_fast_cgi模式。
l 一台Python应用服务器专门负责Web请求的路由。
l 应用服务器与各个数据库和其他类型信息源建立会话,取得所需数据并生成HTML页面。
l 通过增加服务器,一般就可以实现对Web层的扩展。
l Python代码的效率一般不是瓶颈所在,真正瓶颈在于RPC请求。
l Python应用的开发和发布快速灵活,这是他们能够应对激烈竞争的重要保证。
l 正常情况下,能将每个页面的响应时间控制在100ms以内。
l 利用psyco(python->C的动态编译器),通过JIT编译方法实现内部循环的优化。
l 在CPU高敏感的活动(如加密)中使用C扩展。
l 预生成某些HTML页面并缓存。
l 在数据库中实现行级缓存。
l 对Python结果对象缓存。
l 预先计算某些数据,并发送至对应应用,以形成本地缓存。这项策略目前还未大规模运用。不需要每个应用服务器都花很多时间将预先计算,并将结果数据发送到所有服务器。有一个代理机专门负责此项工作——监控数据的变化情况,预先计算并发送。
视频服务
l 成本,包括带宽、硬件购置和电力的消耗。
l 每段视频均通过刀片群集(mini-cluster)服务器管理,也就是说由多个机器联合提供视频内容服务。
l 刀片群集管理的优势:
n 多个磁盘提供内容服务,意味着更快的速度。
n 提供了动态余量。一台机器停止服务,其他可以接管。
n 实现了在线备份。
l 使用lighttpd作为视频的Web服务器:
n Apache的成本太高。
n 使用epoll同时操作多个fds(文件描述符)。
n 从单进程切换到多进程,以处理更多连接。
l 将频繁访问的内容转移到CDN(content delivery network):
n CDN将内容复制到多个源,因此对用户来说,获取数据时可以选择最优路径。
n CDN服务器主要依靠内存提供服务,否则因访问频繁,可能引起抖动。
l 低访问量的内容(每天1-20的访问量),YouTube服务器以colo模式管理。
n 长尾效应。单个视频的访问量不高,但大量视频合起来就不一样了。各磁盘块被访问到的概率是随机的。
n 在这种情况下,花费了大量投入的缓存,作用并不大。这个问题是当前研究的一个热点。如果你有一个长尾型的产品,请记住缓存不见得就是解决性能问题的救世主。
n 优化调整RAID控制器,在底层策略上下功夫。
n 调整每台服务器上的内存,不要太大也不要太小。
视频服务中的几个关键点
l 整体方案力求简洁、廉价。
l 网络路径保持最短,不要在内容和终端用户间部署太多设备。路由器、交换机等可能承受不了这么高的负载。
l 尽量采用普通硬件。高档硬件的支撑设备很昂贵,实际中往往发现它们的作用并不大。
l 使用简单、通用的工具。YouTube优先考虑Linux自带的大多数工具。
l 正确处理随机寻道问题(采用SATA、优化调整等)。
视频截图的处理
l 实现视频截图和缩略图的高效访问,有着惊人的难度。
l 如果每视频平均4个缩略图,那么总图量是非常庞大的。
l 缩略图存储在有限几台机器上。
l 大量小型对象服务中存在的难点问题:
n 磁盘寻道频繁,操作系统级inode(译者注:Linux/Unix系统中记录文件信息的对象)缓存和页缓存多。
n 每个目录受到最大文件数限制。Ext3文件系统可管理的目录层级非常多,即便依托2.6内核将大目录处理性能提高100倍左右,在文件系统中存储大量文件情况下,仍然不是一个值得称许的解决策略。
n 平均含60个缩略图的页面的访问量很大。
n 在如此高负载条件下,Apache的性能急剧下降。
n 使用squid(反向代理)作为Apache的前端,能起到一定作用。但随着负载的上升,性能最终会呈下降趋势——处理能力由原来的300个/s降为20个/s。
n 尝试使用lighttpd。这是一个单进程且单线程的应用,每个进程拥有独立缓存。为了提高性能,需要运行多个进程实例。如此一来,造成了资源浪费和性能限制等问题。
n 大量图片需要处理的情况下,向系统新增一台机器,需要24个小时。
n 重启机器后,系统需要花费6-10小时,来将内容从磁盘载入缓存。
l 为了解决这些问题,他们使用了Google的分布式数据存储策略——BigTable:
n 将文件拢在一起,避免了小文件问题。
n 速度快;即使运行在不可靠网络上,其错误率也是可以容忍的。
n 未知风险小,因为它使用了分布式的多级缓存。缓存工作于colo结构上。
数据库[DSJ2]
l 早期:
n 使用MySQL存储用户、标签和详细描述等原数据。
n 数据存储在挂10磁盘、10卷的单片RAID上。
n 租借硬件。负载上升,添加新设备时他们需要数天时间。
n 和其他很多系统一样,他们走过了这样一段历史:单服务器,主从服务器(单台主服务器,依靠多台从服务器实现读数据的负载均衡),数据库分割(逐渐稳定于分割模式)。
n 存在数据复制延迟的问题。主服务器是多线程的,硬件条件好,性能高;而从服务器运行于单线程模式,且硬件条件差一些。数据从主服务器到从服务器的复制是异步的,因此从服务器上的数据往往严重滞后于主服务器。
n 数据更新后,缓存将被清除,需从I/O更慢的磁盘读取,从而造成复制更为缓慢。
n 在这种以数据复制为中心的架构下,稍微提升写性能,都必须付出巨大成本。
n 他们的解决办法之一是将数据分割到两个不同群集,从而分解访问压力:一个视频池和一个普通群集。这个解决方案的出发点是:访问者最想看到的是视频,因此应该为这些功能分配最多资源;而YouTube社交功能是次重要的,因此做次优配置。
l 后来:
n 继续执行数据库分割策略。
n 按用户划分数据。
n 数据的读、写操作分离。
n 改进了缓存数据定位策略,减少I/O。
n 所需硬件减少了30%。
n 数据复制延迟降为0。
n 现在几乎能做到对数据库任意扩展。
l 开始的时候使用托管机房。除非事先签订了协议,不能自行扩展硬件和网络系统。因此,他们后来选择了colo,可以完全按照自己的设计要求部署系统。
l 使用5/6个数据中心,外加CDN。视频的来源可以是任何一个数据中心,而非就近选择等模式。若访问频度很高,则移至CDN。
l 视频的访问性能依赖于带宽,而不是其他因素。对于图片,其他因素的影响就很大(例如页面平均图片数)。
l 利用BigTable将图片复制到各个数据中心。
经验教训
l 敢于坚持。 局部创新和一些有一定风险的策略,能够解决短期问题。如果一直坚持下去,就一定能找到长期解决方案。
l 确定事情的优先级。找出服务中的关键部分,优先为其配置资源、投入力量。
l 学会选择与合作。不要害怕将项目的关键部分外包。YouTube使用CDN向广大用户提供内容。如果完全依靠自己建设这样一个网络,需要花费的成本和时间都是惊人的。在你的系统中,应该可以存在这类同样的部件。
l 一切从简! 简单,将保证系统具有良好的可重构性以及对问题的快速响应。没有人真正知道怎么样才算是简单,如果在需要做出改变时,相关人员没有产生畏难情绪,就说明达到了简单的目标。
l 数据分割。数据分割策略将实现对磁盘、CPU、内存和IO实体和指标的优化配置,改善的不仅仅是写数据的性能。
l 对瓶颈资源做持续改善:
n 软件层:数据库、缓存
n 操作系统层:磁盘I/O
n 硬件层:内存、RAID
l 团队是成功的基础。在一个有良好纪律的团队中,所有成员都能够准确把握整个系统,了解深层问题。拥有一个好的团队,将无往而不胜。