开源代码及Linux系统在云计算中的应用
2010-08-07 08:38:16 阿炯

云计算和存储将物理资源(例如处理器和存储)转换成 Internet 上可伸缩、可共享的资源(“作为服务”的计算和存储)。虽然虚拟化不是一个新概念,但是通过服务器虚拟化实现的物理系统共享,的确能使资源的可伸缩性大得多,效率也高得多。云计算使用户可以访问大规模计算和存储资源,而且他们不必知道那些资源的位置及其是如何配置的。正如您预期的一样,在此扮演着极为重要的角色。探索云计算,了解其中的奥秘。

最近,没有哪家技术性网站不提到所谓的云计算(cloud computing)的。云计算其实就是以服务的形式提供计算资源(计算机和存储)。这又涉及到以一种简单、透明的方式动态地将服务延伸到更多的计算机和存储的能力。所有这些都类似于效用计算(utility computing)背后的思想。在效用计算中,计算资源被看作一种计量服务,就像更传统的公共设施(例如水或电)一样。它们的区别不在于这些思想背后的目标,而在于组合到一起、使这些思想成为现实的现有技术。

云计算背后最重要的概念之一就是可伸缩性,而实现它的关键则是虚拟化(virtualization)。虚拟化在一台共享计算机上聚集多个操作系统和应用程序,以便更好地利用服务器。虚拟化还允许在线迁移,因此,当一个服务器超载时,可以将一个操作系统的一个实例(以及它的应用程序)迁移到一个新的、不那么繁忙的服务器上。

从外部看,云计算只是将计算和存储资源从企业迁出,并迁入到云中。用户定义资源需求(例如计算和广域网、带宽需求),云提供者在它的基础设施中虚拟地装配这些组件。

开源代码及Linux系统在云计算中的应用

云计算在 Internet 中迁移资源

云计算的目标是使这些资源比您自己所能提供和管理的资源更廉价。云计算除了降低成本外,还有更大的灵活性和可伸缩性。云计算提供者可以轻松地扩展虚拟环境,以通过提供者的虚拟基础设施提供更大的带宽或计算资源。

云计算在环保方面的优势是,它可以在不同的应用程序之间虚拟化和共享资源,以提高服务器的利用率。下图显示了一个例子。在这个例子中,不同的应用程序使用了 3个独立的平台,每个应用程序都在它自己的服务器上运行。在云中,可以在多个操作系统和应用程序之间共享(虚拟化)服务器,从而减少服务器的数量。更少的服务器意味着需要更少的空间(减少数据中心占用的空间)和更少用于制冷的电力(减少碳足迹)。

开源代码及Linux系统在云计算中的应用

虚拟化和资源使用

现在让我们来探索一下,Linux 和开源社区如何为云计算领域做出贡献。您可能已经猜到,Linux 和开放源代码扮演着极其重要的角色。

Software-as-a-Service

SaaS 就是以服务的形式访问 Internet 上的软件。一种早期的 SaaS 方法是 Application Service Provider(ASP)。ASP 提供对 Internet 上存放或交付的软件的订阅。ASP 交付软件,并根据软件的使用收费。这样一来,您就不必购买软件,只需随需租用软件。

SaaS 的另一个方面是在 Internet 上使用远程执行的软件。这种软件可以是本地应用程序所使用的服务(并定义为 Web服务),也可以是通过 Web 浏览器看到的远程应用程序。远程应用程序服务的一个例子是 Google Apps,它通过一个标准的 Web浏览器提供一些企业应用。要远程地执行应用程序,通常需要依赖于一个应用服务器来公布所需的服务。应用服务器 是一个软件框架,它公布软件服务的API(例如事务管理或数据库访问)。具体的例子有 Red Hat JBoss Application Server、Apache Geronimo 和 IBMreg; WebSpherereg; Application Server 等。另外还有很多其他的应用服务器,参考资料 小节给出了一份详细的列表。

SaaS 的另一个最近的例子是 Google 的 Chrome 浏览器。这个浏览器是作为新桌面的理想环境,除了具有传统的 Web 浏览体验外,还可以通过它来(以本地或远程方式)交付应用程序。(要了解更多信息,请参阅 参考资料)。

Platform-as-a-Service

PaaS 可描述为一个完整的虚拟平台,它包括一个或多个服务器(在一组物理服务器上虚拟而成)、操作系统以及特定的应用程序(例如用于基于Web 的应用程序的 Apache 和 MySQL)。在某些情况下,这些平台可以预先定义和选择。而在另一些情况下,可以提供一个VM镜像,该镜像包含所有的特定于用户的应用程序。

