2.2 云的特性


云最根本的推动者是构筑在成千上万通过因特网访问的主机之上的虚拟化技术。我们首先探讨以IaaS为中心的特性,即虚拟化和IP管理,接着是PaaS提供的一些特性。然后,我们探讨一些普遍的问题,例如数以万计的主机所带来的后果,以及云是如何支持弹性的。

2.2.1 虚拟化

在云计算中,虚拟机(Virtual Machine,VM)是物理机的模拟。一个虚拟机镜像就是一个文件,其中包含了可引导的操作系统和在其上安装的软件。虚拟机镜像提供了启动虚拟机(或者更准确一些,虚拟机实例)所需的信息。本书使用“虚拟机”和“虚拟机实例”表示一个虚拟机实例,并使用“虚拟机镜像”表示启动虚拟机或虚拟机实例的文件。例如,亚马逊机器镜像(Amazon Machine Image,AMI)是虚拟机镜像,它能够用来启动弹性计算云(Elastic Compute Cloud,EC2)的虚拟机实例。

使用IaaS时,用户通过云供应商提供的应用程序编程接口(Application Programming Interface,API)从虚拟机镜像获取一个虚拟机实例。应用程序编程接口可能嵌入在命令行解释器、Web界面,或其他某种工具中。无论如何,它请求带有一组资源的虚拟机——CPU、内存和网络。获得的资源可能被托管在一台计算机上,而该计算机可能还托管其他虚拟机(多租户),但从用户的角度,供应商创建一个相当于独立的计算机。

1.创建虚拟机

要创建一个虚拟机,需要执行两个不同的活动。

用户发出一个命令来创建虚拟机。通常,云供应商有创建虚拟机的实用程序。需要将虚拟机所需的资源、虚拟机计费时对应的账户、要装载的软件(见下文),以及指定虚拟机安全性和外部连接的一组配置参数告知该实用程序。

云基础设施确定在哪个物理机上创建虚拟机实例。该物理机的操作系统称为虚拟机监视器(hypervisor),它为新虚拟机分配资源并将新机器“联网”,以便它能够发送和接收消息。给新虚拟机分配一个IP地址——该地址将用来发送和接收消息。我们已经描述了虚拟机监视器在裸机上的运行情况。有可能还会有其他操作系统类软件的层,但每一层都会引入额外的开销,因此最常见的情况就是我们所描述的这种。

2.装载虚拟机

每个虚拟机需要装载一组软件才能做有意义的工作。软件可以作为虚拟机的一部分进行装载,也可以在虚拟机启动后由虚拟机装载。可以通过装载和配置带有所需软件和数据的机器来创建虚拟机镜像,然后将机器内存中的内容(通常是以虚拟硬盘的形式)复制到持久性文件中。然后能够从该虚拟机镜像随意地创建新的虚拟机实例。

创建虚拟机镜像的过程称为烧制镜像。一个重度烧制的镜像包含了运行应用所需的所有软件,而一个轻度烧制的镜像则仅仅包含了一部分需要的软件,如操作系统和中间件容器。我们将在第5章探讨这些选择以及相关的权衡。

虚拟化引入了你应该注意的多种不确定性。

由于一个虚拟机与一个物理机上的其他虚拟机共享资源,所以虚拟机之间可能会有性能干扰。这种情况对于云用户来说可能尤其麻烦,因为他们通常看不到位于同一个物理机上的其他用户的虚拟机。

当加载虚拟机时,取决于底层物理基础设施和需要动态加载的其他软件,可能有时间和可靠性方面的不确定性。为了搭建不同的环境或者部署新版本的软件,DevOps运维常常需要频繁创建和销毁虚拟机。最重要的是,你要意识到这些不确定性。

2.2.2 IP和域名系统管理

创建虚拟机时,为其分配一个IP地址。IP地址是因特网上的计算机之间路由消息的机制。IP地址、路由以及它们的管理都是复杂的主题。接下来,探讨与虚拟机相关的域名系统(Domain Name System,DNS)和IP地址的持久化。

1. DNS

