迁移Channel9.msdn.com到Windows Azure

2011 年 12 月 29 日

简要背景介绍

第 9 频道是由微软运作的专注于开发者的社区网站。它诞生于很有趣的小团队,关于它的许多事情可能和你想象的不太一样。第 9 频道由一个小团队(4 名开发人员)开发,最初被托管在第三方 ISV 处。此外,它与那些运作其他网站,如 http://msdn.microsoft.com http://www.microsoft.com 的大型开发运营团队并无什么瓜葛。

(点击图片进行放大)

事实上,当第 9 频道最初在 2004 年推出时,它就已经跑在世界前列了,因为它使用的技术(ASP.NET)在那时甚至还未发布。

发展历程

很快到了 2010 年,这个小团队也运作开发了许多网站。开发团队快速地加入新功能,但是几乎都没有测试过。那时候,任何拥有 FTP 权限的开发人员都可以进行部署工作,不仅如此,在维护过程中,开发人员有时还不得不修复错误直至深夜。接下来的几年内,我们尝试把事情做得更好:在保持敏捷团队的同时把速度降到足够低,以计划新的开发,并尝试让网站更稳定,这既是为了用户,也是为了我们自己团队。

然而这样做行不通。网站极不稳定,直接导致每周都会宕机。如果网站在凌晨 2 点宕机,我们的 ISP 会打电话告诉开发团队。如果一台服务器需要进行切换,可能要花上数天的时间才能装好一台新的机器用作替换。即使在我们的网站群中,服务器也会有不同的硬件和软件配置,这使得故障会被隔离在特定的某些机器中,以致非常难以进行故障排除。所有的这些问题不仅伤透了用户的心,也在折磨着我们的开发团队。甚至于在手工使用 FTP 进行代码部署时都会经常导致宕机,这时通常是在部署过程中途出现问题,以致部署只有部分完成。随着网站越来越受欢迎,开发团队耗费了所有时间来排除故障和管理运营,以至于根本没有时间开发新的功能。当我向我的老板解释起这些事情的时候,我说了一句我从那以后一直在用的一句话:试想一下,如果建筑师们不得不亲自管理他们设计的每一栋建筑,将会是多大的负担。

我们难以自拔,因为我们要忙于保持网站运行,甚至几乎没有一点时间来寻找一条出路。就在这骨节眼上,2010 年 2 月 Windows Azure 推出了。这对于我来说似乎正是所面临问题的解决方案。尽管第 9 频道是微软的网站,但它的目标是将内容面向大众,它既不是演示也不仅仅是技术展示。考虑到这一点,虽然没有人要求我们将网站搬到新的开发和托管平台上,但是整个开发团队相信 Windows Azure 将会帮助我们重新回到开发功能的道路上。

迁移之路

第 9 频道在同一个 ISP 处托管了将近 6 年,并且我们同他们也已经建立了不错的关系;这个时候做出改变我们需要强有力的理由,尤其面对的是一个相对较新的平台。我们基于三个主要原因做出了这个决定 。

第一个也是最重要的目的是想摆脱那些让开发团队没法开发新功能的运维和服务器管理工作。第二,我们期望拥有干净的隔离系统环境,可以在无论什么时候部署都能够重新映像,拥有这样的环境将可以避免许多难以诊断的错误,而这些错误在过去几年中一直影响着第 9 频道的稳定性。最后一个目的无疑也是决定我们迁移到 Windows Azure 的主要原因,就是 Windows Azure 可以使我们更容易纵向扩展,以处理越来越多的流量。

虽然第 9 频道每年都有着稳定的流量增长,但是这样的逐步增长随着时间推移是可以通过在大部分托管服务商处增加更多服务器得以解决的。然而更加急迫的问题是如何应对突发性流行内容的高峰倾向。在我们托管大型活动如 MIX,PDC 或者最近的 BUILD 大会的内容时,这种高峰常会发生。下面的图表显示了第 9 频道在今年年初 MIX11 大会初期,中途以及刚刚过后时事件部分的流量。

(点击图片进行放大)