PaaS 一个有趣的例子是 Google App Engine。App Engine 是一个服务,通过它可以在 Google的可伸缩性极佳的架构上部署 Web 应用程序。App Engine 为可通过 Internet 引用的 Python应用程序提供一个沙盒(将来还会支持更多的语言)。除了支持用户认证、镜像操作和电子邮件发送外,App Engine 还提供了 PythonAPI,用于持久地存储和管理数据(使用 Google Query Language 或 GQL)。Web应用程序运行时所在的沙盒将限制对底层操作系统的访问。虽然 App Engine 限制了应用程序可用的功能,但是它支持有用的 Web服务的构造。

注意: 在一定的带宽和存储约束范围内,在 App Engine 中部署应用程序是免费的。但是,如果要用 App Engine 构建生产 Web 站点,则需要评估使用费。

PaaS 的另一个例子是 10gen,它既是一个云平台,又是一个可下载的开放源代码包,可用于创建您自己的私有云。10gen 是类似于App Engine 的一个软件栈,它提供与 App Engine 类似的功能 — 但有一些不同之处。通过 10gen,可以使用 Python以及 JavaScript. 和 Ruby编程语言开发应用程序。该平台还使用沙盒概念隔离应用程序,并且使用它们自己的应用服务器的许多计算机(当然,是在 Linux上构建)提供一个可靠的环境。

Infrastructure-as-a-Service

IaaS 是以服务的形式交付计算机基础设施。这一层与 PaaS 的不同之处在于,只提供虚拟硬件,而没有软件栈。客户提供一个 VM镜像,该镜像在一个或多个虚拟服务器上被调用。IaaS 是作为服务的计算的最原始的形式(除了对物理基础设施的访问)。最著名的商业 IaaS提供程序是 Amazon Elastic Compute Cloud(EC2)。在 EC2 中,可以指定一个特定的VM(操作系统和应用程序集),然后将应用程序部署到它上面,或者提供要在服务器上执行的 VM 镜像。然后,只需根据计算时间、存储和网络带宽付费。

Eucalyptus 项目(Elastic Utility Computing Architecturefor Linking Your Programs To Useful Systems)是 Amazon EC2的一个开源实现,它与商业服务接口兼容。和 EC2 一样,Eucalyptus 依赖于 Linux 和 Xen进行操作系统虚拟化。Eucalyptus 是加利福尼亚大学(SantaBarbara)为进行云计算研究而开发的。您可以从该大学的网站上下载它(见 参考资料),或者通过 Eucalyptus PublicCloud 体验它,不过后者有一些限制。

另一个 EC2 风格的 IaaS 是 Enomalism 云计算平台,这是一个开放源代码项目,它提供了一个功能类似于 EC2 的云计算框架。Enomalism 基于 Linux,同时支持 Xen 和 Kernel Virtual Machine(KVM)。与其他纯 IaaS 解决方案不同的是,Enomalism 提供了一个基于 TurboGears Web 应用程序框架和 Python 的软件栈。

企业的云服务选择:SaaS、PaaS、IaaS的对比分析

云服务在如今更为重要,几乎每个企业都需要使用云计算服务,管理大量敏感和机密数据也变得困难。因此,在任何类型的企业中使用云服务都是不可避免的。首先以相对简单的方式进行对比。


然而,使用哪种云服务逐渐成为困扰企业的主要问题。一般而言,企业有三种云计算服务模式可以选择。
软件即服务(SaaS),这是一个完整的软件应用程序,具有用户界面
平台即服务(PaaS),开发人员可以在其中部署自己的应用程序的平台
基础设施即服务(IaaS),提供机器、存储和网络资源,开发人员可以通过安装自己的操作系统、应用程序和支持资源来管理。

上述所有服务都有其优点和局限性,因此有必要了解它们之间的主要差异。


1、什么是SaaS(软件即服务)

SaaS是一种解决方案模型,用户使用网页浏览器访问云端软件,该软件不仅包含程序,还包含用户数据。它将软件上传到云端供用户使用。云服务可能需要按月付订阅费或年费。SaaS无需在本地服务器上下载和运行应用程序。当用户在线登录其帐户时,所有内容都可以通过互联网获得。用户通常可以随时从任何设备访问该软件(只要有互联网连接)。