万维网(World Wide Web,www)之下是一个将URL的一部分转换成IP地址的系统。该功能关注URL的域名部分(例如,ssrg.nicta.com.au),这一部分可以通过DNS解析为一个IP地址。例如,作为浏览器正常启动的一部分,一个DNS服务器的地址会提供给浏览器。如图2-1所示,当你输入一个URL到浏览器中时,浏览器将该URL发送给它知道的DNS服务器,它与一个更大的DNS服务器的网络相连,该DNS服务器将该URL解析为一个IP地址。

域名表示了用于解析的路由路径。例如,域名ssrg.nicta.com.au会先去根DNS服务器查找如何解析.au。根服务器会提供澳大利亚DNS服务器的IP地址,该服务器保存澳大利亚的.com名称。.com.au服务器会提供nicta DNS服务器的IP地址,nicta服务器会提供ssrg的IP地址。

该层级结构的重要性在于,较低的层次(.nicta和.ssrg)完全由本地控制。因此,更改.nicta服务器中的ssrg的IP地址相对容易且是本地的。

此外,每个DNS项都有一个名为存活时间(Time To Live,TTL)的属性。存活时间作为DNS项(例如,域名和IP地址的映射)的过期时间。客户端和本地DNS服务器会缓存该DNS项,而该缓存项将在存活时间指定的时间内保持有效。当查询在过期时间前到达时,客户端/本地DNS服务器将从其缓存中直接获取IP地址。当查询在过期时间之后到达时,IP地址将由权威的DNS服务器来解析。通常,存活时间会设置一个比较大的值;它可能会设置为24小时。也可能会将存活时间设置为低至1分钟。我们会在第11~13章中的案例研究中看到,DevOps如何将本地控制和短存活时间结合起来使用。

有一点值得深入说明。在图2-1中,针对一个域名,DNS返回了一个IP地址。实际上,DNS能够返回多个地址。图2-2显示DNS服务器返回了两个地址。

 

图2-2 针对一个URL,DNS返回两个地址[标注法:架构]

客户会尝试第一个IP地址,如果没有响应,客户将尝试第二个,以此类推。DNS服务器可能会轮换服务器的顺序以便提供某种程度的负载均衡。

多个站点的存在可能有几个原因:

性能。一个站点要服务的用户太多了。从而需要多个站点。

可靠性。如果一个站点由于某种原因无法响应,客户可以尝试第二个站点。

测试。第二个站点可能会提供某些功能或一个新版本,这些是你想在一个受限的生产环境中测试的东西。这种情况下,到第二个站点的访问被限制在你想让其执行测试的那些人。第5章和第6章会提供有关该方法的更多细节。

2.虚拟机的IP地址持久化

只要虚拟机处于活跃状态,虚拟机创建时分配给它的IP地址就会一直保持。当虚拟机被终止、暂停或停止时,虚拟机就处于不活跃状态。这种情况下,IP地址会返回给云供应商的池中以便重新分配。

IP重新分配的后果之一是:如果应用中的一个虚拟机向应用中的另一个虚拟机发送了一个消息,发送方必须验证接收方的IP地址尚未过时。考虑下面的序列,这里你的应用至少包含VMA和VMB

1)VMB收到来自VMA的消息。

2)VMA发生故障。

3)云供应商重新分配了VMA的IP地址。

4)VMB向最初的IP地址做出响应。

5)消息传递到一个不属于你应用的虚拟机中。

要避免这个序列,你要么向云供应商请求持久IP地址(通常为高级用户提供),要么你的应用虚拟机就得在发送消息前验证接收方尚处于活动状态并且有相同的IP地址。我们在第4章探讨验证虚拟机的活动状态的机制。

2.2.3 平台即服务

到目前为止,我们探讨的许多方面都是特定于IaaS的。当使用PaaS产品(PaaS offering)时,你可用从很多这样的细节中抽身出来,因为PaaS服务驻留在栈的更高层上并在一定程度上隐藏了底层细节。

正如之前美国国家技术与标准研究所定义中所述,PaaS产品使你能够在预定义的环境中运行应用。例如,你可以将Java的Web应用编译成Web应用程序存档(WAR)文件,并将其部署在托管的Web应用容器中。然后,你可以根据特定的需要来配置服务,比如底层资源的数量(通常已标准化),并将该应用连接到托管的数据库管理系统(SQL或NoSQL)。虽然多数PaaS平台提供了托管的解决方案,或者在自己的基础设施上或者基于IaaS,一些平台也可用于自行管理的安装。