对于这样的高峰流量,需要能够迅速纵向扩展基础设施,然后再次回落。在我们现有的托管平台中,添加一台新的服务器需要数天的过程,其中包含了大量的手工部署和配置工作。当然,即使托管在 ISP 处,也肯定有更好的方法来做这件事情,但是我们没有任何现有的工具可以用来帮助进行服务器配置。

综合上述所有原因以及暗地里许下的更多新功能、更少宕机时间和轻松进行纵向扩展的承诺,我们对 Windows Azure 上开发一个新版本的第 9 频道的决定亮起了绿灯。

在云端创建第 9 频道

构建一个新的版本?是的,你没看错,虽然到处利用了一些代码,但是本质上我们还是架构和搭建了一个新版本的第 9 频道,这是这次迁移决定的一部分。当然,这并不是完全必要的,因为已有的代码库是基于 ASP.NET 和 SQL Server 的,我们本可以做一些改动就能使它在 Windows Azure 上运行。事实上,我们在早期规划阶段就做了这样的概念模型,但最终我们认为代码库在经历过若过年的“有机”增长后可以大幅简化。一般情况下,我总会主张反对从头重写。重构现有的生产代码往往是更好的解决方案,但是我们似乎处在需要更多剧烈变动的格局。原有的网站代码拥有了越来越多的功能附加其上,并且不是一直都能处于一种规划良好的状态;在这点上,可以说它是运行在相对简单的网站背后的一套极其复杂的代码库。

我们草拟了第 9 频道需要完成的基本目标,其主要目的概括起来是:“用户可以观看视频并对其发表评论”。当然这个网站还有许多其他功能,但是专注于单一目标让我们能够更快地实现一套新的用户体验设计,一个新的架构并最终构建出一套新的代码。

那么我们构建了什么?

由于我们做的是个新项目,因此我们对技术体系做了很大改动。我们使用 ASP.NET MVC 为网站编写页面,使用 Memcached 作为分布式缓存层,并且以 NHibernate(受欢迎的 Hibernate ORM 的.NET 版本)作用于 SQL Azure 上作为我们的数据层。我们所有的视频都被推进 Blob(大型二进制对象)存储,并通过内容分发网络(CDN)来使它们缓存在全世界范围内的边缘服务器上以进行访问。在将网站数据存储在 SQL Azure 的同时,我们还为各种不同的功能(如视图跟踪,诊断和审计)使用了表存储以及队列。

(点击图片进行放大)

在我们建立这个新系统的同时,旧网站依旧在运行(关闭第 9 频道数月真的不是好抉择),并且在我们停止为产品网站构建新代码时,维护依旧在持续。这种冲突问题往往是导致重写产品代码库失败的主要原因之一,而我们解决这个问题的方案可能没法适用于所有人。为了让开发团队腾出时间专注在新代码上,我尽我所能成为唯一一名开发人员工作在活动的第 9 频道网站上。虽然那段时光我无法很好地平衡工作与生活,但是我非常积极努力的想看到新的网站跑在云端。六个多月之后,我们把第 9 频道的 DNS 由之前的旧主机切换到了 Windows Azure 上的新家。伴随着全新代码一起到来的还有一套新的用户体验,这对我们的所有用户来说无疑是最值得引人注目的变动了。

(点击图片进行放大)

新系统在网站稳定性以及开发人员生产力方面都有了预期的效果。虽然我们仍然在管理网站、修复故障、部署新版本以及积极监控网站性能,但是这只花费了我们的一小部分时间。创建新服务器的轻便使我们不仅可以纵向扩展产品网站的规模,还可以轻松地创建过渡版、测试版或 Beta 版的网站。此外,部署到生产环境成为团队中任何人都可以做的事情,且整个过程不必担心结束的时候会让网站处于破坏状态。

现在我们部署到生产环境的流程如下:

  • 部署到生产实例的过渡位置;
  • 测试过渡环境;
  • 执行 VIP 切换,将过渡环境转为生产环境,反之亦然;
  • 删除当前过渡环境中的实例(这是步骤很重要,否则你得为过渡环境的实例付费!)

虽然部署可能要花上 20 分钟,但是它非常流畅,而且团队中的任何人都能做这个工作。相比 20 分钟部署与花上若干小时排解部署错误,我会选择每次花上 20 分钟。