SaaS的交付通过互联网进行,第三方供应商负责处理。大多数应用程序直接在网页浏览器上运行。因此,客户端不需要在本地下载或安装。第三方供应商负责处理应用程序。维护和支持对企业来说变得很容易,这对他们非常有帮助。

1)优势
用户可以在多台设备上轻松使用该软件,而无需安装它们,并且可以从一个中心点轻松管理。SaaS应用程序可以从任何地方、任何设备上访问。它节省了具有执行挑战性任务的时间和金钱成本。这些任务包括升级、安装和管理。用户不再需要聘请IT专家将软件下载到整个办公室的多台计算机上,也不再担心使每台计算机上的软件保持最新状态。这一切都在云端处理。

2)缺点和局限性
数据安全是使用SaaS服务的重大限制之一。将数据传输到基于云的公共SaaS服务可能会导致安全问题。将现有应用程序与新更新的集成也可能是一个重大问题,因为一些供应商可能无法提供舒适的集成系统。由于第三方供应商会处理用户的应用程序,他们的维护停机和网络攻击或网络问题都可能会影响用户的软件性能。

SaaS提供商示例:Dropbox、SAP Concur、Salesforce、Cisco WebEx、GoToMeeting、Oracle

3)SaaS相关数据
1.38%的公司表示,他们几乎完全在SaaS上运行
2.80%的企业计划到2025年使其所有系统成为SaaS
3.到2023年,各种规模公司的SaaS支出将达到5000亿美元
4.86%使用SaaS的企业的员工参与度相对较高
5.就采用而言,北美是最成熟的SaaS市场
6.99%的企业租赁使用一个SaaS解决方案

2、什么是PaaS(平台即服务)

PaaS为开发人员提供了一个框架。他们可以在那里构建和自定义应用程序。这意味着开发人员在创建应用程序时不需要从头开始,为他们编写大量代码节省了大量时间(和金钱)。使用PaaS,服务器、存储和网络由第三方供应商管理。与此同时,开发人员自己进行维护和应用程序管理。

PaaS允许用户使用PaaS中可用的软件组件创建应用程序。该软件通过PaaS开发,继承了云能力。该功能使应用程序具有高度可扩展性,并在多台设备上可用。

1)优势
它具有成本效益,可扩展性,并可以轻松迁移到混合模型。PaaS允许开发人员专注于应用程序开发的创造性方面,而不是管理软件更新或安全补丁等琐碎的任务。他们的所有时间和精力都将用于创建、测试和部署应用程序。利用云提供商的服务和资源立即开始开发,从而加快上市时间。

2)缺点和局限性
基本的编码知识对于充分利用PaaS平台至关重要
对应用程序的控制取决于平台。例如在停电时,用户的软件也可能受到影响
它减少了客户控制力和灵活性
可能会出现像SaaS解决方案一样的数据安全和集成问题

PaaS提供商示例:PaaS的一个很好的例子是AWS Elastic。用户只需要上传和维护其应用程序。其中的例子包括Google App Engine、Heroku应用程序、Windows Azure、Force.com、OpenShift、Apache Stratos。

3、什么是IaaS(基础设施即服务)

它基本上符合现收现付的思维方式。用户需要为他们使用的服务付费,如网络、存储或虚拟化。供应商或服务提供商只管理服务器和仓库。用户必须处理从操作系统到虚拟机的所有内容。它基本上为用户提供了基于云的本地基础设施替代方案,因此企业可以避免投资昂贵的现场资源。

关于Iaas解决方案,开发人员必须安装自己的操作系统、数据库管理软件和支持软件。并且开发人员或公司的系统管理员必须同时管理硬件和软件。

IaaS通过API或仪表板为用户提供云服务器。这样,客户就可以控制整个基础设施。用户可以直接访问服务器和存储。需要完全控制其应用程序的企业或需要快速集成或升级的应用程序应使用 IaaS 平台。此外,只想为其使用的服务付费的企业同样适于使用它。

1)优势
它具有成本效益,因为用户只需要在所使用的服务上付费。此外,用户只需要花时间在服务器、存储和网络上。用户可以根据需要购买其需要的东西,并随着业务的增长购买更多,具有良好的可扩展性。用户可以大规模升级和升级现有的软件和应用程序。用户完全控制了自身的基础设施。

