YouTube 架构学习体会

近期我一直致力于研究和学习大型网站的架构设计,希望未来能够设计出高并发、高容错的系统并应用于实践。今天在搜集架构相关资料时,偶然看到一篇关于 YouTube 架构分析的文章(注:指早期架构),读后深感收获颇丰,仿佛向架构设计的大门又迈进了一步,于是整理出来与大家分享。

YouTube 发展极为迅速,日均视频点击量超过 1 亿,但维护站点和确保伸缩性的人员却很少。这点与 PlentyOfFish 类似,少数人维护着庞大系统。究其原因,绝非靠“人品”或“寂寞”,下面就来看看 YouTube 当时的整体技术架构。

技术平台

  • Web 服务器:Apache
  • 开发语言:Python
  • 操作系统:Linux (SuSe)
  • 数据库:MySQL
  • 优化组件:psyco(一个动态的 Python 到 C 的编译器)
  • 视频服务:lighttpd 代替 Apache 做视频查看

运营状态

  • 流量规模:支持每天超过 1 亿的视频点击量
  • 成立时间:2005 年 2 月
  • 增长历程

    • 2006 年 3 月:达到每天 3 千万视频点击量
    • 2006 年 7 月:达到每天 1 亿视频点击量
  • 团队规模

    • 2 个系统管理员
    • 2 个伸缩性软件架构师
    • 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 密集型任务:对于像加密等密集型 CPU 活动,使用 C 扩展。
  11. 静态化:对于一些开销昂贵的块,使用预先生成并缓存的 HTML。
  12. 数据库缓存:数据库里使用行级缓存。
  13. 对象缓存:缓存完整的 Python 对象。
  14. 本地内存缓存:有些数据被计算出来并发送给各个程序,所以这些值缓存在本地内存中。

    • 注:这是个使用不当的策略。应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改,预计算,然后发送。

视频服务

  1. 成本构成:花费包括带宽、硬件和能源消耗。
  2. 存储策略:每个视频由一个迷你集群来 host,每个视频被超过一台机器持有。
  3. 集群优势

    • 更多的硬盘来持有内容意味着更快的速度。
    • Failover:如果一台机器出故障了,另外的机器可以继续服务。
    • 在线备份
  4. Web 服务器选型:使用 lighttpd 作为 Web 服务器来提供视频服务。

    • Apache 开销太大。
    • 使用 epoll 来等待多个 fds。
    • 从单进程配置转变为多进程配置来处理更多的连接。
  5. CDN 策略:大部分流行的内容移到 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 和描述。
  2. 使用一整个 10 硬盘的 RAID 10 来存储数据。
  3. 依赖于信用卡所以 YouTube 租用硬件。
  4. 演进路线:YouTube 经过一个常见的革命:单服务器 -> 单 master 和多 read slaves -> 数据库分区 -> sharding 方式。
  5. 痛点:痛苦与备份延迟。

    • master 数据库是多线程的并且运行在一个大机器上,所以它可以处理许多工作。
    • slaves 是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以 slaves 会远远落后于 master。
    • 更新引起缓存失效,硬盘的慢 I/O 导致慢备份。
    • 使用备份架构需要花费大量的 money 来获得增加的写性能。
  6. 优化方案:YouTube 的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群。

后期架构

  1. 数据库分区。
  2. 分成 shards,不同的用户指定到不同的 shards。
  3. 扩散读写。
  4. 更好的缓存位置意味着更少的 IO。
  5. 导致硬件减少 30%。
  6. 备份延迟降低到 0。
  7. 现在可以任意提升数据库的伸缩性。

数据中心策略

  1. 依赖于信用卡,所以最初只能使用受管主机提供商。
  2. 受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议。
  3. YouTube 改为使用 colocation arrangement(主机托管)。现在 YouTube 可以自定义所有东西并且协定自己的契约。
  4. 使用 5 到 6 个数据中心加 CDN。
  5. 视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到 CDN。
  6. 依赖于视频带宽而不是真正的延迟。可以来自任何 colo。
  7. 图片延迟很严重,特别是当一个页面有 60 张图片时。
  8. 使用 BigTable 将图片备份到不同的数据中心,代码查看谁是最近的。

核心体会与学到的东西

  1. Stall for time:创造性和风险性的技巧让你在短期内解决问题,而同时你会发现长期的解决方案。
  2. Prioritize:找出你的服务中核心的东西并对你的资源分出优先级别。
  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.

说明:本文内容基于 YouTube 早期(约 2006-2007 年)的架构分析资料整理。文中提到的技术栈(如 psyco、lighttpd、早期 BigTable 应用等)及团队规模均为历史数据,反映的是 YouTube 被 Google 收购前后的架构演进阶段,不代表当前 YouTube 的最新技术现状。仅供架构演进学习参考。