假设你有不错的监控程序,你会发现扩展第 9 频道是个相对容易的工作。我们观察服务器上的 CPU 使用率,寻找持续水平超过 50% 或者大量峰值迫使水平超越的某个点。如果需要做出变化,我们可以仅仅通过改变配置来增加 / 减少 web 节点数量以及 / 或者 Memcached 结点数量。如果有需要,我们还可以通过在部署中改变结点虚拟硬件的大小(例如将 2 核映像变为 4 核),尽管我们还没这么做过。Azure 之外并没有提供自动扩展(automatic scaling)功能,但是有一些例子展示了如何创建这样的系统。一般在运行过程中我们都会有足够的余量(中央处理器 / 内存负载平均下降约 20%),这使得我们不仅可以毫不费力地处理流量的瞬时增加,还能拥有足够的时间应对任何较大的连续性增长。SQL Azure 是我们在进行纵向扩展时碰到的主要问题,因为我们在设计系统时,并没有考虑到支持数据库分片(database sharding)或借助新的联合(Federation)功能。仅仅为网站增加 SQL Azure 服务器的数量或是仅仅增加分配的硬件大小是不可能的。由于我们网站的大部分访问都是只读的(匿名用户只是来观看视频),因此到目前为止网页纵向扩展以及缓存层对我们都很管用。

迁移到 Windows Azure 的经验教训

Windows Azure 是一个新的开发平台,并且即使我们在同一家公司工作,在开始构建新版本网站的时候,我们也没有关于它的任何特殊专业方面的知识。随着时间的推移,在将新站点投入生产的前前后后,我们学到了很多关于事情如何运作以及什么工作最适合我们的团队。以下是我们总结出的在 Windows Azure 世界生存的 5 条关键要素。

第 1 条:为云端而开发

虽然这听起来像个广告,但是你应当全盘接受并全力使你的代码运行在云端。这并不是说你应当用某种方式编写代码而从不考虑去迁移它,而是说最好使用接口和依赖注入来简化模块化代码,这不仅可以达到测试的目的,还可以使你从特定的平台细节中隔离出来。例如第 9 频道既可以运行在本地的 IIS 中,也可以运行在 Windows Azure 模拟器环境中,还可以运行在真实的 Windows Azure 生产环境中。我要说的是,不要仅仅移植当前运行在 IIS 中的代码,相反你应该在脑海中修改或构建一个在 Windows Azure 上的架构,利用内置的功能而不是仅仅因为某些功能在前一个平台上出现就将它们强制加入到 Windows Azure 上。举一个例子,我们已经构建了自己的分布式的缓存层(Memcached)用来当服务器拓扑结构变化时使用 Windows Azure 运行时事件,因此跨越在运行 Memcached 的 n 个工作者角色(Worker Role)上的缓存键分布是动态的,并且可以处理添加和删除实例。我们本来需要创建用在普通服务器群处理的新模型,但是我们知道我们会基于 Azure,所以就对应地进行了构建。

第 2 条:工作量划分

云计算系统工作良好是因为它们设计让多个虚拟机每个运行相对较小的工作负载,并且随时能够换下任何机器,重新映像然后根据需要返回到服务中。这对代码意味着什么?假设当用户点击网站时,机器可能会从头初始化,并且随时都可能消失而恢复之后可能会又变成完全干净的状态。你所做的一切工作,特别是大的任务,应当设计为可以在多个机器上运行。如果给定的任务必须在一台机器上运行,并且必须花上若干小时一气呵成,那么你就错过了许多在 Windows Azure 上运行的优势。通过将一个大任务设计分解成若干个小块,你可以进行纵向扩展并且只需添加机器就能让工作运行得更快。将已有的流程重构成并行处理,在脑海中使用并行处理的的想法设计新的流程。使用 Windows Azure 存储(队列,二进制对象和表)来分发工作和任何需要被共享的资源。你也应当确保工作是可重复的,以处理当一项工作只是部分完成,而新的工作者角色可以接着拿起这项任务重新开始的情况。