2)缺点和局限性
使用IaaS的成本取决于用户使用多少服务,因此在大多数情况下,价格是不可预测的。由于大多数控制权掌握在客户手中,团队人员还必须执行最繁琐的任务。企业可能需要为其团队提供额外的培训,以帮助他们更好地管理基础设施。

IaaS提供商示例:AWS EC2是IaaS的一个很好的例子。EC2用户不拥有物理服务器,AWS提供虚拟服务器。其他的例子有Google Compute Engine、Rackspace、Cisco Metacloud、Linode、DigitalOcean。


4、小结

每个云模型都提供特定的特性和功能,对于企业而言,了解这些差异至关重要。

IaaS在托管定制应用程序方面为用户提供最大的灵活性,并为数据存储提供通用数据中心。

PaaS通常构建在IaaS平台之上,以减少对系统管理的需求。它允许用户专注于应用程序开发,而不是基础设施管理。

SaaS提供现成的开箱即用的解决方案,以满足网站或电子邮件等特定业务需求。大多数现代SaaS平台都构建在IaaS或PaaS平台上。

根据业务的规模和复杂性,企业可以选择一种云计算服务模式。IaaS、PaaS和SaaS的日益普及减少了对内部托管的需求。无论企业选择哪个选项,迁移到云端都是其业务和技术的未来。


云的那些属性项


9个大项包括计算、存储、网络、安全、弹性、软件基础设施服务、数字商业基础设施、运营与治理、供应商管理与审计,下面分别讲解一些。


计算、存储、网络、安全,这些是公有云服务商的基础能力,也是IaaS层最硬核的部分。

计算能力评估

计算大项总共包含33个子项,其中必选项11个、推荐项12个、可选项10个。


这些项目涵盖IaaS计算能力的方方面面(虚拟机、物理机、容器、OS版本、自动伸缩、性能基准…)



软件基础设施服务(Software Infra. Services)

主要涉及数据库为主的PaaS能力(RDS、数仓、函数计算、NoSQL/NewSQL、消息服务、事件网格……)

数字商业基础设施(Digital Business Infrastructure)


Linode 实时迁移详解

当开发者将工作负载部署到云计算平台时,往往并不需要考虑运行这些服务的底层硬件。在人们对“云”的理想化印象中,硬件维护和物理限制往往是无形的,然而硬件不可避免需要时不时进行维护,这可能会导致停机。为避免这样的停机时间被转嫁给我们的客户,并真正实现云的承诺,Linode 提供了一种名为实时迁移(Live Migration)的工具。

借助实时迁移技术,Linode 实例可在不中断服务的前提下在不同物理服务器之间移动。通过实时迁移工具移动 Linode 实例时,迁移过程对 Linode 实例中运行的进程是完全不可见的。如果一台主机的硬件需要维护,即可通过实时迁移,将该主机上的所有 Linode 实例无缝转移到另一台主机中。迁移操作完成后,即可开始修理物理硬件,全过程中并不产生会影响到客户的停机时间。这几乎成为一种决定性的技术,也成为云技术和非云技术之间的转折点。本文将深入了解这项技术背后的细节。

实时迁移的工作原理

和大部分新项目类似,Linode 的实时迁移也是这样启动的:进行大量研究,创建一系列原型,获得同事和管理层的大量帮助。我们的第一步是调查 QEMU 如何处理实时迁移。QEMU 是 Linode 使用的一种虚拟化技术,而实时迁移也是 QEUM 的一项功能。因此我们团队的重点是将这项技术引入 Linode,而非重新发明一个类似的技术。那么实时迁移技术到底是如何以 QEMU 的方式实现的?整个过程分为以下四步:
1.启动目标 QEUM 实例,该实例的各项参数与需要迁移的源 QEUM 实例完全相同。
2.对磁盘进行实时迁移。数据传输过程中,对磁盘内容进行的任何更改也会提交至目标磁盘。
3.对内存数据进行实时迁移。迁移过程中, 内存内容的任何变化也会提交至目标内存。如果这一过程中磁盘内容也出现了变化,相关变化同样会被提交至目标 QEUM 实例的磁盘中。
4.执行割接点。当 QEMU 确认有足够多的内存页可以放心进行割接后,源和目标 QEMU 实例将会暂停。QEMU 会复制最后几页内存数据和机器状态,机器状态包括 CPU 缓存和下一条 CPU 指令。随后,QEMU 会让目标开始运行,这样目标实例就可以从源实例停止时的状态恢复运行了。