多数PaaS平台提供了一组核心服务(例如,托管Java Web应用、Ruby Gem包、Scala应用等)以及一系列扩展(例如,特定的监控方案、自动伸缩选项、日志流,以及警告等)。某种程度上,PaaS与传统Ops部门提供的一些服务相类似,Ops部门通常接管基础设施层的管理并向开发团队提供一组环境选项来托管他们的系统,开发团队可以在这些环境中进行选择。然而,与传统Ops部门相比,使用具有全球可用性的供应商PaaS通常意味着你会有更多的扩展并能更快地获得更新的选择。

与IaaS类似,如果你对具体的PaaS产品没有经验,你首先要学习怎么使用它。这包括平台特定的工具、结构、配置选项,以及业务逻辑。大多数PaaS平台上手都相对容易,但要掌握命令和配置中错综复杂的细节还要花些时间。

相比于IaaS,PaaS的额外抽象意味着你能够集中精力在系统最重要的部分——应用。你不必处理网络配置、负载均衡器、操作系统、底层的安全补丁等。但这也意味着你要放弃对底层的可见性和控制。如果这是可以接受的,那么使用PaaS就是很值得的。然而,当你之后最终需要额外的控制时,迁移可能非常困难。

2.2.4 分布式环境

本节中,我们要探索在云供应商环境中拥有成千上万的机器所产生的一些影响。这些影响关注各种操作所花费的时间、故障的可能性,以及这两方面在数据一致性上造成的后果。

1.时间

在独立的计算机系统中,从内存读取数据项的时间与从磁盘读取数据项的时间有很大的差异。由于硬件速度的提升,实际数字会随时间改变,这里只是直观地感受一下这种差别,从内存顺序访问1MB(大约100万字节)大概需要12μs(微秒)。从旋转型磁盘访问项目大概需要4ms(毫秒)将磁盘头移动到正确的位置。然后,读取1MB数据大约花费2ms。

在分布式环境中,消息是应用中不同进程之间的通信方法,消息在相同数据中心的一个来回大概需要500μs,而在加州和荷兰之间的一个来回大约花费150ms。

这些数字的后果之一是:确定哪些数据放在内存中或者哪些放在磁盘上是一个性能方面的关键决策。缓存容许在两个地方维护一些数据,但会引入保持数据一致性的问题。第二个后果是,持久性数据的物理存放位置也会对性能产生巨大的影响。结合这两个后果以及故障的可能性引出了使用不同风格的数据库管理系统来保持数据一致性的探讨,接下来将对此进行讨论。

2.故障

虽然任何特定的云供应商都保证高可用性,但这些保证通常是针对他们整个云的,而不是指其中的组件。单个组件的失败还是会影响你的应用。下面的列表是来自Google的一些数据,这些数据是一个数据中心可能遇到的各种故障。亚马逊发布的数据表明,在大约64 000台服务器(每个服务器配置两个磁盘)的数据中心,每天平均有5台服务器和17个磁盘发生故障。

下面是数据中心第一年运营中遇到的问题列表(来自Jeff Dean的演讲,Google):

大约0.5次过热(大多数机器<5分钟内关机,大约1~2天恢复)。

大约1次PDU故障(大约500~1000个机器突然消失,大约6小时恢复)。

大约1次机柜移动(有大量警告,大约500~1000台机器关机,大约6小时)。

大约1次网络重新布线(为期2天的时间内梳理了大约5%的机器)。

大约20个机柜故障(40~80台机器立刻消失,1~6小时找回)。

大约5次机柜变得不稳定(40~80台机器观察到50%的丢包)。

大约8次网络维护(4次可能引起大约30分钟的随机连接丢失)。

大约12次重启路由器(将DNS拿出几分钟)。

大约3次路由器故障(必须立即拉流量1小时)。

大约几十个小于30秒的DNS暂时性问题。

大约1000个单机故障。

大约几千个硬盘故障。

磁盘变慢、内存问题、错误配置的机器、运行不正常的机器等。