在第 9 频道的世界里,关于这个概念的很好的例子就是下载和处理传入的 Web 日志文件。我们本来可以用一个工作者角色来检查任何传入的文件,下载解压并分析找出其中所有的视频请求,以此决定每个视频的观看次数然后更新第 9 频道。这些所有的工作用一段代码就可以搞定了,并且可以工作得很好,但是在 Windows Azure 的世界中这会是一种非常低效的编码方式。如果这个过程中,某个文件进行到最后一步然后失败了该怎么办?我们可能需要重新开始下载这个文件等等。

如果我们用 Windows Azure 的思维模式编写这段代码,情况就会稍有不同。我们的代码会检查新的日志文件,将其添加到我们已经知道的文件列表中,然后在队列中加入一项任务来下载该文件。现在我们的代码会取出队列消息,下载好文件放入到二进制对象存储,并向队列中加入消息以进行处理。我们继续将每一个步骤作为单独的任务,并使用队列消息来分发工作。现在如果有大量需要处理的文件,我们可以加入更多的工作者角色,并保持每一个角色忙于处理文件块。一旦一个文件被下载,接下去可以在下载的同时让其他的工作者角色处理解压缩和加工第一个文件。如果这种情况下出现故障,我们只需要重新启动单个步骤即可。

第 3 条:一切在云端运行

我在本文之前提到过,让开发团队身兼运营团队之职扼杀了我们的生产力和整体的工作满意度。所有要维护的不单单是 Web 服务器本身。除了公共网站,我们还有后台进程(如前面给出的日志处理例子),视频编码服务器和报表系统。所有这些刚开始都运行在内部服务器上,这意味着我们不得不对它们进行维护。如果一个系统失败,我们必须对其进行备份然后还原任何丢失的数据。如果一个系统账户密码更改,我们会被中断直到有人在任何运行的进程进行修复。所有的这些事情都恰恰是我最不想要开发团队做的工作类型。

解决问题的方案是将能迁移的一切迁移到 Windows Azure 上。虽然可能要花些时间把一个进程变得“Windows Azure 安全”一些——让其可重复、无状态、并同其环境隔离,但是这些时间用得其所。我们没有 100% 的做到那一点:我们将日志下载和处理任务以及各种各样的其他小系统迁移了过去,但是我们的视频编码过程仍然是一个完全运行在内部服务器上的复杂系统。每当它出现故障需要人工干预时,我会想到把它迁移到 Windows Azure 上,这样的价值就在于可以让团队摆脱运行服务器的事务。

第 4 条:状态扼杀可扩展性

虽然这最后两点对建立任何大型可扩展系统很有用,但是在 Windows Azure 背景下它们也是值得一提的。状态在很多场景下都是必要的,但是状态是可扩展性的敌人。正如我前面提到的,设计系统时你应当假定结点随时都可能被取下,重新映像并以完全干净的状态放回。在实践中,虽然它们往往会运行很长一段时间,但你不能依赖于这样的事实。用户会在角色中来回切换,很有可能每次请求都会在不同的服务器上结束。如果在服务器上建立状态并且用户的下一个请求将依赖于它,那么你的系统将要么没法越过单个实例进行扩展,要么大部分时间没法工作。换一个方法来处理,可以使用 Windows Azure App Fabric 缓存或者 Windows Azure 存储如二进制对象存储和表存储来尽量多的减少状态。

这意味着在第 9 频道我们把持久化状态(像用户要观看的视频队列)存储到二进制存储或 SQL Azure 中以备短期之用(例如在你发表评论时记住所在的视频位置,这样在你再次回到该页面时我们可以为你进行重播),我们甚至可以使用用户机器上的 Cookie。

第 5 条:将一切东西放到边缘服务器

即使通过高速连接,Web 也可能很慢。当你和你想要点击的服务器相互间距离很远时尤其如此。考虑到这点,不管我们将我们的页面变得如何得快,对于我们数据中心世界另一端的用户来说还是可能非常慢。这个问题对于网站本身已经有了解决方案,但是大多数情况真正的问题在于网站正在使用的媒质。解决这个问题的方案可以是简单地将内容放到距离用户近的位置。要做到这点,内容分发网络可以帮得上忙。