这些步骤概括介绍了 QEMU 实时迁移的执行过程。然而依然需要通过包含很多手工操作的方式来精确指定目标 QEMU 实例的启动方式。此外,上述过程中的每个操作都必须在正确的时间执行。


Linode 实现实时迁移的方式

在分析过 QEMU 开发者已经实现的技术后,我们该考虑具体用怎样的方式将其实给 Linode。这个答案恰恰是工作的重中之重。

在实时迁移工作流程的第 1 步,需要启动目标 QEMU 实例以接受传入的实施迁移连接。在实现这一步时,我们最初的想法是拿到当前 Linode 实例的配置文件,随后将其应用到目标计算机。理论上这应该很简单,但进一步思考就会发现,实际情况要复杂很多。尤其是,配置文件虽然可以告诉我们 Linode 实例是如何启动的,但并不一定可以完整描述启动后的 Linode 实例的完整状态。例如,用户可以在 Linode 实例启动完毕后通过热插拔的方式连接块存储设备,但这种情况并不会记录到配置文件中。

为了在目标主机上创建 QEMU 实例,必须对当前运行的 QEMU 实例进行剖析。我们通过检查 QMP 接口的方式对运行中的 QEMU 实例进行剖析,该接口为我们提供了与 QEMU 实例布局情况有关的丰富信息,但它无法帮助我们从来宾系统的视角了解实例内部正在发生的事情。例如,对于本地 SSD 和块存储,它只能告诉我们磁盘链接到哪里,以及虚拟磁盘连接到哪个虚拟化 PCI 插槽上。在查询 QMP 以及检查并分析了 QEMU 接口后,可以构建一个 Profile 来描述如何在目标位置创建一个完全相同的实例。

在目标计算机上将收到完整的描述信息,借此了解源实例到底是什么样,随后就可以在目标位置忠实重建这个实例,但此时还有一个差异。这个差别主要在于,目标 QEMU 实例在启动时使用了一个选项,该选项可以让 QEMU 接受传入的迁移。

至此,实时迁移的记录过程已经基本结束,接下来需要看看 QEMU 是如何实现这些操作的。QEMU 进程树由一个控制进程和多个工作进程组成,其中一个工作进程负责返回 QMP 调用或处理实时迁移等任务,其他进程需要一对一映射至来宾 CPU。来宾环境与 QEMU 端的功能相互隔离,具体行为类似于独立的系统。从这个意义来看需要处理三层内容:
第 1 层是管理层;
第 2 层是 QEMU 进程的一部分,负责处理所有操作;
第 3 层是实际的来宾层,负责与 Linode 用户进行交互。



目标实例启动并准备好接受传入的迁移后,目标硬件会告知源硬件开始发送数据。源端会在收到这个信号后开始进行处理,并会在软件中告知 QEMU 开始传输磁盘内容。软件会自主监控磁盘传输进度,借此检查传输操作是否完成,并会在磁盘传输完成后自动开始迁移内存内容。此时软件依然会自主监控内存迁移进度,并在内存迁移完毕后自动切换至割接模式。上述全过程都是通过 Linode 的 40Gbps 网络进行的,因此网络方面的操作都可以快速完成。


割接:关键环节

割接操作是实时迁移过程中最重要的一环,只有理解了它,才能完全理解实时迁移操作。在割接点状态下,QEMU 已经确认做好了所有准备,可以进行割接并在目标计算机上运行。源 QEMU 实例会让两端暂停运行,这意味着:
1.来宾系统被 “时停”。如果来宾系统横在运行时间同步服务(如 NTP),NTP 会在迁移完成后自动重新同步时间。这是因为系统时钟会产生几秒钟的落后。

2.网络请求停止。如果网络请求是 TCP 请求(如 SSH 或 HTTP),基本上不会产生可感知的连接中断;如果网络请求是 UDP 请求(如流媒体视频),可能会导致少量丢帧。


由于时间和网络请求均已停止,我们希望割接能尽量快速完成。然而为保证成功割接,还需要进行一些检查:
1.确保实时迁移顺利完成不出错。如果出错则要进行回滚,解除源 Linode 实例的暂停状态,不再进一步执行其他操作。开发过程中,我们在这方面进行了大量实验并解决了很多错误,虽然这为我们造成了很多头疼的问题,但最终都顺利解决了。

2.确保关闭源实例的网络,并在目标实例上正确连接。

3.让我们的其余基础设施清楚得知迁移后的 Linode 实例是通过哪台物理计算机运行的。

