架构设计比较 youtubetwitter应用服务器
程序员文章站
2022-03-05 17:01:54
...
本文是整理的关于优酷、YouTube、Twitter及JustinTV几个视频网站的架构或笔记,对于不管是视频网站、门户网站或者其它的网站,在架构上都有一定的参考意义,毕竟成功者的背后总有值得学习的地方,虽然有些文章的发表时间有点久了,但是看看对开阔视野还是有帮助的。
优酷视频网站架构
一、网站基本数据概览
据2010年统计,优酷网日均独立访问人数(uv)达到了8900万,日均访问量(pv)更是达到了17亿,优酷凭借这一数据成为google榜单中国内视频网站排名最高的厂商。
硬件方面,优酷网引进的戴尔服务器主要以 PowerEdge 1950与PowerEdge 860为主,存储阵列以戴尔MD1000为主,2007的数据表明,优酷网已有1000多台服务器遍布在全国各大省市,现在应该更多了吧。
二、网站前端框架
从一开始,优酷网就自建了一套CMS来解决前端的页面显示,各个模块之间分离得比较恰当,前端可扩展性很好,UI的分离,让开发与维护变得十分简单和灵活,下图是优酷前端的模块调用关系:
这样,就根据module、method及params来确定调用相对独立的模块,显得非常简洁。下面附一张优酷的前端局部架构图:
三、数据库架构
应该说优酷的数据库架构也是经历了许多波折,从一开始的单台MySQL服务器(Just Running)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库,这一系列过程只有经历过才会有更深的体会吧,就像MySpace的架构经历一样,架构也是一步步慢慢成长和成熟的。
1、简单的MySQL主从复制:
MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其原来图如下:
其主从复制的过程如下图所示:
但是,主从复制也带来其他一系列性能瓶颈问题:
-写入无法扩展
-写入无法缓存
-复制延时
-锁表率上升
-表变大,缓存率下降
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
2、MySQL垂直分区
如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:
然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平sharding呢?
3、MySQL水平分片(Sharding)
这是一个非常好的思路,将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:
如何来确定某个用户所在的shard呢,可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:
但是,优酷是如何解决跨shard的查询呢,这个是个难点,据介绍优酷是尽量不跨shard查询,实在不行通过多维分片索引、分布式搜索引擎,下策是分布式数据库查询(这个非常麻烦而且耗性能)
四、缓存策略
貌似大的系统都对“缓存”情有独钟,从http缓存到memcached内存数据缓存,但优酷表示没有用内存缓存,理由如下:
避免内存拷贝,避免内存锁
如接到老大哥通知要把某个视频撤下来,如果在缓存里是比较麻烦的
而且Squid 的 write() 用户进程空间有消耗,Lighttpd 1.5 的 AIO(异步I/O) 读取文件到用户内存导致效率也比较低下。
但为何我们访问优酷会如此流畅,与土豆相比优酷的视频加载速度略胜一筹?这个要归功于优酷建立的比较完善的内容分发网络(CDN),它通过多种方式保证分布在全国各地的用户进行就近访问——用户点击视频请求后,优酷网将根据用户所处地区位置,将离用户最近、服务状况最好的视频服务器地址传送给用户,从而保证用户可以得到快速的视频体验。这就是CDN带来的优势,就近访问,有关CDN的更多内容,请大家Google一下。
这是一个完整的PDF:http://www.blogkid.net/qconppt/youkuqiudanqconbeijing-090423080809-phpapp01.pdf
转自:http://www.kaiyuanba.cn/html/1/131/147/7541.htm
YouTube网站架构
YouTube发展迅速,每天超过1亿的视频点击量,但只有很少人在维护站点和确保伸缩性。这点和PlentyOfFish类似,少数人维护庞大系统。是什么原因呢?放心绝对不是靠人品,也不是靠寂寞,下面就来看看YouTube的整体技术架构吧。
平台
1、Apache
2、Python
3、Linux(SuSe)
4、MySQL
5、psyco,一个动态的Python到C的编译器
6、lighttpd代替Apache做视频查看
状态
1、支持每天超过1亿的视频点击量
2、成立于2005年2月
3、于2006年3月达到每天3千万的视频点击量
4、于2006年7月达到每天1亿的视频点击量
5、2个系统管理员,2个伸缩性软件架构师
6、2个软件开发工程师,2个网络工程师,1个DBA
Web服务器
1,NetScaler用于负载均衡和静态内容缓存
2,使用mod_fast_cgi运行Apache
3,使用一个Python应用服务器来处理请求的路由
4,应用服务器与多个数据库和其他信息源交互来获取数据和格式化html页面
5,一般可以通过添加更多的机器来在Web层提高伸缩性
6,Python的Web层代码通常不是性能瓶颈,大部分时间阻塞在RPC
7,Python允许快速而灵活的开发和部署
8,通常每个页面服务少于100毫秒的时间
9,使用psyco(一个类似于JIT编译器的动态的Python到C的编译器)来优化内部循环
10,对于像加密等密集型CPU活动,使用C扩展
11,对于一些开销昂贵的块使用预先生成并缓存的html
12,数据库里使用行级缓存
13,缓存完整的Python对象
14,有些数据被计算出来并发送给各个程序,所以这些值缓存在本地内存中。这是个使用不当的策略。
应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改,预计算,然后发送。
视频服务
1,花费包括带宽,硬件和能源消耗
2,每个视频由一个迷你集群来host,每个视频被超过一台机器持有
3,使用一个集群意味着:
-更多的硬盘来持有内容意味着更快的速度
-failover。如果一台机器出故障了,另外的机器可以继续服务
-在线备份
4,使用lighttpd作为Web服务器来提供视频服务:
-Apache开销太大
-使用epoll来等待多个fds
-从单进程配置转变为多进程配置来处理更多的连接
5,大部分流行的内容移到CDN:
-CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
-CDN机器经常内存不足,因为内容太流行以致很少有内容进出内存的颠簸
6,不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器
-长尾效应。一个视频可以有多个播放,但是许多视频正在播放。随机硬盘块被访问
-在这种情况下缓存不会很好,所以花钱在更多的缓存上可能没太大意义。
-调节RAID控制并注意其他低级问题
-调节每台机器上的内存,不要太多也不要太少
视频服务关键点
1,保持简单和廉价
2,保持简单网络路径,在内容和用户间不要有太多设备
3,使用常用硬件,昂贵的硬件很难找到帮助文档
4,使用简单而常见的工具,使用构建在Linux里或之上的大部分工具
5,很好的处理随机查找(SATA,tweaks)
缩略图服务
1,做到高效令人惊奇的难
2,每个视频大概4张缩略图,所以缩略图比视频多很多
3,缩略图仅仅host在几个机器上
4,持有一些小东西所遇到的问题:
-OS级别的大量的硬盘查找和inode和页面缓存问题
-单目录文件限制,特别是Ext3,后来移到多分层的结构。内核2.6的最近改进可能让 Ext3允许大目录,但在一个文件系统里存储大量文件不是个好主意
-每秒大量的请求,因为Web页面可能在页面上显示60个缩略图
-在这种高负载下Apache表现的非常糟糕
-在Apache前端使用squid,这种方式工作了一段时间,但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个
-尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题,因为它们各自保持自己单独的缓存
-如此多的图片以致一台新机器只能接管24小时
-重启机器需要6-10小时来缓存
5,为了解决所有这些问题YouTube开始使用Google的BigTable,一个分布式数据存储:
-避免小文件问题,因为它将文件收集到一起
-快,错误容忍
-更低的延迟,因为它使用分布式多级缓存,该缓存与多个不同collocation站点工作
-更多信息参考Google Architecture,GoogleTalk Architecture和BigTable
数据库
1,早期
-使用MySQL来存储元数据,如用户,tags和描述
-使用一整个10硬盘的RAID 10来存储数据
-依赖于信用卡所以YouTube租用硬件
-YouTube经过一个常见的革命:单服务器,然后单master和多read slaves,然后数据库分区,然后sharding方式
-痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作,slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以slaves会远远落后于master
-更新引起缓存失效,硬盘的慢I/O导致慢备份
-使用备份架构需要花费大量的money来获得增加的写性能
-YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群
2,后期
-数据库分区
-分成shards,不同的用户指定到不同的shards
-扩散读写
-更好的缓存位置意味着更少的IO
-导致硬件减少30%
-备份延迟降低到0
-现在可以任意提升数据库的伸缩性
数据中心策略
1,依赖于信用卡,所以最初只能使用受管主机提供商
2,受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议
3,YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约
4,使用5到6个数据中心加CDN
5,视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN
6,依赖于视频带宽而不是真正的延迟。可以来自任何colo
7,图片延迟很严重,特别是当一个页面有60张图片时
8,使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的
学到的东西
1,Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案
2,Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别
3,Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money
4,Keep it simple!简单允许你更快的重新架构来回应问题
5,Shard。Sharding帮助隔离存储,CPU,内存和IO,不仅仅是获得更多的写性能
6,Constant iteration on bottlenecks:
-软件:DB,缓存
-OS:硬盘I/O
-硬件:内存,RAID
7,You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队,如安装打印机,安装机器,安装网络等等的人。
With a good team all things are possible。
转自:http://www.kaiyuanba.cn/html/1/131/147/7540.htm
Twitter网站架构
一、twitter网站基本情况概览
截至2011年4月,twitter的注册用户约为1.75亿,并以每天300000的新用户注册数增长,但是其真正的活跃用户远远小于这个数目,大部分注册用户都是没有关注者或没有关注别人的,这也是与facebook的6亿活跃用户不能相提并论的。
twitter每月有180万独立访问用户数,并且75%的流量来自twitter.com以外的网站。每天通过API有30亿次请求,每天平均产生5500次tweet,37%活跃用户为手机用户,约60%的tweet来自第三方的应用。
平台:Ruby on Rails 、Erlang 、MySQL 、Mongrel 、Munin 、Nagios 、Google Analytics 、AWStats 、Memcached
下图是twitter的整体架构设计图:
二、twitter的平台
twitter平台大致由twitter.com、手机以及第三方应用构成,如下图所示:
其中流量主要以手机和第三方为主要来源。
Ruby on Rails:web应用程序的框架
Erlang:通用的面向并发的编程语言,开源项目地址:http://www.erlang.org/
AWStats:实时日志分析系统:开源项目地址:http://awstats.sourceforge.NET/
Memcached:分布式内存缓存组建
Starling:Ruby开发的轻量级消息队列
Varnish:高性能开源HTTP加速器
Kestrel:Scala编写的消息中间件,开源项目地址:http://github.com/robey/kestrel
Comet Server:Comet是一种ajax长连接技术,利用Comet可以实现服务器主动向web浏览器推送数据,从而避免客户端的轮询带来的性能损失。
libmemcached:一个memcached客户端
使用mysql数据库服务器
Mongrel:Ruby的http服务器,专门应用于rails,开源项目地址:http://rubyforge.org/projects/mongrel/
Munin:服务端监控程序,项目地址:http://munin-monitoring.org/
Nagios:网络监控系统,项目地址:http://www.nagios.org/
三、缓存
讲着讲着就又说到缓存了,确实,缓存在大型web项目中起到了举足轻重的作用,毕竟数据越靠近CPU存取速度越快。下图是twitter的缓存架构图:
大量使用memcached作缓存
例如,如果获得一个count非常慢,你可以将count在1毫秒内扔入memcached
获取朋友的状态是很复杂的,这有安全等其他问题,所以朋友的状态更新后扔在缓存里而不是做一个查询。不会接触到数据库
ActiveRecord对象很大所以没有被缓存。Twitter将critical的属性存储在一个哈希里并且当访问时迟加载
90%的请求为API请求。所以在前端不做任何page和fragment缓存。页面非常时间敏感所以效率不高,但Twitter缓存了API请求
在memcached缓存策略中,又有所改进,如下所述:
1、创建一个直写式向量缓存Vector Cache,包含了一个tweet ID的数组,tweet ID是序列化的64位整数,命中率是99%
2、加入一个直写式行缓存Row Cache,它包含了数据库记录:用户和tweets。这一缓存有着95%的命中率。
3、引入了一个直读式的碎片缓存Fragmeng Cache,它包含了通过API客户端访问到的sweets序列化版本,这些sweets可以被打包成json、xml或者Atom格式,同样也有着95%的命中率。
4、为页面缓存创建一个单独的缓存池Page Cache。该页面缓存池使用了一个分代的键模式,而不是直接的实效。
四、消息队列
大量使用消息。生产者生产消息并放入队列,然后分发给消费者。Twitter主要的功能是作为不同形式(SMS,Web,IM等等)之间的消息桥
使用DRb,这意味着分布式Ruby。有一个库允许你通过TCP/IP从远程Ruby对象发送和接收消息,但是它有点脆弱
移到Rinda,它是使用tuplespace模型的一个分享队列,但是队列是持久的,当失败时消息会丢失
尝试了Erlang
移到Starling,用Ruby写的一个分布式队列
分布式队列通过将它们写入硬盘用来挽救系统崩溃。其他大型网站也使用这种简单的方式
五、总结
1、数据库一定要进行合理索引
2、要尽可能快的认知你的系统,这就要你能灵活地运用各种工具了
3、缓存,缓存,还是缓存,缓存一切可以缓存的,让你的应用飞起来。
部分转自:http://timyang.net/architecture/twitter-cache-architecture/
这里还有一份根据英文翻译的:http://hideto.iteye.com/blog/130044
JustinTV网站架构
Justin.TV每月有3000万个独立访问量,在游戏视频上传领域打败了YouTube ,他们每天每分钟新增30个小时的视频,而YouTube只有23。
下面从Justin.TV的实时视频系统使用到的平台,他们的架构细节,从他们身上应该学到的东西等几个方面逐一展开。
使用到的平台
Twice —— 代理服务系统,主要用缓冲优化应用服务器负载
XFS —— 文件系统
HAProxy —— 用于TCP/HTTP负载平衡
LVS stack and Idirectord —— 高可靠性
Ruby on Rails —— 应用服务器系统
Nginx —— web服务器系统
PostgreSQL —— 数据库,用于用户和meta数据
MongoDB —— 数据库,用于内部分析
MemcachedDB —— 数据库,用于存放经常要修改的数据
Syslog-ng —— 日志服务系统
RabitMQ —— job系统
Puppet —— 创建服务
Git —— 源代码管理
Wowza —— Flash/H.264视频服务器和许多Java写的custome modules
Usher —— 播放视频流的逻辑控制服务器
S3 —— 用于存储小型镜像
Justin.TV的一些统计数据
有覆盖全美的4个数据中心
在任何时候都有2000多个同时流入的数据流
每天每分钟新增30个小时的视频
每月有3000万个独立访问量(不计同一用户多次访问)
每秒实时的网络流量在45G左右
实时视频结构详述
实时视频结构
1.使用了P2P和CDN
一般人认为,只需要不断提高带宽,把传来的数据都放入内存,不断的接收数据流就可以了,事实并非如此。实时视频要求不能打断,这就意味着你不可以超负荷的使用带宽。YouTube只需要让播放器缓冲一下,就可以用8G的带宽解决10G通道的需求,但在实时视频里,你不能缓冲,如果在信道上的流量超过了它的传输能力,哪怕只是一瞬间,那么所有的正在看的用户在那一刻都会卡。如果你在它的极限能力上再加入了一点儿负载,所有人立刻就会进入缓冲状态。
Justin.TV使用了点对点的结构来解决这个问题,当然他们也有更好的解决办法,CDN(内容分发网络)便是之一。当用户的流量负载超过Justin.TV的负载能力时,Justin.TV便很巧妙的将超标流量引入到一个CDN中去,Usher控制着这个处理逻辑,一旦接到了超标用户的负载请求,Usher便立刻将这些新用户转发到CDN中去。
2.100%可用时间和维护的矛盾
实时视频构建的系统既要保证100%的可用时间,又要保证机器可以进行维护。与一般网站不同,一般网站维护时出现的问题只有少数人会发现、关注,而实时视频网站不同,用户很快就会发现维护时带来的任何问题,并且互相传播的非常快。这就使得没有什么问题可以隐瞒用户,面对现在用户的挑剔,你必须避免维护时出问题。对一个服务器维护时,你不能主动结束用户的进程,必须等待所有在这个服务器上的用户自己结束服务才能开始,而这个过程往往非常缓慢。
3.Usher与负载均衡
Justin.TV遇到的最大的麻烦是即时拥塞,当大量的用户同时看同一个栏目的时候,便会突然产生突发网络拥塞。他们开发了一个实时的服务器和数据中心调度系统,它就是Usher。
Justin.TV的系统在突发的高峰拥塞上做了很多。他们的网络每秒可以处理大量的链入连接。用户也参与了负载均衡,这也是Justin.TV需要用户使用Justin.TV自己的播放器的原因之一。至于TCP,由于它的典型处理速度就是百kbps级的,所以也不用对TCP协议做什么修改。
相对于他们的流量,他们的视频服务器看来来有些少,原因是他们可以使用Usher把每个视频服务器的性能发挥到最好,负载均衡可以确保流量从不会超过他们的负载极限。负载大部分是在内存中,因此这个系统可以让网络的速度发挥到极限。服务器他们是一次从Rackable(SGI服务器的一个系列)买了一整套,他们做的仅仅是从所有预置的里面做了下挑选。
Usher是Justin.TV开发的一款定制化软件,用来管理负载平衡,用户认证和其他一些流播放的处理逻辑。Usher通过计算出每个流需要多少台服务器提供支持,从而分配资源,保证系统处于最优状态,这是他们的系统和别家不同之处。Usher通常会从下面几个指标计算、衡量某个流媒体所需要的服务器:
每个数据中心的负载是多少
每个服务器的负载是多少
延迟优化的角度
当前这个流可用的服务器列表
用户的国家(通过IP地址获得)
用户是否有可用的对等网(通过在路由数据库中查询IP地址获得)
请求来自于哪个数据中心
Usher使用这些指标便可以在服务净成本上来优化,把服务放在比较空闲的服务器上,或者把服务放在离用户较近的服务器上,从而给用户带来更低的延迟和更好的表现。Usher有很多个可以选择的模式从而达到很细的控制粒度。
Justin.TV系统的每个服务器都可以做边缘服务器,直接为用户输出视频流,同时每个服务器也可以做源服务器,为其他服务器传递视频流。这个特性,使得视频流的负载结构成了动态的,经常改变的一个过程。
4.服务器形成了加权树
服务器之间由视频流的拷贝而产生的联系和加权树非常相似。数据流的数量经常被系统取样、统计,如果观看某个视频流的用户数量飞速上涨,系统便将其拷贝很多份到一些其他的服务器上去。这个过程反复执行,最终就形成了一个树状的结构,最终会将网络中所有的服务器都画在里面。Justin.TV的视频流从源服务器出发,被拷贝到其他服务器,或者拷贝到用户的整个过程中,都处于内存中,没有硬盘路径的概念。
5.RTMP和HTTP
Justin.TV尽可能的使用了Flash,因为它使用RTMP协议,对每个视频流,系统都有一个独立的Session去维护它。由于使用这个协议,成本就相当高。由于ISP不支持下载流,因而无法使用多路广播和P2P技术。Justin.TV确实想过用多路广播在内部服务器之间拷贝数据流,然而由于他们的系统控制覆盖整个网络,而且内部有大量的很便宜的带宽可以使用,这样使用多路广播的技术就并没有产生多少效益。同时,由于他们的优化算法是将每个服务器上的流数都最小化,这就使得在很细的力度上做些事情会非常麻烦,甚至超过了他们能得到收益。
Justin.TV的Usher使用HTTP请求去控制某个服务器负载哪个视频流,从而控制了服务的拓扑结构。Justin.TV在流数据上使用HTTP,但存在的一个问题是它没有延迟和实时方面的性能。有些人说实时的定义就是5-30秒,然而,面对数千人做实时视频的时候这显然不行,因为他们还需要实时的讨论,交流,这意味着延迟不能高于1/4秒。
6.从AWS到自己的数据中心
起初Justin.TV使用AWS,后来迁移到Akamai(云服务供应商),最后到了自己的数据中心。
离开AWS到Akamai的原因有:1,成本;2,网速不能满足他们的需求。视频直播对带宽非常敏感,因此有一个快速的,可靠的,稳定的和低延迟的网络非常关键。使用AWS时,你不能控制这些,它是一个共享的网络,常常超负载,AWS的网速不会比300Mbps更快。他们对动态范围改动和云API很重视,然而在性能和成本问题上没有做什么。
3年前,Justin.TV计算他们每个用户的成本,CDN是$0.135,AWS是0.0074,Datacenter是$0.001如今,他们的CDN成本降低了,但他们的数据中心的成本却仍然一样。
拥有多个数据中心的关键是为了能够接近所有的主要交换节点,他们选择国内最好的位置从而使得他们为国内最多的节点提供了入口,而且节约了成本,构建了这些数据中心后,他们就直接连入了这些其他的网络,从而就省去了之前处理这些中转流量的费用,还提高了性能,他们直接连入了他们所谓的"eyeball"网络,这个网络中包含了大量的cable/DSL用户,和"content"网络连接有些类似,Justin.TV的"eyeball"连接的流量主要来自终端用户,在大多数情况下,这些都是免费的,不用任何花一分钱,要做的就是连进来就行。Justin.TV有一个主干网,用于在不同的数据中心传输视频流,因为要到一个可用节点的选拔过程是去找愿意和你做对等节点的过程,这通常是很困难的。
7.存储
视频流不是从磁盘形成,而是要存到磁盘上去。源服务器将一个传入的视频流在本地磁盘上复制一份,之后便将这个文件上传到长期存储器上,视频的每一秒都被录下来并且存档了。
存储设备和YouTube类似,就是一个磁盘库,使用XFS文件系统。这个结构用于记录通过服务器传播的广播。默认的视频流是保存7天,用户可以手动的设置,甚至你可以保存到永远(如果公司没有倒闭的话)。
8.实时转码
增加了实时的转码功能,可以将任何一种流式数据转化为传输层数据或者是代码,并且可以用新的格式将它重新编为流媒体。有一个转码集群,用来处理转换工作转,换的会话使用job系统进行管理。如果需要的转码服务超过了集群的处理能力,那所有的服务器都可以用作转码服务器。
Web结构
Web 结构
1.Justin.TV前端使用Ruby on Rails。
2.用Twice做缓存
系统个每个页面都使用了他们自己定制的Twice缓存系统,Twice扮演的角色是轻量级反向代理服务器和模板系统的合并角色。思路是对每一个用户,缓存每一个页面,然后将每个页面的更新再并入其中。使用Twice以后,每个进程每秒可以处理150条请求,同时可以在后台处理10-20个请求,这就扩展了7-10倍之前的服务器可以处理的网页的数量。大部分动态网页访问都在5ms以内。Twice有一个插件结构,所以它可以支持应用程序的一个特点,例如添加地理信息。
不用触及应用服务器,便能自动缓存像用户名一样的数据。
Twice是一个为Justin.TV的需求和环境而定制化开发的。如果开发一个新的Rails应用,使用Varnish或许是一个更好的主意。
3.网络流量由一个数据中心服务,其他的数据中心为视频服务。
4.Justin.TV 对所有的操作都做了监控.每一个点击,查看页面和每一个动作都被记录下来,这样就可以不断提高服务。前端,网络呼叫或者一个应用服务器的日志消息都被转换成系统日志消息,通过syslog-ngto转发。他们扫描所有的数据,将它装入MongoDB,使用Mongo执行查询。
5.Justin.TV的API来自网站的应用服务器,它使用相同缓冲引擎,通过扩展网站来扩展他们的API。
6.PostegreSQL是他们最主要的数据库。结构是简单的主从结构,由一个主机和多个从属读数据库组成。
由于他们网站的类型,他们不需要许多写数据库,缓冲系统控制着这些读数据库。他们发现PostgreSQL并不擅长处理写操作,因此Justin.TV就是用MemcachedDB去处理那些经常要写的数据,例如计数器。
7.他们有一个聊天服务器集群,专门用来为聊天功能服务。如果用户进入了一个频道,用户就会有5个不同的聊天服务器为他服务,扩展聊天功能要比扩展视频功能简单的多,用户可以被划分到不同的房间,这些房间又由不同的服务器负载。他们也不会让100,000个人同时在一起聊天。他们限制每个房间200人,这样就可以在一个小组里进行更有意义的交谈。这同时对扩展也很有帮助,这真的是一个很聪明的策略。
8.AWS用于存储文档镜像。他们没有为存储许多小镜像而开发专门的系统,他们使用了S3。它非常方便,而且很便宜,这就不用在他们上面花更多的时间了。他们的镜像使用频率很高,所有他们是可缓冲的,也没有留下什么后续问题。
网络拓扑结构设计
网络拓扑结构非常简单,每个服务器机架顶都有一对1G的卡,每个机架都有多个10G的接口,接口连接到外部的核心路由器。他们使用Dell Power Edge交换机,这些交换机对L3(TCP/IP)并不是完全支持,但是比L2(ethernet)要好的多。每个交换机每天要传输20G的数据,而且很便宜。核心路由器是思科的6500的系列。Justin.TV想要将节点最小化,从而让延迟降低,并且降低每个packet的处理时间。Usher管理着所有的接入控制和其他的逻辑,而不仅仅限于网络硬件。
使用多个数据中心可以充分利用对等网的优势,把流量转移到离用户最近的地方。和其他的网络和节点的连接非常多。这样就有多个可选的传输途径,所以可以使用最好的那个路径。如果他们遇到了网络的拥塞,就可以选择一条别的路。他们可以通过IP地址和时间,找到对应的ISP。
开发和部署
他们使用Puppet服务器主机,有20中不同种类的服务器。从数据库中出来的任何东西都要经过缓存器,使用Puppet他们可以把这个缓存器变成他们想要的任何东西。
他们有两个软件队伍。一个是产品队伍,另一个是硬件基础设施队伍。他们的队伍非常小,大概每个队伍只有7-8个人,每个队伍都有一个产品经理。他们雇佣一般的技术员,但却雇佣了网络结构和数据库相关的专家。
他们使用了基于网络的开发系统,所以每个新的改动都会在几分钟内完成。QA必须在变成产品之前完成,在这里通常需要5-10分钟。
Justin.TV使用Git管理源代码。Justin.TV喜欢Git的这个功能,你可以写一个程序副本,20-30行,然后它可以融合到其他人手里正在修改的副本。这个工作是独立的,模块化的。在你不得不撤销你提交的副本时,你可以很容易就修改或者撤销你的代码。每过几天每个人都会试着将自己的代码副本融入到主代码中去消除冲突。他们每天对软件做5-15个修改,范围从1行代码中的bug到大范围的测试都有。
数据库模式通过手动更新完成。将他们复制的数据库副本迁移到一起就会形成一个最新的动态记录的版本。在把改动最终应用到产品之前会在许多不同的环境下对其进行测试。
Puppet管理配置文件。每个小的改动基本上就是一个实验,他们会追踪每个对核心文件的改动的影响和之前的版本。这些测试很重要,因为通过它他们可以找出哪些改动是真正提高他们关心的指标。
Justin.TV的未来
他们的目标是增加一个数量级。首先要切分他们的视频元数据系统,由于流数据和服务器的大幅增长,他们的元数据负载也指数级的爆发增长,因此,他们需要将其大范围进行切分,对于网络数据库,将使用Cassandra对其进行拆分。其次,为了灾后恢复,要对核心数据中心进行备份。
学到的东西
自己开发还是购买。他们在这个问题上已经做了很多错误的决策。例如,他们起初应该买一台视频服务器而不是自己去做了一台。软件工程师喜欢将软件做的个性化,然后使用开源社区维护的东西却有很多益处。因此他们提出了一个更好的流程去做这个决定:1.这个项目是活动?还是维护?还是修补漏洞?2.有其他的人要用它么?你能向别人请教下该如何定义它?3.扩展性的问题,他们必须去做改变。4.如果我们自己开发,我们可以做到更快,更好,还是我们可以获得更多我们需要的特性呢? 就像使用Usher,他们考虑他们可否创造一个新的外部特性,并且和另外一个系统交互。把Usher做为视频扩展性的核心针对相对笨拙的视频服务器来说是一个非常好的决策的例子。
关注自己做的事情,不要在意别人怎么干。他们的目标是有用最好的系统,最多的服务时间和最完美的扩展性。他们用了3年去开发能管理百万个广播并发的技术。
不要外包。你学到的核心价值在于经验,而不是代码或者硬件。
把一切都当做实验来做。对所有的东西都进行测量,局部测试,追踪,测量。这很划算。从一开始就做,使用优秀的测量工具。例如,他们在复制的URL上附加一个标签,然后就可以知道你是否分享了这个链接。他们从不测量的走到了如今高度测量。通过重写广播进程,使得他们的会话数量增长了700%。他们想要网站运行更快,响应更快,网页装载更快,视频服务更好,系统挤出的每一毫秒的延迟都带来了更多的广播者。他们有40个实验,如果他们希望让一个用户变成一个广播者,对每个实验他们都想要看一下广播后的留存率,广播的可用性,会话率,然后对每个改动都做一个明智的决策。
最重要的一件事是理解你的网站如何共享服务,怎么优化它。他们通过减少共享的链接在菜单中的深度,成功的提高了500%的分享率。
使用公共的构建模块和基础设施意味着系统将立刻识别什么是重要的,然后执行。具有网络能力很重要,这也是他们应该从开始就关注的地方。
让系统忙起来。使用系统的所有能力,为什么要把钱放在桌子上呢?构建可以通过应答对系统进行合理的分配的系统。
对不重要的事情不要浪费时间。如果它非常方便并且不用花费多少,就没有必要在它上面花费时间。使用S3去存储镜像就是一个很典型的例子。
试着为用户想做的事情提供支持,而不是做你认为用户该这样使用的东西。Justin.TV的终极目标似乎是把所有人都变成一个广播点。在用户实验时,通过尽可能的走出用户的使用方式,他们试着让这个过程变得尽可能简单。在这过程中,他们发现,游戏是一个巨大的作用力。用户喜欢将Xbox截图出来,并且与大家分享,讨论它,很有可能有些东西是你没想过要放在商务计划里的。
为负载峰值做设计。如果你只为了静态的状态做了设计,之后你的网站将会在峰值来临时垮掉。在实时视频上,这通常是一个大事,如果你陷入了这个麻烦,很快人们就开始传播对你不利的话。为峰值负载进行设计需要使用一个所有层次的技术。
让网络结构保持简单。使用多数据中心,使用点对点网络连接结构。
不要担心将东西划分到更多的可扩展块中去。例如,与其使用一个100,000人的频道,不如将他们划分到更多的社会和可扩展的频道去。
实时系统不能隐藏来自用户的任何问题,这就是的说服用户你的网站很可靠变的很困难。由于他们和实时系统之间的联系是固定的,这会使的系统的每个问题和故障都让大家知道,你藏不住。每个人都会发现,并且每个人都会通过交流传播发生了什么,很快,用户就会有一个你的网站有很多问题的感觉。在这种情况下,和你的用户交流就变得很重要,从一开始就构建一个可信赖的,高质量的,可扩展的,高性能的系统,设计一个用户用起来尽可能简单和舒服的系统。(编译:@康文博/审校:仲浩)
摘自:http://www.csdn.net/article/2012-11-23/2812183-JustinTV_real-time_architecture
优酷视频网站架构
一、网站基本数据概览
据2010年统计,优酷网日均独立访问人数(uv)达到了8900万,日均访问量(pv)更是达到了17亿,优酷凭借这一数据成为google榜单中国内视频网站排名最高的厂商。
硬件方面,优酷网引进的戴尔服务器主要以 PowerEdge 1950与PowerEdge 860为主,存储阵列以戴尔MD1000为主,2007的数据表明,优酷网已有1000多台服务器遍布在全国各大省市,现在应该更多了吧。
二、网站前端框架
从一开始,优酷网就自建了一套CMS来解决前端的页面显示,各个模块之间分离得比较恰当,前端可扩展性很好,UI的分离,让开发与维护变得十分简单和灵活,下图是优酷前端的模块调用关系:
这样,就根据module、method及params来确定调用相对独立的模块,显得非常简洁。下面附一张优酷的前端局部架构图:
三、数据库架构
应该说优酷的数据库架构也是经历了许多波折,从一开始的单台MySQL服务器(Just Running)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库,这一系列过程只有经历过才会有更深的体会吧,就像MySpace的架构经历一样,架构也是一步步慢慢成长和成熟的。
1、简单的MySQL主从复制:
MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其原来图如下:
其主从复制的过程如下图所示:
但是,主从复制也带来其他一系列性能瓶颈问题:
-写入无法扩展
-写入无法缓存
-复制延时
-锁表率上升
-表变大,缓存率下降
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
2、MySQL垂直分区
如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:
然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平sharding呢?
3、MySQL水平分片(Sharding)
这是一个非常好的思路,将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:
如何来确定某个用户所在的shard呢,可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:
但是,优酷是如何解决跨shard的查询呢,这个是个难点,据介绍优酷是尽量不跨shard查询,实在不行通过多维分片索引、分布式搜索引擎,下策是分布式数据库查询(这个非常麻烦而且耗性能)
四、缓存策略
貌似大的系统都对“缓存”情有独钟,从http缓存到memcached内存数据缓存,但优酷表示没有用内存缓存,理由如下:
避免内存拷贝,避免内存锁
如接到老大哥通知要把某个视频撤下来,如果在缓存里是比较麻烦的
而且Squid 的 write() 用户进程空间有消耗,Lighttpd 1.5 的 AIO(异步I/O) 读取文件到用户内存导致效率也比较低下。
但为何我们访问优酷会如此流畅,与土豆相比优酷的视频加载速度略胜一筹?这个要归功于优酷建立的比较完善的内容分发网络(CDN),它通过多种方式保证分布在全国各地的用户进行就近访问——用户点击视频请求后,优酷网将根据用户所处地区位置,将离用户最近、服务状况最好的视频服务器地址传送给用户,从而保证用户可以得到快速的视频体验。这就是CDN带来的优势,就近访问,有关CDN的更多内容,请大家Google一下。
这是一个完整的PDF:http://www.blogkid.net/qconppt/youkuqiudanqconbeijing-090423080809-phpapp01.pdf
转自:http://www.kaiyuanba.cn/html/1/131/147/7541.htm
YouTube网站架构
YouTube发展迅速,每天超过1亿的视频点击量,但只有很少人在维护站点和确保伸缩性。这点和PlentyOfFish类似,少数人维护庞大系统。是什么原因呢?放心绝对不是靠人品,也不是靠寂寞,下面就来看看YouTube的整体技术架构吧。
平台
1、Apache
2、Python
3、Linux(SuSe)
4、MySQL
5、psyco,一个动态的Python到C的编译器
6、lighttpd代替Apache做视频查看
状态
1、支持每天超过1亿的视频点击量
2、成立于2005年2月
3、于2006年3月达到每天3千万的视频点击量
4、于2006年7月达到每天1亿的视频点击量
5、2个系统管理员,2个伸缩性软件架构师
6、2个软件开发工程师,2个网络工程师,1个DBA
Web服务器
1,NetScaler用于负载均衡和静态内容缓存
2,使用mod_fast_cgi运行Apache
3,使用一个Python应用服务器来处理请求的路由
4,应用服务器与多个数据库和其他信息源交互来获取数据和格式化html页面
5,一般可以通过添加更多的机器来在Web层提高伸缩性
6,Python的Web层代码通常不是性能瓶颈,大部分时间阻塞在RPC
7,Python允许快速而灵活的开发和部署
8,通常每个页面服务少于100毫秒的时间
9,使用psyco(一个类似于JIT编译器的动态的Python到C的编译器)来优化内部循环
10,对于像加密等密集型CPU活动,使用C扩展
11,对于一些开销昂贵的块使用预先生成并缓存的html
12,数据库里使用行级缓存
13,缓存完整的Python对象
14,有些数据被计算出来并发送给各个程序,所以这些值缓存在本地内存中。这是个使用不当的策略。
应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改,预计算,然后发送。
视频服务
1,花费包括带宽,硬件和能源消耗
2,每个视频由一个迷你集群来host,每个视频被超过一台机器持有
3,使用一个集群意味着:
-更多的硬盘来持有内容意味着更快的速度
-failover。如果一台机器出故障了,另外的机器可以继续服务
-在线备份
4,使用lighttpd作为Web服务器来提供视频服务:
-Apache开销太大
-使用epoll来等待多个fds
-从单进程配置转变为多进程配置来处理更多的连接
5,大部分流行的内容移到CDN:
-CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
-CDN机器经常内存不足,因为内容太流行以致很少有内容进出内存的颠簸
6,不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器
-长尾效应。一个视频可以有多个播放,但是许多视频正在播放。随机硬盘块被访问
-在这种情况下缓存不会很好,所以花钱在更多的缓存上可能没太大意义。
-调节RAID控制并注意其他低级问题
-调节每台机器上的内存,不要太多也不要太少
视频服务关键点
1,保持简单和廉价
2,保持简单网络路径,在内容和用户间不要有太多设备
3,使用常用硬件,昂贵的硬件很难找到帮助文档
4,使用简单而常见的工具,使用构建在Linux里或之上的大部分工具
5,很好的处理随机查找(SATA,tweaks)
缩略图服务
1,做到高效令人惊奇的难
2,每个视频大概4张缩略图,所以缩略图比视频多很多
3,缩略图仅仅host在几个机器上
4,持有一些小东西所遇到的问题:
-OS级别的大量的硬盘查找和inode和页面缓存问题
-单目录文件限制,特别是Ext3,后来移到多分层的结构。内核2.6的最近改进可能让 Ext3允许大目录,但在一个文件系统里存储大量文件不是个好主意
-每秒大量的请求,因为Web页面可能在页面上显示60个缩略图
-在这种高负载下Apache表现的非常糟糕
-在Apache前端使用squid,这种方式工作了一段时间,但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个
-尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题,因为它们各自保持自己单独的缓存
-如此多的图片以致一台新机器只能接管24小时
-重启机器需要6-10小时来缓存
5,为了解决所有这些问题YouTube开始使用Google的BigTable,一个分布式数据存储:
-避免小文件问题,因为它将文件收集到一起
-快,错误容忍
-更低的延迟,因为它使用分布式多级缓存,该缓存与多个不同collocation站点工作
-更多信息参考Google Architecture,GoogleTalk Architecture和BigTable
数据库
1,早期
-使用MySQL来存储元数据,如用户,tags和描述
-使用一整个10硬盘的RAID 10来存储数据
-依赖于信用卡所以YouTube租用硬件
-YouTube经过一个常见的革命:单服务器,然后单master和多read slaves,然后数据库分区,然后sharding方式
-痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作,slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以slaves会远远落后于master
-更新引起缓存失效,硬盘的慢I/O导致慢备份
-使用备份架构需要花费大量的money来获得增加的写性能
-YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群
2,后期
-数据库分区
-分成shards,不同的用户指定到不同的shards
-扩散读写
-更好的缓存位置意味着更少的IO
-导致硬件减少30%
-备份延迟降低到0
-现在可以任意提升数据库的伸缩性
数据中心策略
1,依赖于信用卡,所以最初只能使用受管主机提供商
2,受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议
3,YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约
4,使用5到6个数据中心加CDN
5,视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN
6,依赖于视频带宽而不是真正的延迟。可以来自任何colo
7,图片延迟很严重,特别是当一个页面有60张图片时
8,使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的
学到的东西
1,Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案
2,Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别
3,Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money
4,Keep it simple!简单允许你更快的重新架构来回应问题
5,Shard。Sharding帮助隔离存储,CPU,内存和IO,不仅仅是获得更多的写性能
6,Constant iteration on bottlenecks:
-软件:DB,缓存
-OS:硬盘I/O
-硬件:内存,RAID
7,You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队,如安装打印机,安装机器,安装网络等等的人。
With a good team all things are possible。
转自:http://www.kaiyuanba.cn/html/1/131/147/7540.htm
Twitter网站架构
一、twitter网站基本情况概览
截至2011年4月,twitter的注册用户约为1.75亿,并以每天300000的新用户注册数增长,但是其真正的活跃用户远远小于这个数目,大部分注册用户都是没有关注者或没有关注别人的,这也是与facebook的6亿活跃用户不能相提并论的。
twitter每月有180万独立访问用户数,并且75%的流量来自twitter.com以外的网站。每天通过API有30亿次请求,每天平均产生5500次tweet,37%活跃用户为手机用户,约60%的tweet来自第三方的应用。
平台:Ruby on Rails 、Erlang 、MySQL 、Mongrel 、Munin 、Nagios 、Google Analytics 、AWStats 、Memcached
下图是twitter的整体架构设计图:
二、twitter的平台
twitter平台大致由twitter.com、手机以及第三方应用构成,如下图所示:
其中流量主要以手机和第三方为主要来源。
Ruby on Rails:web应用程序的框架
Erlang:通用的面向并发的编程语言,开源项目地址:http://www.erlang.org/
AWStats:实时日志分析系统:开源项目地址:http://awstats.sourceforge.NET/
Memcached:分布式内存缓存组建
Starling:Ruby开发的轻量级消息队列
Varnish:高性能开源HTTP加速器
Kestrel:Scala编写的消息中间件,开源项目地址:http://github.com/robey/kestrel
Comet Server:Comet是一种ajax长连接技术,利用Comet可以实现服务器主动向web浏览器推送数据,从而避免客户端的轮询带来的性能损失。
libmemcached:一个memcached客户端
使用mysql数据库服务器
Mongrel:Ruby的http服务器,专门应用于rails,开源项目地址:http://rubyforge.org/projects/mongrel/
Munin:服务端监控程序,项目地址:http://munin-monitoring.org/
Nagios:网络监控系统,项目地址:http://www.nagios.org/
三、缓存
讲着讲着就又说到缓存了,确实,缓存在大型web项目中起到了举足轻重的作用,毕竟数据越靠近CPU存取速度越快。下图是twitter的缓存架构图:
大量使用memcached作缓存
例如,如果获得一个count非常慢,你可以将count在1毫秒内扔入memcached
获取朋友的状态是很复杂的,这有安全等其他问题,所以朋友的状态更新后扔在缓存里而不是做一个查询。不会接触到数据库
ActiveRecord对象很大所以没有被缓存。Twitter将critical的属性存储在一个哈希里并且当访问时迟加载
90%的请求为API请求。所以在前端不做任何page和fragment缓存。页面非常时间敏感所以效率不高,但Twitter缓存了API请求
在memcached缓存策略中,又有所改进,如下所述:
1、创建一个直写式向量缓存Vector Cache,包含了一个tweet ID的数组,tweet ID是序列化的64位整数,命中率是99%
2、加入一个直写式行缓存Row Cache,它包含了数据库记录:用户和tweets。这一缓存有着95%的命中率。
3、引入了一个直读式的碎片缓存Fragmeng Cache,它包含了通过API客户端访问到的sweets序列化版本,这些sweets可以被打包成json、xml或者Atom格式,同样也有着95%的命中率。
4、为页面缓存创建一个单独的缓存池Page Cache。该页面缓存池使用了一个分代的键模式,而不是直接的实效。
四、消息队列
大量使用消息。生产者生产消息并放入队列,然后分发给消费者。Twitter主要的功能是作为不同形式(SMS,Web,IM等等)之间的消息桥
使用DRb,这意味着分布式Ruby。有一个库允许你通过TCP/IP从远程Ruby对象发送和接收消息,但是它有点脆弱
移到Rinda,它是使用tuplespace模型的一个分享队列,但是队列是持久的,当失败时消息会丢失
尝试了Erlang
移到Starling,用Ruby写的一个分布式队列
分布式队列通过将它们写入硬盘用来挽救系统崩溃。其他大型网站也使用这种简单的方式
五、总结
1、数据库一定要进行合理索引
2、要尽可能快的认知你的系统,这就要你能灵活地运用各种工具了
3、缓存,缓存,还是缓存,缓存一切可以缓存的,让你的应用飞起来。
部分转自:http://timyang.net/architecture/twitter-cache-architecture/
这里还有一份根据英文翻译的:http://hideto.iteye.com/blog/130044
JustinTV网站架构
Justin.TV每月有3000万个独立访问量,在游戏视频上传领域打败了YouTube ,他们每天每分钟新增30个小时的视频,而YouTube只有23。
下面从Justin.TV的实时视频系统使用到的平台,他们的架构细节,从他们身上应该学到的东西等几个方面逐一展开。
使用到的平台
Twice —— 代理服务系统,主要用缓冲优化应用服务器负载
XFS —— 文件系统
HAProxy —— 用于TCP/HTTP负载平衡
LVS stack and Idirectord —— 高可靠性
Ruby on Rails —— 应用服务器系统
Nginx —— web服务器系统
PostgreSQL —— 数据库,用于用户和meta数据
MongoDB —— 数据库,用于内部分析
MemcachedDB —— 数据库,用于存放经常要修改的数据
Syslog-ng —— 日志服务系统
RabitMQ —— job系统
Puppet —— 创建服务
Git —— 源代码管理
Wowza —— Flash/H.264视频服务器和许多Java写的custome modules
Usher —— 播放视频流的逻辑控制服务器
S3 —— 用于存储小型镜像
Justin.TV的一些统计数据
有覆盖全美的4个数据中心
在任何时候都有2000多个同时流入的数据流
每天每分钟新增30个小时的视频
每月有3000万个独立访问量(不计同一用户多次访问)
每秒实时的网络流量在45G左右
实时视频结构详述
实时视频结构
1.使用了P2P和CDN
一般人认为,只需要不断提高带宽,把传来的数据都放入内存,不断的接收数据流就可以了,事实并非如此。实时视频要求不能打断,这就意味着你不可以超负荷的使用带宽。YouTube只需要让播放器缓冲一下,就可以用8G的带宽解决10G通道的需求,但在实时视频里,你不能缓冲,如果在信道上的流量超过了它的传输能力,哪怕只是一瞬间,那么所有的正在看的用户在那一刻都会卡。如果你在它的极限能力上再加入了一点儿负载,所有人立刻就会进入缓冲状态。
Justin.TV使用了点对点的结构来解决这个问题,当然他们也有更好的解决办法,CDN(内容分发网络)便是之一。当用户的流量负载超过Justin.TV的负载能力时,Justin.TV便很巧妙的将超标流量引入到一个CDN中去,Usher控制着这个处理逻辑,一旦接到了超标用户的负载请求,Usher便立刻将这些新用户转发到CDN中去。
2.100%可用时间和维护的矛盾
实时视频构建的系统既要保证100%的可用时间,又要保证机器可以进行维护。与一般网站不同,一般网站维护时出现的问题只有少数人会发现、关注,而实时视频网站不同,用户很快就会发现维护时带来的任何问题,并且互相传播的非常快。这就使得没有什么问题可以隐瞒用户,面对现在用户的挑剔,你必须避免维护时出问题。对一个服务器维护时,你不能主动结束用户的进程,必须等待所有在这个服务器上的用户自己结束服务才能开始,而这个过程往往非常缓慢。
3.Usher与负载均衡
Justin.TV遇到的最大的麻烦是即时拥塞,当大量的用户同时看同一个栏目的时候,便会突然产生突发网络拥塞。他们开发了一个实时的服务器和数据中心调度系统,它就是Usher。
Justin.TV的系统在突发的高峰拥塞上做了很多。他们的网络每秒可以处理大量的链入连接。用户也参与了负载均衡,这也是Justin.TV需要用户使用Justin.TV自己的播放器的原因之一。至于TCP,由于它的典型处理速度就是百kbps级的,所以也不用对TCP协议做什么修改。
相对于他们的流量,他们的视频服务器看来来有些少,原因是他们可以使用Usher把每个视频服务器的性能发挥到最好,负载均衡可以确保流量从不会超过他们的负载极限。负载大部分是在内存中,因此这个系统可以让网络的速度发挥到极限。服务器他们是一次从Rackable(SGI服务器的一个系列)买了一整套,他们做的仅仅是从所有预置的里面做了下挑选。
Usher是Justin.TV开发的一款定制化软件,用来管理负载平衡,用户认证和其他一些流播放的处理逻辑。Usher通过计算出每个流需要多少台服务器提供支持,从而分配资源,保证系统处于最优状态,这是他们的系统和别家不同之处。Usher通常会从下面几个指标计算、衡量某个流媒体所需要的服务器:
每个数据中心的负载是多少
每个服务器的负载是多少
延迟优化的角度
当前这个流可用的服务器列表
用户的国家(通过IP地址获得)
用户是否有可用的对等网(通过在路由数据库中查询IP地址获得)
请求来自于哪个数据中心
Usher使用这些指标便可以在服务净成本上来优化,把服务放在比较空闲的服务器上,或者把服务放在离用户较近的服务器上,从而给用户带来更低的延迟和更好的表现。Usher有很多个可以选择的模式从而达到很细的控制粒度。
Justin.TV系统的每个服务器都可以做边缘服务器,直接为用户输出视频流,同时每个服务器也可以做源服务器,为其他服务器传递视频流。这个特性,使得视频流的负载结构成了动态的,经常改变的一个过程。
4.服务器形成了加权树
服务器之间由视频流的拷贝而产生的联系和加权树非常相似。数据流的数量经常被系统取样、统计,如果观看某个视频流的用户数量飞速上涨,系统便将其拷贝很多份到一些其他的服务器上去。这个过程反复执行,最终就形成了一个树状的结构,最终会将网络中所有的服务器都画在里面。Justin.TV的视频流从源服务器出发,被拷贝到其他服务器,或者拷贝到用户的整个过程中,都处于内存中,没有硬盘路径的概念。
5.RTMP和HTTP
Justin.TV尽可能的使用了Flash,因为它使用RTMP协议,对每个视频流,系统都有一个独立的Session去维护它。由于使用这个协议,成本就相当高。由于ISP不支持下载流,因而无法使用多路广播和P2P技术。Justin.TV确实想过用多路广播在内部服务器之间拷贝数据流,然而由于他们的系统控制覆盖整个网络,而且内部有大量的很便宜的带宽可以使用,这样使用多路广播的技术就并没有产生多少效益。同时,由于他们的优化算法是将每个服务器上的流数都最小化,这就使得在很细的力度上做些事情会非常麻烦,甚至超过了他们能得到收益。
Justin.TV的Usher使用HTTP请求去控制某个服务器负载哪个视频流,从而控制了服务的拓扑结构。Justin.TV在流数据上使用HTTP,但存在的一个问题是它没有延迟和实时方面的性能。有些人说实时的定义就是5-30秒,然而,面对数千人做实时视频的时候这显然不行,因为他们还需要实时的讨论,交流,这意味着延迟不能高于1/4秒。
6.从AWS到自己的数据中心
起初Justin.TV使用AWS,后来迁移到Akamai(云服务供应商),最后到了自己的数据中心。
离开AWS到Akamai的原因有:1,成本;2,网速不能满足他们的需求。视频直播对带宽非常敏感,因此有一个快速的,可靠的,稳定的和低延迟的网络非常关键。使用AWS时,你不能控制这些,它是一个共享的网络,常常超负载,AWS的网速不会比300Mbps更快。他们对动态范围改动和云API很重视,然而在性能和成本问题上没有做什么。
3年前,Justin.TV计算他们每个用户的成本,CDN是$0.135,AWS是0.0074,Datacenter是$0.001如今,他们的CDN成本降低了,但他们的数据中心的成本却仍然一样。
拥有多个数据中心的关键是为了能够接近所有的主要交换节点,他们选择国内最好的位置从而使得他们为国内最多的节点提供了入口,而且节约了成本,构建了这些数据中心后,他们就直接连入了这些其他的网络,从而就省去了之前处理这些中转流量的费用,还提高了性能,他们直接连入了他们所谓的"eyeball"网络,这个网络中包含了大量的cable/DSL用户,和"content"网络连接有些类似,Justin.TV的"eyeball"连接的流量主要来自终端用户,在大多数情况下,这些都是免费的,不用任何花一分钱,要做的就是连进来就行。Justin.TV有一个主干网,用于在不同的数据中心传输视频流,因为要到一个可用节点的选拔过程是去找愿意和你做对等节点的过程,这通常是很困难的。
7.存储
视频流不是从磁盘形成,而是要存到磁盘上去。源服务器将一个传入的视频流在本地磁盘上复制一份,之后便将这个文件上传到长期存储器上,视频的每一秒都被录下来并且存档了。
存储设备和YouTube类似,就是一个磁盘库,使用XFS文件系统。这个结构用于记录通过服务器传播的广播。默认的视频流是保存7天,用户可以手动的设置,甚至你可以保存到永远(如果公司没有倒闭的话)。
8.实时转码
增加了实时的转码功能,可以将任何一种流式数据转化为传输层数据或者是代码,并且可以用新的格式将它重新编为流媒体。有一个转码集群,用来处理转换工作转,换的会话使用job系统进行管理。如果需要的转码服务超过了集群的处理能力,那所有的服务器都可以用作转码服务器。
Web结构
Web 结构
1.Justin.TV前端使用Ruby on Rails。
2.用Twice做缓存
系统个每个页面都使用了他们自己定制的Twice缓存系统,Twice扮演的角色是轻量级反向代理服务器和模板系统的合并角色。思路是对每一个用户,缓存每一个页面,然后将每个页面的更新再并入其中。使用Twice以后,每个进程每秒可以处理150条请求,同时可以在后台处理10-20个请求,这就扩展了7-10倍之前的服务器可以处理的网页的数量。大部分动态网页访问都在5ms以内。Twice有一个插件结构,所以它可以支持应用程序的一个特点,例如添加地理信息。
不用触及应用服务器,便能自动缓存像用户名一样的数据。
Twice是一个为Justin.TV的需求和环境而定制化开发的。如果开发一个新的Rails应用,使用Varnish或许是一个更好的主意。
3.网络流量由一个数据中心服务,其他的数据中心为视频服务。
4.Justin.TV 对所有的操作都做了监控.每一个点击,查看页面和每一个动作都被记录下来,这样就可以不断提高服务。前端,网络呼叫或者一个应用服务器的日志消息都被转换成系统日志消息,通过syslog-ngto转发。他们扫描所有的数据,将它装入MongoDB,使用Mongo执行查询。
5.Justin.TV的API来自网站的应用服务器,它使用相同缓冲引擎,通过扩展网站来扩展他们的API。
6.PostegreSQL是他们最主要的数据库。结构是简单的主从结构,由一个主机和多个从属读数据库组成。
由于他们网站的类型,他们不需要许多写数据库,缓冲系统控制着这些读数据库。他们发现PostgreSQL并不擅长处理写操作,因此Justin.TV就是用MemcachedDB去处理那些经常要写的数据,例如计数器。
7.他们有一个聊天服务器集群,专门用来为聊天功能服务。如果用户进入了一个频道,用户就会有5个不同的聊天服务器为他服务,扩展聊天功能要比扩展视频功能简单的多,用户可以被划分到不同的房间,这些房间又由不同的服务器负载。他们也不会让100,000个人同时在一起聊天。他们限制每个房间200人,这样就可以在一个小组里进行更有意义的交谈。这同时对扩展也很有帮助,这真的是一个很聪明的策略。
8.AWS用于存储文档镜像。他们没有为存储许多小镜像而开发专门的系统,他们使用了S3。它非常方便,而且很便宜,这就不用在他们上面花更多的时间了。他们的镜像使用频率很高,所有他们是可缓冲的,也没有留下什么后续问题。
网络拓扑结构设计
网络拓扑结构非常简单,每个服务器机架顶都有一对1G的卡,每个机架都有多个10G的接口,接口连接到外部的核心路由器。他们使用Dell Power Edge交换机,这些交换机对L3(TCP/IP)并不是完全支持,但是比L2(ethernet)要好的多。每个交换机每天要传输20G的数据,而且很便宜。核心路由器是思科的6500的系列。Justin.TV想要将节点最小化,从而让延迟降低,并且降低每个packet的处理时间。Usher管理着所有的接入控制和其他的逻辑,而不仅仅限于网络硬件。
使用多个数据中心可以充分利用对等网的优势,把流量转移到离用户最近的地方。和其他的网络和节点的连接非常多。这样就有多个可选的传输途径,所以可以使用最好的那个路径。如果他们遇到了网络的拥塞,就可以选择一条别的路。他们可以通过IP地址和时间,找到对应的ISP。
开发和部署
他们使用Puppet服务器主机,有20中不同种类的服务器。从数据库中出来的任何东西都要经过缓存器,使用Puppet他们可以把这个缓存器变成他们想要的任何东西。
他们有两个软件队伍。一个是产品队伍,另一个是硬件基础设施队伍。他们的队伍非常小,大概每个队伍只有7-8个人,每个队伍都有一个产品经理。他们雇佣一般的技术员,但却雇佣了网络结构和数据库相关的专家。
他们使用了基于网络的开发系统,所以每个新的改动都会在几分钟内完成。QA必须在变成产品之前完成,在这里通常需要5-10分钟。
Justin.TV使用Git管理源代码。Justin.TV喜欢Git的这个功能,你可以写一个程序副本,20-30行,然后它可以融合到其他人手里正在修改的副本。这个工作是独立的,模块化的。在你不得不撤销你提交的副本时,你可以很容易就修改或者撤销你的代码。每过几天每个人都会试着将自己的代码副本融入到主代码中去消除冲突。他们每天对软件做5-15个修改,范围从1行代码中的bug到大范围的测试都有。
数据库模式通过手动更新完成。将他们复制的数据库副本迁移到一起就会形成一个最新的动态记录的版本。在把改动最终应用到产品之前会在许多不同的环境下对其进行测试。
Puppet管理配置文件。每个小的改动基本上就是一个实验,他们会追踪每个对核心文件的改动的影响和之前的版本。这些测试很重要,因为通过它他们可以找出哪些改动是真正提高他们关心的指标。
Justin.TV的未来
他们的目标是增加一个数量级。首先要切分他们的视频元数据系统,由于流数据和服务器的大幅增长,他们的元数据负载也指数级的爆发增长,因此,他们需要将其大范围进行切分,对于网络数据库,将使用Cassandra对其进行拆分。其次,为了灾后恢复,要对核心数据中心进行备份。
学到的东西
自己开发还是购买。他们在这个问题上已经做了很多错误的决策。例如,他们起初应该买一台视频服务器而不是自己去做了一台。软件工程师喜欢将软件做的个性化,然后使用开源社区维护的东西却有很多益处。因此他们提出了一个更好的流程去做这个决定:1.这个项目是活动?还是维护?还是修补漏洞?2.有其他的人要用它么?你能向别人请教下该如何定义它?3.扩展性的问题,他们必须去做改变。4.如果我们自己开发,我们可以做到更快,更好,还是我们可以获得更多我们需要的特性呢? 就像使用Usher,他们考虑他们可否创造一个新的外部特性,并且和另外一个系统交互。把Usher做为视频扩展性的核心针对相对笨拙的视频服务器来说是一个非常好的决策的例子。
关注自己做的事情,不要在意别人怎么干。他们的目标是有用最好的系统,最多的服务时间和最完美的扩展性。他们用了3年去开发能管理百万个广播并发的技术。
不要外包。你学到的核心价值在于经验,而不是代码或者硬件。
把一切都当做实验来做。对所有的东西都进行测量,局部测试,追踪,测量。这很划算。从一开始就做,使用优秀的测量工具。例如,他们在复制的URL上附加一个标签,然后就可以知道你是否分享了这个链接。他们从不测量的走到了如今高度测量。通过重写广播进程,使得他们的会话数量增长了700%。他们想要网站运行更快,响应更快,网页装载更快,视频服务更好,系统挤出的每一毫秒的延迟都带来了更多的广播者。他们有40个实验,如果他们希望让一个用户变成一个广播者,对每个实验他们都想要看一下广播后的留存率,广播的可用性,会话率,然后对每个改动都做一个明智的决策。
最重要的一件事是理解你的网站如何共享服务,怎么优化它。他们通过减少共享的链接在菜单中的深度,成功的提高了500%的分享率。
使用公共的构建模块和基础设施意味着系统将立刻识别什么是重要的,然后执行。具有网络能力很重要,这也是他们应该从开始就关注的地方。
让系统忙起来。使用系统的所有能力,为什么要把钱放在桌子上呢?构建可以通过应答对系统进行合理的分配的系统。
对不重要的事情不要浪费时间。如果它非常方便并且不用花费多少,就没有必要在它上面花费时间。使用S3去存储镜像就是一个很典型的例子。
试着为用户想做的事情提供支持,而不是做你认为用户该这样使用的东西。Justin.TV的终极目标似乎是把所有人都变成一个广播点。在用户实验时,通过尽可能的走出用户的使用方式,他们试着让这个过程变得尽可能简单。在这过程中,他们发现,游戏是一个巨大的作用力。用户喜欢将Xbox截图出来,并且与大家分享,讨论它,很有可能有些东西是你没想过要放在商务计划里的。
为负载峰值做设计。如果你只为了静态的状态做了设计,之后你的网站将会在峰值来临时垮掉。在实时视频上,这通常是一个大事,如果你陷入了这个麻烦,很快人们就开始传播对你不利的话。为峰值负载进行设计需要使用一个所有层次的技术。
让网络结构保持简单。使用多数据中心,使用点对点网络连接结构。
不要担心将东西划分到更多的可扩展块中去。例如,与其使用一个100,000人的频道,不如将他们划分到更多的社会和可扩展的频道去。
实时系统不能隐藏来自用户的任何问题,这就是的说服用户你的网站很可靠变的很困难。由于他们和实时系统之间的联系是固定的,这会使的系统的每个问题和故障都让大家知道,你藏不住。每个人都会发现,并且每个人都会通过交流传播发生了什么,很快,用户就会有一个你的网站有很多问题的感觉。在这种情况下,和你的用户交流就变得很重要,从一开始就构建一个可信赖的,高质量的,可扩展的,高性能的系统,设计一个用户用起来尽可能简单和舒服的系统。(编译:@康文博/审校:仲浩)
摘自:http://www.csdn.net/article/2012-11-23/2812183-JustinTV_real-time_architecture