如果设置了 CDN 账户,你可以通过 Windows Azure 内置功能或者其它提供商如 Akamai,将你的内容服务器映射到特定的域名。借助一些 DNS 重写的功能,当用户访问你的内容时,请求不会发往 CDN,而是尝试从最近的服务器(任何一个优秀的 CDN 都会在全世界范围内 100 个地点拥有结点)向用户提供内容。如果 CDN 没有正在被请求的内容,它们会从初始源头处去取内容,虽然这使得第一次请求会有点慢,但是内容会被取出放到边缘服务器上,为那些要用相同文件的人做好准备。

如果你有任何静态内容,不管它是视频、图片、JavaScript、CSS 或者任何类型的文件,确保它们都由 CDN 提供。如果网站对给定的 URL,向每个人提供的内容都完全相同的话,那么这对网站本身也同样适用。第 9 频道目前为登录用户在页面上做了许多定制化内容,这使得我们很难为页面利用到 CDN,但是我们绝对为任何其他的东西都使用了 CDN。

我们变回了开发人员并乐此不疲

迁移到 Windows Azure 对我们团队而言很奏效。我们可以专注于我们真正擅长的工作上,而把运行的服务器留给专家们。如果你的开发团队陷于运营、部署和其他维护工作,可以考虑更新一下你的托管平台。当然,Windows Azure 并不是唯一的选择。我们的经验是,即使使用常规的 ISP,只要将手工配置的服务器迁移成基于映像和虚拟机的方式,也会受益匪浅。

不管你怎么做,让开发人员专注于开发都错不了,如果你最终选择了 Windows Azure,那么在计划对自己的系统进行迁移时可以考虑一下我给出的建议。

关于作者

Duncan Mackenzie第9 频道(一个由微软运作的视频/ 社区网站)的开发主管,他的工作是在MSDN 构建代码样例和撰写文章,他最开始是以一名顾问的身份在微软加拿大工作。在微软工作之外,他撰写了各式各样的关于Visual Basic、Word VBA、Xbox 甚至Zune 的书籍。当他不忙于编码或写作时,Duncan 会在华盛顿州雷德蒙德的家里陪他的两个小孩并且花上一定合理数量的时间在视频游戏上。

查看英文原文: Moving Channel9.msdn.com to Windows Azure


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011 年 12 月 29 日 00:001508
用户头像

发布了 125 篇内容, 共 28.5 次阅读, 收获喜欢 2 次。

关注

评论

发布
暂无评论
发现更多内容

架构师训练营 Week6 - 技术选型 - 分布式数据库,NoSQL,Zookeeper,搜索引擎

极客大学架构师训练营

架构师训练营—第六周作业

Geek_shu1988

第 2 周 框架设计作业

心在那片海

第二周-总结

jizhi7

架构师训练营第二期 Week 2 总结

bigxiang

第二周作业

阿呆

第六周作业

TheSRE

极客大学架构师训练营

week06学习总结

追风

架构师一期

第六周-CAP原则理解

袭望

分布式CAP原理

Jacky.Chen

架构师训练营 - 第 6周课后作业-CAP原理

树森

架构师训练营第二周作业

张小胖

极客大学架构师训练营

架构师训练营第 1 期 -Week6 - 课后练习

鲁小鲁

极客大学架构师训练营

架构师训练营第 1 期 -Week6 - 技术选型二学习总结

鲁小鲁

极客大学架构师训练营

架构师训练营第六周总结

月殇

极客大学架构师训练营

架构师训练营—第五周学习总结

Geek_shu1988

架构师训练营—第六周学习总结

Geek_shu1988

doris临时故障恢复图

happy

技术选型(1) 课后作业

ABS

第 2 周 框架设计总结

心在那片海

架构师训练营 第六周学习总结

郎哲158

极客大学架构师训练营

第六周作业 (作业一)

Geek_83908e

极客大学架构师训练营

第二周课后练习

jizhi7

极客大学架构师训练营

架构一期第六周作业

Airs

架构师训练营第六周作业

郎哲158

极客大学架构师训练营

第六周总结

Geek_ac4080

第六周作业

Geek_ac4080

WK1作业

Gavin_From_Mars

架构师训练营第 2 期 第二周作业 1

月下独酌

架构师训练营—第五周作业

Geek_shu1988

架构师训练营 week2 学习总结

花果山

极客大学架构师训练营

迁移Channel9.msdn.com到Windows Azure-InfoQ