由于割接过程时间有限,我们希望能尽快完成上述操作。解决了这些问题后,即可继续进行割接了。源 Linode 实例会自动会自动收到“割接完成”信号并让目标实例运行起来。目标 Linode 实例会从源实例暂停时的状态恢复运行。源和目标实例上的其余内容则会被清理。如果目标 Linode 实例在未来某个时间需要再次进行实时迁移,则会重复执行上述步骤。

边缘案例概述

实时迁移的大部分过程都是直接实现的,但考虑到边缘案例后,该功能本身的开发也进行了大量扩展。这个项目的顺利完成很大程度上要归功于管理团队,他们坚信该工具有着极大的愿景,并提供了完成该任务所需的各项资源,另外当然也离不开坚信该项目能够成功完成的大量员工。在下列这些领域遇到了很多边缘案例:

1.通过开发内部工具为 Linode 客户支持人员和硬件运维团队进行与实时迁移有关的协调工作。这些工具与我们当时正在使用的其他同类工具较为类似,但也有些许差异,我们为此投入了大量开发工作:
1.1、该工具必须能自动检查数据中心内部的所有硬件设施,进而确定哪台主机可以成为每个需要迁移的 Linode 实例的最佳目标。在进行这种选择和决策时,考虑的相关规格包括可用 SSD 存储空间及内存分配情况等。
1.2、目标计算机的物理处理器必须与传入的 Linode 实例相兼容。尤其是 CPU 必须具备用户所运行的软件必不可少的某些功能(我们将其称之为 CPU 标记)。例如,AES 就是这样的一种功能,该功能提供了基于硬件加速的加密能力。实时迁移的目标计算机 CPU 必须支持与源计算机相同的 CPU 标记。我们发现这是一种极为复杂的边缘用例,下文将介绍我们所采用的方法。

2.优雅地处理故障,包括最终用户的干预或实时迁移过程中网络连接丢失等情况。下文还将详细介绍这些信息。

3.紧跟 Linode 平台自身的变化,而这是一个持续不断的长期过程。对于 Linode 平台当前和未来所支持的每个功能,我们都需要确保这些功能可与实时迁移兼容。详细信息请继续阅读下文。

CPU 标记

在向来宾操作系统呈现 CPU 方面,QEMU 有不同的选项。其中一个选项可将主机 CPU 的型号和功能(即 CPU 标记)直接传递给来宾系统。通过使用该选项,来宾即可不受约束地使用 KVM 虚拟化系统所支持的全部能力。当 Linode 首次采用 KVM 时(当时还没有实时迁移功能),为了实现最大化性能,我们就使用了该选项。然而在开发实时迁移功能的过程中,该选项为我们造成了很多挑战。


在实时迁移的测试环境中,源和目标主机是两台完全相同的计算机。但在现实世界中,硬件集群并非 100% 完全相同的,计算机之间的某些配置差异可能导致产生不同的 CPU 标记。这很重要,因为当一个程序被载入 Linode 的操作系统后,Linode 会向该程序呈现 CPU 标记,为了充分利用这些标记,程序可以将软件中的特定部分载入内存。如果一个 Linode 实例被实时迁移到不支持该 CPU 标记的目标计算机,程序将会崩溃。这可能导致来宾操作系统崩溃,甚至导致 Linode 重启动。发现有三个因素会影响到计算机的 CPU 标记如何呈现给来宾系统:
1.取决于购买时间,不同 CPU 之间会存在一些细微差异。取决于 CPU 制造商何时发布新硬件,年底购买的 CPU 可能与年初购买的具备不同标记。为了扩容,Linode 会持续购买新硬件,但就算两个硬件订单购买了同款 CPU,它们的 CPU 标记也可能存在差异。

2.不同的 Linux 内核可能会向 QEMU 传递不同的标记。尤其是,参与实时迁移的源计算机的 Linux 内核可能会向 QEMU 传递与目标计算机的 Linux 内核不同的标记。为源计算机更新 Linux 内核必须重启动,因此无法在实时迁移之前通过升级内核版本的方式解决这种不匹配问题,因为这会导致计算机上的 Linode 实例停机。

3.同理,不同的 QEMU 版本也会影响所呈现的 CPU 标记。更新 QEMU 同样需要重启动计算机。

因此在实现实时迁移时,我们必须设法防止程序因为 CPU 标记的不匹配而崩溃。可行的选项有两个:
1.让 QEMU 模拟 CPU 标记。但这可能导致原本快速运行的软件运行速度变慢,并且完全无法调查原因。