长途连接:野狗(wild dogs)、鲨鱼(sharks)、死马(dead horses)、醉酒的猎人(drunken hunters)等。

从应用或运维的角度,这些故障统计意味着什么?首先,任何特定的虚拟机或网络部分都可能发生故障。这个虚拟机或网络也许正在执行应用或运维功能。其次,由于组件串行使用的故障的可能性与单个组件故障率的积相关,所以一次请求涉及的组件越多,故障的可能性就越大。我们将分别讨论这两种可能性。

(1)虚拟机故障

分布式系统的架构师要做的主要决策之一是如何在应用的不同部分之间划分状态。如果无状态组件发生故障,可以直接替换它,无需考虑状态。另一方面,状态必须要维护在某个应用可以访问到的地方,而在同一个虚拟机中进行状态获取和计算会带来某种程度的开销。我们区分三种主要情况。

1)无状态组件。如果虚拟机是无状态的,则虚拟机故障的恢复可以通过创建同一个虚拟机镜像的另一个实例并确保消息正确地路由到该实例。从故障恢复的角度,这是最理想的情况。

2)客户端状态。会话(Session)是两个或多个组件或设备之间的对话。通常,给每个会话分配一个ID来提供对话的连续性。例如,你可以通过浏览器和服务器之间的一次交互来登录一个网站。在连续的消息中,会话状态使浏览器能够告知服务器你已成功登录,以及你是你所声称的人。有时,出于安全或应用程序的目的,客户端会添加额外的状态。由于客户端状态必须用消息发送来通知上下文的服务器或一组参数,所以它应该保持最小。

3)应用程序状态。应用程序状态包含了应用程序特定的信息或应用程序的特定用户的信息。它可能很大,比如一个知识库或网络爬虫的结果;它也可能很小,比如用户观看视频流时的当前位置。我们确定了3类应用程序状态。

a.少量的持久状态。持久状态要在多个会话之间或在发生故障的服务器和客户端之间进行维护。少量的持久状态可以保持在平面文件中或文件系统的其他结构中。应用即可以为每个用户保持状态也可以为整个应用保持状态。还可以使用工具将少量状态缓存起来,像ZooKeeper或Memcached这样的工具可以在多个虚拟机之间维护持久状态。

b.中等量的持久或半持久状态。之前看到的时间数据表明,将计算中经常用到的那部分持久状态缓存起来是有利的。在一个虚拟机的不同实例之间维护状态也是有好处的,该虚拟机容许共享该状态。在某种意义上,这相当于硬件层的共享内存,只不过它是通过网络在不同虚拟机之间完成的。像Memcached这样的工具意在管理一定量的共享状态,这些状态代表缓存的数据库记录或生成的页面。Memcached自动向其客户提供了一个一致的数据视图,并通过在服务器之间共享数据,为虚拟机故障时提供了容错性。

c.大量的持久状态。大量的持久状态可以保存在数据库管理系统所管理的数据库中或者像Hadoop分布式文件系统(Hadoop Distributed File System,HDFS)这样的分布式文件系统中。Hadoop分布式文件系统就像一个网络(或者至少是集群)文件系统并且它能自动维护数据项的副本来防止故障。它通过一些机制提供高性能,例如将数据按64M的块写入。大的块尺寸造成少量数据写入低效。因此,Hadoop分布式文件系统应该用于大数据量。既然Hadoop分布式文件系统的文件可以在一个集群内访问,那么任何客户故障都不会丢失已提交到Hadoop分布式文件系统的数据。

(2)长尾

如图2-3a所示,许多自然现象呈现出一种正态分布。值主要分布在平均值附近,越靠近边缘值分布的概率越低。在云上,许多现象,如请求响应时间,表现出一种长尾分布,如图2-3b所示。这个结果通常是由于故障的概率随着涉及实体的增多而增加,一个组件的故障会造成响应时间比平常变慢一个数量级(例如,在主网络链路断开并且错误被检测到后,网络数据包要通过不同的链路进行路由)。

在Map-Reduce完成时间、搜索查询的响应时间以及亚马逊云的启动实例中都观察到长尾现象。对于后者,满足一个启动实例请求的中位时间是23秒,但4.5%的请求超过了36秒。

