最近几个月以来,微服务架构和基于容器的虚拟化技术以迅雷不及掩耳之势席卷了整个软件开发社区。Adrian Cockcroft是云技术社区中最为人所认可的思想家之一, 他将微服务与Docker的结合视为一种“颠覆” ,他认为,在与容器结合使用后,微服务架构的优点得到了进一步的放大。微服务鼓励软件开发者将整个软件解耦为较小的功能片段,并且这些功能片段能够应对外界的故障。而容器进一步对这种解耦性进行了扩展,它能够将软件从底层的硬件中分离出来。这种方式所产生的结果是:应用程序能够更快地进行创建,并且更易于维护,同时又能够得到更高的质量。
在谈论基于容器的微服务时,人们经常会忽略存储的作用,但它却是大多数应用程序的核心所在。本文将对基于容器的微服务的优势展开讨论,同时还将分析:如果无法对具有状态的服务,例如数据库进行容器化,为什么会使微服务架构所带来的好处大大降低。
虽然对于“微服务”这个术语没没有非常精确的定义,不过如果我们看看使用这种架构的原因,以及如何使用这种架构的情形,我们就会发现它为软件团队带来的两大优势:即敏捷性与适应性。让我们来逐一分析一下这两个方面。
软件解决方案的敏捷性,指的是它能够快速进行变更的能力。Adrian Cockcroft曾在Netflix就任云端架构师一职,也是微服务的忠实支持者,他是这样描述在软件构建中进行快速变更的重要性的:“……基本上可以这么说,在软件开发中所做的每一件事,都是为能够比其他人更快地做出决策、推出产品这一最终目标所服务的。”
敏捷性是微服务架构的特性中最显著的一点。Martin Fowler也是一位在微服务领域方面非常突出的思想家与参与者,他表示:这种敏捷性的产生,是将运行中的系统解耦为“ 一系列小型服务 ”的结果。
微服务架构能够将对系统中其它部分的依赖加以限制,这种特性能够让基于微服务架构的应用在应对bug或是对新特性的请求时,能够快速地进行变更。这一点与传统的整体性架构恰恰相反,在传统架构中经常发生的一种情况是:“要对应用程序中某个小部分进行变更,就必须对整体架构进行重新构建,并且重新进行部署。”
Martin Fowler在上述那篇文章中还指出,由于微服务架构所表现出的天然的分布式特性,每个服务“在设计时都需要保证,它们能够应对(其它)服务产生故障的情况”。在类似于Netflix这样的公司中,他们的基础设施往往分布在全球,应对服务的故障是一种持续的工作。为了确保他们的基础设施能够应对这些挑战,Netflix推出了一套著名的工具集 Simian Army以测试他们的系统 ,这套工具集会有意地将正在运行的软件进行关闭,或是降级,以此测试系统在这种条件是否依然能够正常运作。
正是微服务架构中的分布式特性让它成为可能,在这套系统中的服务都能够应对以下一些可预计的情况:
Contino的CTO Benjamin Wooton在最近的一篇报告中表示,虽然微服务是构建具有良好适应性的软件的一种强有力的方式,但“ 天下没有免费的午餐 ”。和其它各种类似的架构一样,微服务的具体实现也有可能做得很糟糕。此外,由于这些服务是通过网络连接进行通信的,因此必须仔细考虑网络延迟可能会带来的影响。尽管如此,微服务还是获得了大量的关注,并且在Netflix、Spotify、Twitter和Gilt等公司已经得到了应用。正如Martin Fowler自己所说的:“……对于我的许多同事来说,微服务已经成为他们在 构建企业级应用时默认的风格了 ”。
微服务鼓励软件开发者将整个软件解耦为较小的功能片段,并且这些功能片段能够应对外界的故障。如果做的足够好,那么微服务的这一优点将提升应用的敏捷性和适应性。
虽然微服务已经成为某些大型工程组织中的新兴趋势了,但2013年Docker Inc.公司(之前叫做DotCloud)所发布的Docker则给微服务的蓬勃发展注入了更强的活力。Docker是一套开源工具,它能够以某种方式对现有的基于容器的虚拟化技术进行封装,使得它能够在更广阔的工程社区中得到应用。
在Docker出现之前,容器这种工具只在一些最尖端的组织中才会得到应用, 众所周知,Google就将所有的服务都封装在容器中 。而在Docker出现之后,人们对容器的关注和应用产生了爆炸式的增长。在DockerCon Europe 2014大会的主题演讲上,Adrian Cockroft对这种爆发式的关注进行了总结:“在2014年,Docker还是一只无人理睬的丑小鸭,而在2015年,它摇身一变,成为了一只人人喜爱的白天鹅”。
Docker的吸引力来自于两个方面:快速与可移植性
普通的虚拟机在每次开机时都需要启动一个完整的新操作系统实例,而Docker的容器能够通过内核共享的方式,共享一套托管操作系统。这意味着,Docker容器的启动和停止不需要几分钟,只要几百毫秒就足够了。
更快的速度就意味着,使用Docker容器创建的软件系统比起使用基于虚拟机的解决方案能够实现更高级别的敏捷性,即使将那些基于虚拟机的解决方案通过基于微服务的架构进行组织也是一样。此外,“ 容器化 ”的应用比起虚拟机和裸机的性能更好,在2014年IBM发布的一份研究报告中表明:“在几乎所有情况下,容器都能表现出与虚拟机相等、或者是更好的性能。”
在基于虚拟机的解决方案中,应用的可移植性通常来说会受到云提供商所支持的地区的限制,如果是在自托管的环境中运行企业软件,那么可移植性就限制在数据中心内。原因在于,不同的云提供商通常会提供不同格式的虚拟机。如果使用 Packer 这样的工具,那么在不同的云服务中使用运行相同的虚拟机镜像文件也是可以的,但需要进行许多额外的工作。虽然可行,但它也将用户限制在一个单一的平台中。下文将进一步分析这一点的问题所在。
Docker容器的设计理念是“ 一次编写,到处运行 ”,这可以使开发者避免上面这种限制。工程团队与运维团队可以将他们的基础设施扩展到多个云提供商的服务中,只要Docker的守护进程还在运行,就能够保证应用程序的正常运行。这种将应用从云提供商中进行解耦的方式能够给予IT团队更大的自由度,也可以在与各个提供商之间的对冲中,提高软件解决方案的适应性。
在DockerCon Europe 2014大会上,Adrian Cockroft将微服务架构与 Docker容器 的结合视为一种“颠覆”。原因十分明显:当与容器结合使用时,微服务架构所具备的优势将被进一步放大。微服务鼓励软件开发者将整个软件解耦为较小的功能片段,并且这些功能片段能够应对外界的故障,这为我们带来了敏捷性和适应性。而Docker将我们的软件从底层的硬件中进行解耦,这为我们带来了在基于虚拟机的解决方案中见所未见的可移植性与速度。
虽然对 微服务 与 Docker 容器的关注在2014年得到了爆炸式的增长,但它的发展面临着一个重大障碍,为了理解这一点,我们需要仔细分析,通常所说的无状态应用程序设计具体是指什么。
微服务架构的创建者倾向于在任何可能的情况下使用无状态的服务 、而不是有状态的服务。无状态应用程序设计的主要优点在于:它能够平稳地应对为服务添加或移除某些实例的场景,而无需对应用程序进行重大的变更或进行配置的改动。比方说,如果服务的负载产生了突发性的增长,可以为服务加入更多无状态的web服务器,而如果某个无状态的服务器挂机了,也可以方便地用另外一台服务器取代它。因此,无状态的服务更容易实现敏捷性和适应性。
尽管无状态的应用程序设计是大势所趋,但在许多系统中,状态是不可避免的。比方说,任何需要保存数据的系统都必须对状态进行管理,而且有状态的工具在数量和种类上都在不断增长,例如MongoDB、PostgreSQL、RabbitMQ、Redis、Cassandra、Riak、MySQL和ElasticSearch等等。现代软件开发者所用到的数据服务在不断增长。随着微服务架构逐渐成为规范,开发者和架构师开始在应用程序的不同地方使用不同类型的数据服务。要解析几十亿的日志信息?用ElasticSearch。要处理工作队列?用Redis或是RabbitMQ。客户的注册信息呢?那就用MySQL或MongoDB。以上这些场景完全有可能同时出现在某个应用程序中。
即使在现代的无状态应用程序架构中,状态也会产生在每个地方,要点在于如何对这些状态进行管理。
出于Docker的爆炸式增长速度,有些基本的问题没有得到回答,或只是得到了部分性的回答。在这些问题中,出现的最频繁的就是关于状态的问题了,通常也称为关于持久化或存储的问题。
在Docker出现的早期,曾经有一种说法认为:由于保持状态方面的问题, Docker永远无法获得广泛的应用 。虽然这则预言最终没有成为现实,但这个问题始终没有得到解答。Andrew Phillips是Xebia Labs产品管理部门的副总裁在他的博客帖子 “2015年,有关微服务、容器和Docker的8个问题” 中,将‘存储’这个问题放在了第一位。
由于在Docker中管理有状态服务(例如数据库)方面的信息或解决方案太少,因此软件开发社区中有很大一部分人选择了忽略在容器中使用状态信息的问题。在大多数情况下,容器只用于应用程序中无状态的那一部分,而类似于数据库这样的有状态服务则被视为一种“ 支持性服务 ”,需要在应用程序生命周期的外部进行管理。这种建议虽然开始流行起来,但它会让数据这一应用程序的核心内容变成了 其它人的问题 。这严重地限制了使用基于容器的微服务所带来的好处,让它无法在完整的应用程序中得到应用。
有道是麻绳专在细处断,如果工程团队与运维团队想要从微服务架构和Docker中得到最大的敏捷性和适应性,他们就必须使有状态服务的速度和可移植性达到与无状态服务相同的标准,而不是在应用程序的外部进行管理,这样会减弱对于服务的控制能力。先记住这一结论,再来看看,将管理有状态服务的工作放在基于容器的微服务架构中,究竟有哪些特别的优点?
Barry Boehm和Philip N. Papaccio在一篇1988年发表的论文中,首先提出了一个概念,即bug在开发周期中发现的时机,随着周期的推移,修复它所花费的时间将以指数级上升 1 。他们估计,修复在“实际运行中”所发现的bug,比起在开发周期中修复它们,所花的时间要多出50至200倍。Barry Boehm和 Victor R. Basili在2001年再次提起这一话题,这次他们的分析要乐观一些,他们表示在生产环境中修复bug所花的时间大约会多出5倍 2 ,其他人的报告也反映出了类似的趋势。
之后的调查 表明,工程师修复在生产环境上发现的bug,比起在代码审查或单元测试阶段修复它,所消耗的精力会多出40倍,比起在系统测试阶段修复bug的精力要多出5倍。
无论报告的结果具体是多少,这里的观点是很明确的:能尽早发现bug是最理想的结果。但开发者如何做到这一点呢?假设工程团队已经维护了一个可以由开发者运行的自动化测试集,那么有一件东西可以同时减轻IT的负担,即 开发/生产环境的等同性 。
自从Heroku的工程师发布了那篇著名的 Twelve-Factor App宣言 之后,其中所讲到的开发/生产环境的等同性这一思想获得了更广泛的认可。这一思想的本意是尽量减少创建代码的“开发”环境,与实际运行代码,并且由真正的客户所使用的“生产”环境之间的不同。
基本原理非常简单:如果代码所测试的环境与实际运行的环境是不同的,那么测试的结果就有可能是无效的,团队或许将为些付出更大的代价,因为他们不得不在生产环境上修复bug。
与虚拟机相比,运行容器所需的内存要小得多,因此开发者能够在开发机器上运行多个容器。想象一下,如果在生产环境中运行了10台虚拟机,那么无论它们的内存占用有多小,想要在一台普通的开发机器上运行总共10个虚拟机也是基本不可能的。
因此,开发者为了能够在本地进行测试,不得不采用一些捷径,例如在开发环境中使用SQLite,然后祈祷在生产环境中能够正常运行。不过,正如Heroku的JVM语言负责人Joe Kutner所说的一样,他很明确地 表示 :“SQLite不等于MySQL,也不等于PostGresQL。”每一次使用这种捷径,都会减少开发/生产环境的等同性,并且使bug出现的时机发生在交付管理中更晚、并且代价更高的阶段的机会也大大增加了。
然而,在开发机器中运行10个Docker容器却是小菜一碟,这样一来,开发者就能够在开发环境中模拟生产环境,从而增加开发/生产环境的等同性。
在开发环境与生产环境之间建立等同性,以此提高在早期发现bug的可能性,这一原理建议:应用程序的每一部分,包括有状态的服务,例如数据库,都应该在本地进行测试,就像它们在生产环境中运行一样。
随着越来越多的公司将它们的内部基础设施渐进式地、或是全部搬迁到基于云端的服务,对提供商的依赖这方面的顾虑也在上长。Dimensional Research在 2014年进行了一次全球性的调查问卷 ,共有超过650名IT专家参与了调查,结果表示,有超过91%的受访者打算在未来的12个月以内“将产品部署在云端”,并且有77%的人表示“正计划将产品部署到多个云”。
在容器出现以前,要跨多个云端运行产品是一件相当复杂的任务。各大处于竞争中的云提供商的虚拟机格式都有所不同,从配置管理所需的精力来看,要在多个云端运行产品的代价几乎是不可接受的。
由于Docker容器包含了运行应用程序所需的运行时环境,以及刚好足够的操作系统资源,因此对于基础设施唯一的要求就是安装Docker守护程序。这样一来,软件公司只需要在每个云提供商的环境中维护一台能够运行Docker的虚拟机就可以了。
Docker “一次编写,到处运行”的能力原本受限于端到提供商的依赖,不过,如果你仅仅对应用程序中无状态的部分使用容器,那么这一论点也就不成立了。
只有放置在与应用服务器足够接近的位置,数据库才能运行在最好的状态下。因此,如果无状态应用服务器无法远离所维护的数据,那么将这些服务器在不同的云端主机之间进行移动也变得没有什么价值了。而一旦数据库和数据本身被容器化,情况就变得不同了。如果运维部门需要对整个数据中心进行迁移,那么经过完全容器化的应用程序就可以在不同的数据中心中进行移动了。
由于长距离移动大量的数据集所面临的巨大挑战,因此运维团队不太可能将这种操作视为一种常规的操作。尽管如此,由于这种方案能够在不对应用程序的架构进行重新调整的情况下进行迁移,因此对于那些希望将对某个云提供商的依赖降至最低的团队来说,这种方案依然有着很大的吸引力。
Cloudscaling Inc.公司的CTO及联合创始人Randy Bias在2012年的一次 演讲 中,引用了Bill Baker所提出的“宠物还是公牛”(“pets vs. cattle”)这一比喻,将其引申到服务器的场景中。Bias说:“宠物”式的系统管理方式,是指你“给它们取名字,当它们生病了,你得照看它们,直到恢复健康为止”。在这种场景中,运维人员不仅熟知他们所管理的服务器,并且也十分熟悉部署在这些服务器上的各种软件。这种温柔体贴的关爱式照看所导致的结果是“ 雪花 ”式的服务器的增加,这些服务器通常是独一无二的、脆弱、难以进行改变的。
如果某个数据中心中充斥着大量的雪花式服务器, 其结果之一 就是形成开发者和运维人员之间的一种对抗性关系,因为他们彼此的动机不同。开发者希望变更越多越好,因为他们的使命是尽快发布新的软件,而运维人员则希望变更越少越好,因为他们的使命是维持现有软件的稳定性。
打破这一僵局的方案要从两方面进行。在组织层面上,Devops这一趋势正试图将开发与运维团队带到一起,让他们的使命保持一致。同时,在技术层面上,运维人员必须改变他们看待服务器的方式,Bias解释说:“你对他们进行编号,当他们生病了,你就射杀他(像射杀一头公牛一样)”。
这种认识首先催生了短期服务器,或称为“ 凤凰服务器 ”的存在,随后必然会催生出那些在每次软件变更时都需要重新部署的服务器,也被称为“ 不可变服务器 ”。而Docker容器就能够创建出完美的不可变服务器。
将服务器视为公牛,让Netflix这样的公司能够在更大的规模上实现敏捷性与适应性。Adrian Cockroft 认为:“ 对可移植的容器部署进行标准化,能够节省时间与精力 ”。这里的关键在于,为运维设立一个小型的、定义良好的管理过程。这也意味着,如果要为有状态的应用和无状态的应用分别维护不同的工具集,就走向了错误的方向。
Google云平台的全球解决方案主管Mike Ward最近 表示 :“如果你正在构建某个应用程序,你的选择包括‘裸机’、虚拟化的本地基础设施、公有云和私有云,以及各种可用的PaaS选项。那么你在打包与部署软件上最多可以有 六种不同的方式 !而通过标准化的容器格式,这些部署模式中的任意一种的提供商都可以实现一种统一的体验……”。
从这一优点上来看,如果容器格式的标准化仅限于无状态的应用程序组件,那么标准化的好处就降低了,因为你还是需要管理两种不同的系统:无状态的系统和有状态的系统。
如果能够在所有应用程序组件,包括有状态的组件和无状态的组件,以及底层的基础设施之间提供一个短小的、定义良好的表面区域,我们就有机会进一步缓解开发者与运维人员之间的对抗关系。通过为整个应用程序提供一组单一的运维工具,混淆不清的情况就变为一种健康的关注分离场景了。
在DockerCon 2014大会上,来自IBM的Boden Russel问道:“ 你们认为是什么在推动着技术方面的业务决策呢 ?答案是效益、效益、还是效益。”
虚拟机的一个主要卖点在于,它能够更有效地使用底层硬件的资源,这种衡量标准也经常被称为“密度”。这种思想很容易理解:运维部门希望将应用程序隔离在不同的服务器上,但对于裸机来说,这就意味着那些服务器通常什么事也不做,只是在浪费钱而已。而使用虚拟机能够让底层的硬件进行共享,这就意味着更高的密度、更低的成本,或更高的收益。
虚拟化技术本身也有一些问题存在,尤其是在数据库方面会明显地表现出性能问题,因为数据库的应用倾向于大量的I/O操作。这就是为什么许多服务提供商在提供数据库即服务时,会使用容器技术代替虚拟化技术。比方说,在Rackspace设计基于云端的关系型数据库服务“ Rackspace Cloud Database ”时,选择了Linux容器,而不是虚拟机。J.R. Arredondo在2013年的一份白皮书中写道,虚拟机“得到性能补偿的地方,也正是数据库正常运行所需要的部分,只是访问者没有意识到它已经被虚拟化了”。
Arredondo在一份白皮书中概述了使用容器管理数据库的原因和这种方式的优点,他提起了两种传统的虚拟化选择,硬件虚拟化和半虚拟化(paravirtualization),展现在Racespace面前的选择就如同“第二十二条军规”一样的处境(意指左右为难)。硬件虚拟化会对客户机操作系统(Guest OS)的性能造成影响,并且在运行时需要占用更多的资源。半虚拟化与硬件虚拟化相比,能够实现更好的性能,但是要付出可移植性方面的代价。
Arredondo表示:“基于容器的虚拟技术所占用的资源是很少的,通常在2%左右,而传统的硬件虚拟技术会占用10%到30%左右的可用CPU资源”。
通过在存储服务上使用了基于容器的解决方案,Rackspace最终在两方成实现了收益:一方面,由于密度的增加,对于底层硬件的占用减少了。另一方面,由于性能的提高,他们的服务在市场上获得了更强的竞争力。
Rackspace的例子并不只是想表明为什么服务提供商应该采用基于容器的虚拟化技术。随着越来越多的企业业务依赖于通过软件为客户提供服务,对于基础设施的成本进行优化,并进一步提高性能的需求开始对于每个服务提供商都提出了相似的要求。在容器中运行服务器,有助于让企业将它们的注意力重新转移到业务的收益这一方面。
本文对于容器技术的爆炸式增长是如何改变了位于前沿的公司构建、交付和维护软件的方式进行了深入研究。当容器技术与微服务进行结合之后,就能够将敏捷性及适应性提高到一个空间的规模。
不过,在这一巨大改变发生的早期,有一些挑战尚未得到充分的研究,尤其是在数据库方面。随着越来越多的公司开始认识到容器技术与微服务架构所带来的优点,对于这些挑战进行深入钻研的压力也在逐渐增长,因为如果在存储方面的解决方案不能够与容器进行良好地配合,由微服务革命所带来的优点也不能得到尽情地发挥。
Luke Marsden 是ClusterHQ, The Container Data People公司的联合创始人兼CTO。他在创建web应用、使用容器技术和分布式存储方面有着12年的经验。为了应对在运行大规模web应用时所面对的实际运维问题,他创办了ClusterHQ公司。Luke具有牛津大学的计算机科学这门学科的学位。
查看英文原文: The Microservice Revolution: Containerized Applications, Data and All