2.收集源计算机的 CPU 标记列表,确保目标计算机具备完全相同的标记,随后再进行迁移。这种方式更复杂,但不会影响用户程序的运行速度。我们最终选择了这种方式。

在决定对源和目标的 CPU 标记进行匹配后,我们使用下列两种方法的组合最终实现了目标:
1.第一种方法更简单。将源硬件的所有 CPU 标记发送给目标硬件,当目标硬件设置新的 QEMU 实例时,会通过检查来确保自己至少拥有和源 Linode 实例相同的标记。如果不匹配,将不进行实时迁移。

2.第二种方法更复杂,但可以避免因为 CPU 标记不匹配导致的迁移失败。在发起实施迁移前,我们会对具备可兼容 CPU 标记的硬件创建一个列表,随后从该列表中选择硬件来创建目标计算机。

第二种方法必须能快速执行,并且让我们的工作变得更复杂。某些情况下需要针对超过 900 台计算机检查最多 226 个 CPU 标记。为所有这 226 个 CPU 标记编写检查代码本就很困难,而这些代码还需要不断进行维护。但 Linode 的创始人 Chris Aker 提出的一个惊人想法最终解决了这个问题。

方法的关键在于为所有 CPU 标记创建一个列表,并将其表示为一个二进制字符串。随后可以使用 Bitwise and(“按位与”)运算来对比字符串。可以用下面这个简单的例子来演示这个算法。下面这段 Python 代码可以使用 “按位与” 对比两个数:
>>> 1 & 1
1
>>> 2 & 3
2
>>> 1 & 3
1

要理解为何 “按位与” 运算能产生这样的结果,首先需要将数字用二进制形式表示。一起看看十进制的 “2” 和 “3” 在用二进制形式表示的情况下,“按位与” 是如何处理的:
>>> # 2: 00000010
>>> # &
>>> # 3: 00000011
>>> # =
>>> # 2: 00000010

“按位与” 会对比二进制的 “数”,也就是两个不同数字中的 “位”。该操作会从上述数字最右边的位开始向左处理:
“2” 和 “3” 最右侧(第一)位分别是 “0” 和 “1”,0 & 1 的按位与结果为 “0”。
“2” 和 “3” 右数第二位都是 “1”,1 & 1 的按位与结果为 “1”。
这两个数的所有其他位都是 “0”,0 & 0 的按位与结果为 “0”。

因此完整结果的二进制表示就是 00000010,也就是十进制的 “2”。

对于实时迁移,CPU 标记完整列表会表示为一个二进制字符串,其中每一位都代表一个标记。如果一个位为“0”,代表对应的标记不存在;如果某个位为“1”,则代表标记存在。例如,一个位可以代表 AES 标记,另一个位可以代表 MMX 标记。这些标记在二进制字符串中的位置会维护并记录在案,随后用于我们数据中心内的所有计算机。

相比维护一组 if 语句来检查某个 CPU 标记是否存在,这种列表的维护工作无疑更简单也更高效。例如,假设总共需要追踪并检查 7 个 CPU 标记,这些标记可以存储在一个 8 位数字中(多出的一位供未来进行扩展)。例如这样的字符串可能类似于 00111011,最右侧的一位代表 AES 已启用,右数第二位代表 MMX 已启用,右数第三位代表其他标记已启用,以此类推。

在下文的代码片段中,我们可以看到哪些硬件支持这些标记的组合,这段代码可以在一个周期内返回所有匹配的结果。如果用一组 if 语句进行对比,则需要更多周期才能获得所需结果。如果进行实时迁移的源计算机包含 4 个 CPU 标记,这种情况下就需要 203400 个周期才能找到匹配的硬件。

实时迁移操作会在源和目标计算机上针对 CPU 标记字符串执行 “按位与” 操作。如果两个计算机的 CPU 标记字符串运算结果相等,意味着目标计算机是兼容的。该过程可参考下列 Python 代码片段:
>>> # The b'' syntax below represents a binary string
>>>
>>> # The s variable stores the example CPU flag
>>> # string for the source:
>>> s = b'00111011'
>>> # The source CPU flag string is equivalent to the number 59:
>>> int(s.decode(), 2)
59
>>>
>>> # The d variable stores the example CPU flag
>>> # string for the source:
>>> d = b'00111111'
>>> # The destination CPU flag string is equivalent to the number 63:
>>> int(d.decode(), 2)
63
>>>
>>> # The bitwise and operation compares these two numbers:
>>> int(s.decode(), 2) & int(d.decode(), 2) == int(s.decode(), 2)
True
>>> # The previous statement was equivalent to 59 & 63 == 59.
>>>
>>> # Because source & destination == source,
>>> # the machines are compatible