尽管尚未证明,但我们的直觉是,分布的偏度(长尾的长度)是为满足一个请求而激活的不同云元素数量的函数。也就是说,诸如计算、读文件或者接收本地消息这样的简单请求都有接近正态的分布。复杂的请求,如大量的Map-Reduce任务、大型数据库的搜索或启动虚拟实例,将有像长尾这样的偏态分布。

 

图2-3 a)正态分布,值集中在均值附近,中值与均值相等;b)长尾分布,有些值离中值非常远

耗费特别长时间响应的请求应该当作故障。然而,这种请求的一个问题是,没有办法知道这个请求已经完全失败,还是最终会完成。防止长尾的一个机制是取消耗时过长的请求,例如,耗时超过了95%的历史请求,重新发起该请求。

3.一致性

考虑到故障的概率,稳妥的做法是复制持久性数据。如果数据项有两个备份,理想状况是,当客户读取数据项时,无论其读取哪个备份,他都应该获取到相同的值。如果数据项的所有备份在特定时刻拥有相同的值,那么就认为它们在那一时刻是一致的。记得将数据值写入持久存储是要花时间的。

在分布式系统中,通过引入锁来维护一致性,这些锁控制访问单个数据项的顺序。但锁定数据项会带来访问这些数据项的延迟,因此,产生了各种不同的方案来维护一致性并减少由锁引起的延迟。无论使用什么方案,引入锁带来的延迟将影响数据项的可用性。

另外,云的持久性数据可能按不同区域进行分割,以减少访问时间,特别是在数据量很大时。根据称为CAP(Consistency:一致性,Availability:可用性,Partition tolerance:分区容错性)原理的理论结果,不可能同时拥有完全可用、一致并分区的数据。最终一致性意味着当改变数据项时,分布、分区和复制的数据即便没有立即一致,在一段时间后将会一致——副本最终将变得一致。

4. NoSQL数据库

由于种种原因,包括CAP原理以及设置关系数据库系统造成的开销,许多数据库系统在NoSQL的名称之下被开发出来。起初,这个名字的意思是No SQL,由于现在有些系统支持SQL,所以现在它代表Not Only SQL。

NoSQL系统使用与关系系统不同的数据模型。关系系统的基础在于将数据呈现为表。NoSQL系统使用了从键值对到图的数据模型。NoSQL系统的兴起造成了几个结果。

NoSQL系统还没有像关系系统那样成熟,关系系统的许多功能(诸如事务、模式和触发器)还没有被这些NoSQL系统支持。如果应用程序需要这些功能,开发人员必须自己实现。

应用程序开发人员必须确定哪种数据模型最适合他们使用。不同的应用程序在其持久性数据方面有着不同的需求,这些需求必须在选择数据库系统前得到理解。

应用程序可能针对不同需求使用多个数据库系统。键值存储能够高效地处理大量半结构化数据。图数据库能够高效维护数据项之间的连接。使用多个不同数据库系统的好处是,你能够让系统与你的需求更好地匹配。第11章的案例研究给出了一个为不同目的使用多个数据库系统的例子。许可证费用和增加的维护费用是使用多个不同数据库系统的缺点。

5.弹性

快速弹性和供给是美国国家技术与标准研究所确定的云特性之一。弹性意味着服务一个应用的资源(如虚拟机)数量可以根据负载增加和减少。监控现有资源的利用率是度量负载的一种方法。

图2-4展示了客户通过负载均衡器访问虚拟机并通过监控确定不同虚拟机(这些虚拟机放在一个伸缩组中)的CPU和I/O利用率。监控将信息发送给伸缩控制器,这个控制器包含许多规则,这些规则确定何时向伸缩组添加服务器或者何时从伸缩组移除服务器。这些规则可能是被动的(例如,“当利用率达到某个阶段时,添加额外的服务器”)或者是主动的(例如,在早上7:00添加额外的服务器,在下午6:00移除它们)。当添加新服务器的规则被触发时,伸缩控制器会创建新的虚拟机并确保其装载正确的软件。之后,将新虚拟机注册到负载均衡器中,现在负载均衡器就有额外的虚拟机用来把消息分发给它。还可以通过各种应用程序编程接口来控制伸缩。我们会在第12章看到这方面的例子。