“不可变基础架构”这一术语最近在运维社区不断被讨论。InfoQ采访了几个富有经验的运维工程师,咨询了不可变基础架构的定义和边界,以及它的优缺点,尤其对比于当前十分流行的“理想状态”配置管理解决方案。在基础设施的有效管理方面,它是一个进步还是倒退?
专家们:
问题:
InfoQ:你们能简单解释下你们对不可变基础架构所下的定义吗?
Chad:几个月前我曾在我的博客上详细描述过这个问题。但对我来说,不可变基础架构的高层精华与函数型编程里的不可变数据结构拥有相同的质量。类似内存内数据结构这样的基础架构组件,是可以同时访问的运行组件。这点与共享状态存在同样的问题。
我对不可变基础架构的定义是:服务器(或其它)只部署一次,然后不再改变。如果因为某些原因需要修改,就意味着它们需要被丢弃。现有服务器上的软件从不更新。相反,服务器将被新的具有等同功能的服务器替换。
Mitchell:不可变基础架构将架构中的不同组件视为不可变或不能修改。与其修改任意组件,我们使用带有变化的新组件,然后将旧的移除。因此,你可以肯定(或更自信)你的架构已经能够运行。那么,对配置管理的变更将不会破坏现有可工作的架构。
不可变基础架构有时也被称作“凤凰服务器”,但是我觉得这一定义不够广泛,因为不可变性也可以应用于服务层,而不只是服务器层。
Mark:其实“不可变”这一术语实在是用词不当(如果基础架构真的是一成不变的话,那其用处也不大:整个架构将被冻结,什么都不会发生)。其实该术语试图引发的概念是让人们在磁盘映像阶段就尽量提前决定尽可能多的服务器配置细节,这样就“不需要配置”了。然后该想法认为这样能更快更稳定地加速机器。当问题发生时,我们只要丢弃该机器,从断点构建一个新的就可以了。这就是我对这一说法的理解。
尽管如此,我觉得这种说法还有很多地方有问题。更改配置到底意味着什么这一概念还非常不清楚,这使得该方案具有不必要的争议性。首先,提前决定主机的一切是不可能。合理的配置管理解决动态主机状态的同时,也处理了静态主机状态。以IP地址和网络配置为例,它们必须在机器开启后就确定配置好。如何保证随时执行新程序?如果程序崩溃,或启动失败怎么办?当机器启动后,如何区分什么能做以及什么不能做?我们可以添加包吗?我们是否应当允许来自DHCP的变动,而阻止来自CFEngine或Pupper的?为什么?在我看来,这些都是改变。因此没有任何机器会在任何意义上是一成不变的。
而我们应着眼的真正问题是:在连续基础上,我们希望主机表现出什么样的行为?用我的话来说,基础架构应维持什么样的承诺?
InfoQ:不可变基础架构能否在帮助防止系统分叉的同时,解决常规配置升级的需求?
Chad:当然可以。这只是不同模式的“更新”而已。只是与其更新现有系统,我们选择替换旧的而已。归根结底,我觉得这取决于你如何看待所谓“组件”这一粒度。15年前,如果我想更新UNIX系统中的软件组件,我会更新软件包及其依赖关系。而现在我则倾向将运行服务器实例看成是组件。如果你需要更新OS或系统中的程序包,只要将系统替换成已更新好的就可以了。如果你需要升级自己的应用程序代码,只要创建带有新代码的服务器实例,然后替换掉旧的服务器就可以了。
Mitchell:其实如果实施不合理的话,不可变基础架构会使系统分叉更加严重。在可变基础架构中,配置管理会持续执行以保持系统处于融合状态。而在不可变基础架构中,我们要承担部署不同版本的不可变部分所造成的高度分散环境而带来的风险。
尽管该错误来自对不可变基础架构的不合理拥护或采用。由于不可变基础架构,我们不用再担心破坏组件。因此当新版本出来时,我们最终应能替换所有组件。而我们的基本架构将高度融合。然而,大部分情况下都是规范和流程问题,导致有时很难在组织中执行起来。
Mark:我不认为不可变基本架构能帮助防止系统分叉。试图提前冻结配置导致了“微波晚餐”心态:只要把预先准备好的饭放入微波炉,然后填抱肚子就得了。可能有些人可以接受这些,但难免会遇到以下两个问题:要不得不到我们真正需要的,要不就是提供和管理足够多种类的预包装食品这一新问题。由于很难观察预包装镜像或“微波晚餐”里面究竟是什么,后者比起只用快速的、基于模型的配置管理来说是一个较难解决的问题。因此最好保证整个软件包是完全正确的。
另外,如果有什么东西稍有失误?你是否真的想返厂,重新打包,为的就是完成微波晚餐这一美梦?预包装不应该是实现统一的唯一途径。配置工具已经证明了这一点。我们不需要通过毁坏整个机器来使那些小的可重复的修改变得便宜。想想你会因为有个轮胎漏气或汽油用尽,就去买辆新车吗?
真正能防止系统分叉的是对你想要的结果具有明确的模型,而不是如何打包分叉起点的方式。
InfoQ:比起理想状态融合,不可变基础架构在处理架构上是否更好?如果是,它的主要优点是什么?如果不是,其主要缺点是什么?
Chad:我认为是的。当然任何场景都会涉及一些权衡需要我们做出决定,但我还是认为不可变基础架构比起理想状态融合是更好的默认答案。
不可变服务器更容易推理。它们在并发方面处理得更好。不仅更容易审计。由于初始状态被保留了下来,因而更容易重现。
Mitchell:当然它有它的优点,也有它的缺点。总体说来,我相信不可变基础架构是更强大的选择,也是正确的方式。但重点要理解的是:它并不是什么银弹,它也会引进一些之前从没遇到过的问题(在解决其它问题的同时)。
其优点是部署速度快、运行稳定、开发可测试性、版本控制和回滚能力。
对于不可变,由于所有的一切都“预编译”到镜像中,部署变得特别快。服务器一旦启动就开始运行。可能之后会有一些基本的配置需要处理,但是比较花费时间的那些部分都已经完成:编译软件,安装软件包等。
由于所有的东西都是不可变的,一旦有事件开始运行,我们可以确信没有外部力量可能会意外破坏配置。
不可变基础架构特别容易测试,而且其测试结果也非常精确,尤其针对运行时会真正发生什么。我喜欢的类推是:不可变基础架构对于配置管理类似于已编译应用程序对于源代码。我们可以单元测试源代码,但当编译时,我们无法保证程序库的版本变化不会破坏构建。同样,我们也可以重复地运行配置管理,即使当前它是没有问题的,我们也无法保证几个月后它依然能成功运行。但对于已编译应用程序或预构建服务器,所有的的依赖都已保证且构建好了;启动服务器时发生问题的可能性则非常非常低。
版本控制则非常简单和清晰。因为我们可以标记指定镜像中用于构建它的修改过的配置管理,以及修改过的应用程序和所有依赖版本等。而可变服务器,则比较难以确定每个服务器中存在的版本或修订。
最后,不可变基础架构具有回滚能力!很多人觉得“回滚就是个骗局”,而在某种程度上它确实是。如果你练习逐步增量修改你的基础架构,通过不可变基础架构回滚到近期以前版本既便宜又简单:只要将新服务器替换为由旧镜像启动的服务器就可以了。毫无疑问,有好几次回滚都帮助我们解决了一些严重的问题,而这点则很难在理想状态配置中实现。
Mark:对待基础架构的正确方式莫过于对系统规范有连续的知识联系(也就是我在CFEngine中所说的承诺)。为了满足目的以及支持业务连续性,我们必须保证能提供持续的一致性。除非所有的事务都设计执行于单独构建好的基础架构之上,改变开始点是不会解决问题的。它是政策上的简化,而非技术上的,还增加了开销。
我想说的是,比起平衡带有文件化融合调整的预计划镜像范式,“不可变”范式往往更糟糕。固定镜像的缺点在于其缺乏透明度和及时性。尽管其拥护者很可能会反对,但如果他们知道其磁盘镜像版本到底是什么的话,他们对机器状态将会有更好的了解。麻烦的是系统状态并非一直处于开始时所设置的状态,它也会随着运行过程中各种情况的变化而变化。这种观点把状态看得太单纯简单。
在某种程度上,将某些决策逻辑预先缓存成固定镜像可能会节省一些部署时间,但很可能由于需要重新部署机器,而非调整或修复那些简单问题,这些时间很快就消失了(及损失更多的业务连续性)。试想一下如果你的车出了问题,一般厂家会将其召回去打补丁,而不是赔你一辆新车,如果这样厂家早就破产了。
作为规模经济体一部分,缓存数据在优化工作上非常有道理,但我们不应该把其变成一个错误二分法,声称它是唯一的解决方法。一般情况下,带有针对“最后一刻”修改的配置管理,且基于部分磁盘映像的解决方案更具有商业意义。
实践中,“不可变性”(再次强调该术语用得比较差)意味着可丢弃性。当组织内的资源看起来过于丰富时,就会呈现出可丢弃性。可最后当资源变得不那么丰富时,我们就需要处理废物重利用。这时我们就会意识到可丢弃模式其实对环境特别有害(所有这类浪费的副作用是什么?),然后开始怀疑为什么就没有预先考虑到这些呢?我们当前所处阶段就呈现出丰富性,由于云环境隐藏了浪费成本,因此开发人员无需考虑这部分。但是我在想什么时候利润将缩水到足以让我们改变主意的地步。
InfoQ:不可变基础架构的边界是什么?比如:对于什么样的变化会使替换服务器比更新其配置/状态来得更合理?
Chad:如果存在有边界,部分变化将发生在现有服务器上,这样服务器就不是一成不变的了。理想状态下,我认为我们应该不允许有边界。“不可变”并非是个时髦词语,其本身具有意义。我们要不保持它的含义,要不停止使用它。取其中间是个危险的举动,可能会给不可变的预期收益带来错误的安全假象。
这意味着系统确实需要能够快速被修复,而当前我们替换基础架构所用的方法比起现有系统的热修复方法确实要慢些。因此我们需要某些可接受的、能维持不可变优点的混合性质。目前对Wunderlist的计划是实现带有内置自毁功能的热修复。因此当你需要热修复一个服务器时,它将自动被标识为需要更换。尽管我们还未自动化实现这一步骤,但已成功通过手动方式完成,并能成功运行。在我看来,这只是个丑陋的优化,而非好的设计方法。
Mitchell:在我看来,不可变基础架构的边界可以分解为我们想要快速修改问题的某些点,比如:小的配置变化、应用部署等。
但是仅仅想要在不可变服务器上部署应用程序并不意味着服务器就是不可变的。相反,我们应该将服务器的不可变性看成是一个洋葱:它是有层次的。服务器的基础层(操作系统和某些配置及程序包)是不可变的。应用程序本身也有自己的不可变组件:希望是个预编译二进制文件部署到服务器。因此尽管我们服务器上所带的组件可以说是可变的,但其本身确是不可变版本组件。
不可变基础架构中应用程序部署时我们不想做的是在不可变服务器上实时编译。因为编译可能失败,进而破坏应用程序,甚至可能破坏服务器本身的功能。
Mark:当某一特定配置到达其使用寿命时,很可能应该被替换掉。但这应该是个商业决策,而非技术决策。该决策可以以经济为基本,根据相关损益来做修改。但如果流程不透明或应用程序是任务关键的,则要小心其隐藏成本
由于某些原因,任何时候如果你想停止某一个系统,都是一个将其整个替换、而不必要打扰其他人的好机会。只要你有一个对需求有足够了解的模型并以最小影响将其替换,然后通过免提方式自动创建相应环境。现在由于某些应用程序带有分开的“分支”,并行部署多版本变得越来越简单。但我们需要记住的是并不是所有的一切都在云中。飞机、轮船、火箭及移动设备修改起来都比较脆弱,而且他们还都是运行关键任务的。另外嵌入式设备大部分时间依然在无线状态下工作,或以低速率通信。它们无法被重新镜像,或安全地、方便地被替换掉。但它们可以通过类似CFEngine这样的工具进行打补丁和管理,甚至不用网络连接就可以处理。
InfoQ:对于给定基础架构,是否能将所有服务器都看成是不可变的,还是说有些服务器必须分开对待?
Chad:对于不可变基础架构,我们有所谓的“秘籍”。关系型数据库就是个很好的例子。我认为虽然它可以以不可变形式运作,但其所需要花费的精力却不值得。如果我们是基础架构供应商的话,可能会在这里花费点精力;但我们所要做的是为客户创建应用程序,因此我们更偏向于将更多的内容外包给比如:Amazon RDS这样的管理服务。
我的目标是将整个基础架构设计成要么所有部分都是非直接管理的,要么所有组件都是完全可以替换的。而且我们基本达到了该目标,目前来看整个体验特别乐观。
Mitchell:这很有可能的,但确实有部分角色相对于其它更易于以不可变形式处理。其中无状态服务器就特别容易。然而类似数据库这样的状态服务器就棘手多了。因为如果服务器被破坏了,其相应状态也会被破坏,这往往是不可接受的。
Mark:运行单一整体应用程序的关键任务服务器一般情况下不能以这种可丢弃方式管理。根据我对它的了解,对该工作模式的主要争论是对它的信任。有些人宁肯相信镜像,也不相信配置引擎。他们倾向允许开发人员逐步地管理和维护自己的基础架构需求。尽管如此,如果我们强迫所有人只能通过磁盘镜像处理修改,那就限制了动态变化,比如:调整用于处理延迟的服务器的并行实例数量,或性能等其它方面的因素。哪怕忽略这些因素在商业决策上的考虑,开发人员在理解可扩展性和性能方面通常也没有正确的体验,更不用说提前部署了。
InfoQ:不可变基础架构和理想状态融合在工具上有什么主要的概念性不同吗?
Chad:理想状态融合执行起来其复杂度不是同一域的。尽管该想法令人着迷,但至少对于我的用例,它是过时的。系统存在越久,我就越担心。我无法100%确定其配置就是我想要的,也无法保证软件完全正确。成千上万的开发时间就浪费在解决这些问题上。
在不可变基础结构领域中,我将服务器看成是可替换的结构单元,类似汽车的各个部件。我们不更新部件,而是替换。系统是所有部件的总和。由于各个部件是不变的,因而可预见。在概念上非常简单。
Mitchell:其实两者在工具上并没有什么改变!实际上,所有用于理想状态融合的工具在不可变基础架构上也同样可用。不同的是,不可变基础架构往服务器或应用程序中添加了之前不存在的编译步骤。比如:与其启动服务器和运行Chef,我们现在使用Packer作为编译工具来启动服务器和运行Chef,并将它们转换为镜像。
唯一需要改变的是思维方式:不可变工具集只能运行一次,以构建镜像;而理想状态融合工具则期望运行多次来完成融合。在实践中,这不会造成多少问题,因为我们可以在构建镜像时,多次运行理想状态融合工具。但是用于构建不可变性的工具在第一次完成其预期目标时则更稳定。
Mark:如果想将系统配置冻结到预定义镜像中,我们需要提前了解该环境中的所有相关信息,然后说明我们不会尝试一下子去完全适应。我们会为了修复最小的头疼问题,而销毁主机。相对基于保存和持续性的方式,此方法对于变化显然不可持续。以生物学为例,可以将其看作组织,如果皮肤上掉了几个细胞,大可以由其它的大量细胞来完成相应工作。因此只有在资源充足而又多余时,该方法才能运行。
而理想状态融合,不论系统规模多大,我们可以完全预测它将会有修复、甚至对实际情况的简单修改及对实时商务问题的回应,然后针对这些做出最小的干预。这就类似生物学中的细胞DNA这一角色,由于在细胞内层并没有多余的细胞,因此需要不间断的修复流程。
由于在探索模式上有优势,在理想状态模型下管理大量信息比起大数据堆更容易。由于模型定义了跨版本度量标准,我们可以容易地跟踪状态的更改(为了合规和审计目的)。可以想象类似PCI或HIPPA这样的合规审计。怎么给审计员证明你的系统是合规的?如果你没有一个模型带有期望结果,其结果就是要到文档中到处寻找版本字符,这即昂贵又费时。
InfoQ:当前工具在选择和成熟度上,以及不可变基础架构模式本身是否足够成为主流?
Chad:这不大可能。尽管随着托管及内部的云供应商及框架的不断发展,各个基础架构变得越来越好了,但创建牢固的不可变基础架构在当前并非是障碍最小的路径。我认为随着时间的推移,大部分人会往这个方向发展,但就目前而言,它离主流还很远。
Mitchell:它们还不是主流。对比于一年前,尽管它们已经突飞猛进了,但还需要继续变得更成熟,并为不可变基础架构的早期采用者解决可能存在的不同问题。
尽管如此,所有工具都已绝对成熟,可以用于体验及测试基础架构中的某些方面。
Mark:除非所有软件都以无状态方式编写,不然我不相信它会成为主流。因为在分布式环境下,对故障的沟通将变得特别脆弱。即使不是,我也不认为它是可取的。难道我们真的就愿意去讨论是否要让全世界人民吃微波晚餐;或强迫厨师将所有食品打包到塑料袋里,然后再享用?如果历史告诉了我们什么,那就是人们都渴望自由。我们必须了解可丢弃性是个大规模经济策略,但并不适用于所有情况。
InfoQ:不可变基础架构是否适用于(以及如何适用于)那些将服务执行于物理基础架构的组织(尤其出于性能原因)?
Chad:当然可以。尽管服务器本身会运行很久,且很可能需要就地升级以保证有效运行,但由于可用于虚拟化的选择有多种,所有基于它的方法都是可能的。我认为将该方式往堆栈更深层发展也是有可能的,但我还没有必要这么做,也不想过去多猜想。
Mitchell:可以的。但它确实要求更多的规范工作。组织需要准备好优秀的自动化流程用于处理或重新镜像物理机器。不幸的是,很多组织并没有流程,而它在某种程度上却是实现不可变基础架构的先决条件。
比如:对于物理硬件,你确实需要类似Mesos或Borg这样的工具。
Mark:其实不可变基础架构并非就特定于虚拟化。同样的方法也可以应用到物理基本架构,只是服务不连续性会更大。
现今,不可变性经常与云中持续交付这一争论混淆起来,但我相信可丢弃计算很容易就会与持续交付目标相冲突,因为它往部署修改中添加了需要额外跳跃的循环,并降低结果的透明性。
InfoQ:从应用程序的架构和实现角度看,当锁定不可变基础架构这一目标时,我们应考虑哪些因素?
Chad:基础结构和服务必须可见。不论我们用什么来注册服务,都必须能通过API进行编程。我们必须准备好智能监控和度量,而且监控必须更多地关注服务的最终目标,而非初始基本架构,这很可能与你所习惯的非常不同。如果可能尽量保持一切都是无状态的。
正如我之前提及的,我们有像管理数据库系统这样的“秘籍”。我不会去评论你应该如何修改你的基础架构以拥有不可变及可丢弃数据库系统。值得庆幸的是这还不是我需要或愿意解决的问题。
Mitchell: 其实不需要改变什么就能达到不可变基础架构的目的,但架构和开发应用程序的某些部分则变得更加简单。不可变基本架构中的开发人员必须牢记他们所接触的任何服务可能会在任意时间死亡(希望能快速被替换)。单是就这种心态就会促使开发人员去建立更加健壮及失败友好的应用程序。
在强耦合、可变基础架构中,以下情况并不少见:先中断应用程序的相关服务,然后完全中断应用程序,直到相关服务重启后再重启应用程序。
除了牢记不可变基础架构的同时,应用程序也更加有弹性。就拿我们管理Vagrant云的基础架构来说,我们可以在替换和更新所有服务器(整个基础架构)时无任何可感知宕机时间,而且在替换过程中也不用触碰Web前端。Web应用程序只要不断重试某些链接,最终总会连接到网络上来。唯一的不良体验是某些请求的排队时间比正常的要长一些!
Mark:我们的目标并非是将应用程序设计用于不可变基础架构。我们不能单纯为了迎合工具而挑选工作。相反,不可变基础架构通用目的就是为了迎合应用开发人员的需求。关键问题是我们如何优化持续交付管道?
InfoQ:不可变基础架构让修复服务只需丢弃已损坏的服务器,而不用修复,这是否会造成对导致问题根本原因分析能力的下降?如果是,这会是个问题吗,又或是个新的运作方式?
Chad:我并不这么认为。哪怕针对最差的案例,我们也不需要改变根本原因分析方式。因为当某些事情出错时,更换和重启都是最后尝试。而对于最好的案例,不可变基础架构使得对可能解决方案的尝试变得更加简单,比如:可以一一调整变量,可以调出临时测试服务器,还可以从内到外的交换产品服务器等。
但是我理解你问题中的暗示。如果服务器的平均寿命不到一天的话,有些问题将被完全忽略(可参照:隐晦到以至于不存在)。同样如果问题只是偶尔出现,而且还忽略了服务器寿命这一变量的话,我们也很难查明这些问题。
但可能这点并不重要。
Mitchell:其实用于替换的服务器中很可能也会出现同样的问题,因此不可变基础架构并没有推广任何较差的根本原因分析方法。可能某些问题会较长时间被忽略,但最终大多数组织都会将其合理解决。
实际上,我觉得根本原因分析变得更强大了。由于组件是不可变的,有很大可能在相同条件下表现出相同的问题,这样重现、定位、解决问题,以及最终部署修改到整个基础架构都会变得更加简单。
另外,理想状态配置很有可能会加剧问题:配置管理系统计划好的运行可能会隐藏真正的根本问题,这样运营团队就需要花费更多的时间用来查找,甚至只是检测问题。
Mark:对因果证据的处理很可能加大了理解环境的难度。由于缺乏基于模型的配置,很多决策被推到难以理解的脚本或预设模板文件中,因而只有几个开发人员知道这些决策的背后理由。如果开发人员是唯一决策人,该流程在某种程度上可能可行,但想要让其重现则非常有挑战。如果掌握该知识的人离开了组织怎么办?
从心理学上我们了解到如果没有任何帮助,我们只能记住少量东西。问题是:我们怎样才能创建以知识为导向的架构,允许意图和结果是透明的同时,能快速地以最低重复尝试重现问题。这就是设计配置管理的目的,而且我依然相信这是管理大部分基础架构配置的最好方法。管理基础架构的关键是根据时间空间在相关范畴分离和采用不同的行为。在我”In Search of Certainty: The science of our information infrastructure”一书中有很多关于这方面的内容。
Chad Fowler Chad Fowler是国际上知名的软件开发者、培训师、经理、演讲者及音乐家。在过去的十年里,他曾与一些世界上最大的公司及最令人敬佩的软件开发者共事过。他还是6Wunderkinder的首席技术官。同时是多本流行软件书籍的作者和合著者,其中包括Rails Recipes和The Passionate Programmer: Creating a Remarkable Career in Software Development。
Mark Burgess Mark Burgess是CFEngine的首席技术官和创始人,曾是奥斯陆大学网络与系统管理学院的教授;同时也是CFEngine软件的主要作者。他攥写的书籍和论文涵盖了物理、网络和系统管理,直到小说。
Mitchell Hashimoto最广为人知的是Vagrant的开发者及HashiCorp的创始人。同时他还是O’Reilly的作者和专业演讲者。他是GitHub中追随者最多、活动最频繁、贡献最多的用户之一。他“痴迷于自动化”,致力在HashiCorp中创建高级的、功能强大的DevOps工具用以自动化所有事物。Mitchell很可能是世界上唯一一个对大多数虚拟化管理程序都有很深了解的人。
查看英文原文:Virtual Panel on Immutable Infrastructure