请注意,在上述代码片段中,目标计算机比源计算机支持更多的标记。此时可以认为目标计算机是兼容的,因为源的所有 CPU 标记都已包含在目标计算机中,这一点可以由 “按位与” 运算提供保证。

我们的内部工具可以使用上述算法得到的结果为可兼容的硬件构建一个列表。该列表会展示给我们的客户支持和硬件运维团队,这些团队可以使用我们的内部工具来编排不同的运维任务:
1.使用该工具为特定 Linode 实例挑选兼容性最高的硬件。
2.在不指定目标的情况下发起 Linode 实例实时迁移。随后,同一数据中心内兼容性最高的硬件会被自动选中并立即开始迁移。
3.通过一个任务,对一台主机上的所有 Linode 实例发起实时迁移。针对主机执行维护任务前通常会执行这样的操作。我们的工具会自动为所有实例选择目标,并为每个实例进行必要的编排。
4.将需要维护的多台计算机指定为一个列表,我们的工具可以跨越所有主机,自动为所有实例编排实时迁移。

仅仅为了让软件能够“跑起来”,就需要进行大量的开发工作……

失败处理

软件领域有一个话题很少被人讨论:优雅地处理失败。软件至少应该能够 “跑起来”。为了实现这一点,往往需要进行大量开发工作,实时迁移功能的开发也是如此。我们花了很多时间考虑如果该工具无法正常运行要怎么办,以及该如何优雅地处理这种情况。也考虑了很多场景,并确定了具体的应对方式:
1.如果客户希望从 Cloud Manager 访问 Linode 的某项功能该如何处理?例如用户可能会重启动 Linode 或为实例连接 Block Storage Volume。
解决方法:客户完全可以这样做。实时迁移会被打断,无法继续处理。这种处理方法是合适的,因为实时迁移可以稍后重试。

2.目标 Linode 启动失败怎么办?
解决方法:通知源硬件,通过专门设计的内部工具在数据中心内自动选择另一个硬件。此外还将通知运维团队,以便调查失败的目标硬件。这种情况曾在生产环境中发生过,我们的实时迁移可以顺利应对。

3.如果迁移过程中网络连接丢失该怎么办?
解决方法:自主监测实时迁移进度,如果过去一分钟内没有产生任何进展,将会取消实时迁移并通知运维团队。这种情况在测试环境之外从未发生过,但我们也针对这种场景做好了充分准备。

4.如果互联网的其他部分断开了,但源和目标硬件依然在运行和通信,并且源和目标 Linode 实例都在正常运行,此时会发生什么情况?
解决方法:如果实时迁移未进行到关键环节,将停止实时迁移,并在稍后重试。
如果已进行到关键环节,则将继续迁移。这一点很重要,因为源 Linode 已被暂停,目标 Linode 需要处于启动状态才能继续恢复操作。

这些场景都已在测试环境中进行了模拟,我们认为上述行为也是不同情况下的最佳应对措施。

紧跟技术变化的步伐

成功进行了数十万次实时迁移后,我们不免会考虑:“实时迁移的开发工作何时才能结束?”随着时间推移,实时迁移这项技术的使用范围会越来越广,并且会不断完善,因此该项目似乎会永远持续下去。回答这个问题的一种方法是考虑该项目的大部分工作什么时候会结束。答案也很简单:为了获得可靠、可信赖的软件,我们的工作还将持续很久。

随着时间推移,Linode 会增加新的功能,我们也许要继续努力保证实时迁移可以兼容这些功能。引入某些新功能时,可能无需围绕实时迁移执行新的开发工作,但我们可能依然需要测试该功能是否可以按照预期正常工作。对于某些功能,则可能需要在开发的早期阶段,针对实时迁移进行必要的兼容性测试和相关工作。和其他几乎所有软件类似,对于同一件事,通过不断研究,总能发现更好的实现方法。例如,从长远来看,为实时迁移功能开发更多模块化的集成方法,无疑可以降低维护负担。或者我们甚至可能将实时迁移的相关功能纳入到底层代码中,从而使其成为 Linode 一项拆箱即用的功能。