什么是云原生应用架构

本文译自Migrating to Cloud Native Application Architectures第一部分,归档到https://github.com/rootsongjc/migrating-to-cloud-native-application-architectures

第1章 云原生的崛起

软件正在吞噬这个世界。—Mark Andreessen

近些年来,在一些长期由领导者支配的行业中,这些领导者的领先地位已经岌岌可危,这都是由以这些行业为核心业务的软件公司造成的。像Square、Uber、Netflix、Airbnb和特斯拉这样的公司能够持续快速增长,并并拥有傲人的市场估值,成为它们所在行业的新领导者。这些创新公司有什么共同点?

  • 快速创新
  • 持续可用的服务
  • 弹性可扩展的Web
  • 以移动为核心的用户体验

将软件迁移到云上是一种自演化,使用了云原生应用架构是这些公司能够如此具有破坏性的核心原因。通过云,任何能够按需、自助弹性提供和释放计算、网络和存储资源的计算环境。云的定义包括公有云(例如 Amazon Web Services、Google Cloud和Microsoft Azure)和私有云(例如 VMware vSphere和 OpenStack)。

本章中我们将探讨云原生应用架构的创新性,然后论证云原生应用架构的主要特性。

为何使用云原生应用架构

首先我们来阐述下将应用迁移到云原生架构的动机。

速度

天下武功,唯快不破,市场竞争亦是如此。想象一下,能够快速创新、实验并交付软件的企业,与使用传统软件交付模式的企业,谁将在市场竞争中胜出呢?

在传统企业中,为应用提供环境和部署新版本花费的时间通常以天、周或月来计算。这种速度严重限制了每个发行版可以承担的风险,因为修复这些错误往往跟发行一个新版本有差不多的耗时。

互联网公司经常提到它们每天极版次发布的实践。为什么频繁发布如此重要?如果你可以每天实现几百次发布,你们就可以几乎立即从错误的版本恢复过来。如果你可以立即从错误中恢复过来,你就能够承受更多的风险。如果你可以承受更多的风险,你就可以做更疯狂的试验——这些试验结果可能会成为你接下来的竞争优势。

基于云基础设置的弹性和自服务的特性天生就适应于这种工作方式。通过调用云服务API来提供新的应用程序环境比基于表单的手动过程要快几个数量级。然后通过另一个API调用将代码部署到新的环境中。将自服务和hook添加到团队的CI/CD服务器环境中进一步加快了速度。现在,我们可以回答精益大师Mary Poppendick提出的问题了——“如果只是改变了应用的一行代码,您的组织需要多长时间才能把应用部署到线上?“答案是几分钟或几秒钟。

你可以大胆想象 一下,如果你也可以达到这样的速度,你的团队、你的业务可以做哪些事情呢?

安全

光是速度快还是不够的。如果你开车是一开始就把油门踩到底,你将因此发生事故而付出惨痛的代价(有时甚至是致命的)!不同的交通方式如飞机和特快列车都会兼顾速度和安全性。云原生应用架构在快速变动的需求、稳定性、可用性和耐久性之间寻求平衡。这是可能的而且非常有必要同时实现的。

我们前面已经提到过,云原生应用架构可以让我们迅速地从错误中恢复。我们没有谈论如何预防错误,而在企业里往往在这一点上花费了大量的时间。在追寻速度的路上,大而全的前端升级,详尽的文档,架构复核委员会和漫长的回归测试周期在一次次成为我们的绊脚石。当然,之所以这样做都是出于好意。不幸的是,所有这些做法都不能提供一致可衡量的生产缺陷改善度量。

那么我们如何才能做到即安全又快速呢?

可视化

我们的架构必须为我们提供必要的工具,以便可以在发生故障时看到它。 我们需要观测一切的能力,建立一个“哪些是正常”的概况,检测与标准情况的偏差(包括绝对值和变化率),并确定哪些组件导致了这些偏差。功能丰富的指标、监控、警报、数据可视化框架和工具是所有云原生应用程序体系结构的核心。

故障隔离

为了限制与故障带来的风险,我们需要限制可能受到故障影响的组件或功能的范围。如果每次亚马逊的推荐引擎挂掉后人们就不能再在亚马逊上买产品,那将是灾难性的。单体架构通常就是这种类型的故障模式。云原生应用程序架构通常使用微服务。通过将系统拆解为微服务,我们可以将任何一个微服务的故障范围限制在这个微服务上,但还需要结合容错才能实现这一点。

容错

仅仅将系统拆解为可以独立部署的微服务还是不够的;还需要防止出现错误的组件将错误传递它所的依赖组件上造成级联故障。Mike Nygard 在他的《Release It! - Pragmatic Programmers》一书中描述了一些容错模型,最受欢迎的是断路器。软件断路器的工作原理就类似于电子断路器(保险丝):断开它所保护的组件与故障系统之间的回路以防止级联故障。它还可以提供一个优雅的回退行为,比如回路断开的时候提供一组默认的产品推荐。我们将在“容错”一节详细讨论该模型。

自动恢复

凭借可视化、故障隔离和容错能力,我们拥有确定故障所需的工具,从故障中恢复,并在进行错误检测和故障恢复的过程中为客户提供合理的服务水平。一些故障很容易识别:它们在每次发生时呈现出相同的易于检测的模式。以服务健康检查为例,结果只有两个:健康或不健康,up或down。很多时候,每次遇到这样的故障时,我们都会采取相同的行动。在健康检查失败的情况下,我们通常只需重新启动或重新部署相关服务。云原生应用程序架构不要当应用在这些情况下无需手动干预。相反,他们会自动检测和恢复。换句话说,他们给电脑装上了寻呼机而不是人。

弹性扩展

随着需求的增加,我们必须扩大服务能力。过去我们通过垂直扩展来处理更多的需求:购买了更强悍的服务器。我们最终实现了自己的目标,但是步伐太慢,并且产生了更多的花费。这导致了基于高峰使用预测的容量规划。我们会问”这项服务需要多大的计算能力?”然后购买足够的硬件来满足这个要求。很多时候我们依然会判断错误,会在如黑色星期五这类事件中打破我们的可用容量规划。但是,更多的时候,我们将会遇到数以百计的服务器,它们的CPU都是空闲的,这会让资源使用率指标很难看。

创新型的公司通过以下两个开创性的举措来解决这个问题:

  • 它们不再继续购买更大型的服务器,取而代之的是用大量的更便宜机器来水平扩展应用实例。这些机器更容易获得,并且能够快速部署。
  • 通过将大型服务器虚拟化成几个较小的服务器,并向其部署多个隔离的工作负载来改善现有大型服务器的资源利用率。

随着像亚马逊AWS这样的公有云基础设施的出现,这两个举措融合了起来。虚拟化工作被委托给云提供商,消费者只需要关注在大量的云服务器实例很想扩展它们的应用程序实例。最近,作为应用程序部署的单元,发生了另一个转变,从虚拟机转移到了容器。

由于公司不再需要大量启动资金来部署软件,所以向云的转变打开了更多创新之门。正在进行的维护还需要较少的资本投入,并且通过API进行配置不仅可以提高初始部署的速度,还可以最大限度地提高我们应对需求变化的速度。

不幸的是,所有这些好处都带有成本。相较于垂直扩展的应用,支持水平扩展的应用程序的架构必须不同。云的弹性要求应用程序的状态短暂性。我们不仅可以快速创建新的应用实例;我们也必须能够快速、安全地处置它们。这种需求是状态管理的问题:一次性与持久性相互作用如何? 在大多数垂直架构中采用的诸如聚类会话和共享文件系统的传统方法并不能很好地支持水平扩展。

云原生应用程序架构的另一个标志是将状态外部化到内存数据网格,缓存和持久对象存储,同时保持应用程序实例本身基本上是无状态的。无状态应用程序可以快速创建和销毁,以及附加到外部状态管理器和脱离外部状态管理器,增强我们响应需求变化的能力。当然这也需要外部状态管理器自己来扩展。大多数云基础设施提供商已经认识到这一必要性,并提供了这类服务的健康菜单。

移动应用和客户端多样性

2014年1月,美国移动设备占互联网使用量的55%。专门针对桌面用户而开发的应用程序的时代已经过去。不过,我们必须假设用户装在口袋里到处散步的是超级计算机。这对我们的应用架构有很大的影响,因为指数级用户可以随时随地与我们的系统进行交互。

以查看银行账户余额为例。这项任务过去是通过拨打银行的呼叫中心,前往ATM,或者在银行的一个分支机构的向柜员请求完成的。这些客户互动模式在任何时间内,都会对银行为底层软件系统提出新需求产生极大的限制。

迁移到网上银行导致访问量的上升,但并没有从根本上改变交互模式。您仍然必须在计算机终端上与系统进行交互,这仍然显著限制了需求。只有当我们都开始的时候,正如我的同事Andrew Clay Shafer经常说的那样,“我们口袋里正带着超级计算机到处游走”,我们开始对这些系统造成痛苦。 现在,成千上万的客户可以随时随地与银行系统进行互动。 一位银行行政人员表示,在发薪日,客户会每隔几分钟检查一次余额。 遗留的银行系统架构根本无法满足这种需求,而云原生的应用程序体系结构却可以。

移动平台的巨大差异也对应用架构提出了要求。客户随时都可能与多个不同供应商生产的设备,运行多个不同的操作系统平台,运行多个版本的相同操作平台以及不同类别的设备(例如手机与平板电脑)进行交互。 这不仅对移动应用程序开发人员,还对后端服务的开发人员造成了各种限制。

移动应用程序通常必须与多个传统系统以及云原生应用程序架构中的多个微服务进行交互。这些服务无法设计成支持客户使用的各种各样移动平台的独特需求。强迫这些这些不同的服务,为移动开发人员上带来了负担,增加了应用访问延迟和网络访问频率,导致应用响应慢、耗电量高,最终导致用户删除您的应用程序。云原生应用程序架构还通过诸如API网关之类的设计模式来支持移动优先开发的概念,API网关将服务聚合负担转移回服务器端。

云原生架构定义

现在我们将探索云原生应用架构的几个主要特征,和这些特征是如何解决我们前面提到的使用云原生应用架构的动机。

12因素应用

12因素应用是一系列云原生应用架构的模式集合,最初由Heroku提出。这些模式可以用来说明什么样的应用才是云原生应用。它们关注速度、安全、通过声明式配置扩展、可横向扩展的无状态/无共享进程以及部署环境的整体松耦合。如Cloud Foundry、Heroku和Amazon ElasticBeanstalk都对部署12因素应用进行了专门的优化。

在12因素的背景下,应用(或者叫app)指的是独立可部署单元。组织中经常吧一些列互相协作的可部署单元称作一个应用。

12因素应用遵循以下模式:

代码库

每个可部署app在版本控制系统中都有一个独立的代码库,可以在不同的环境中部署多个实例。

依赖

App应该使用适当的工具(如Maven、Bundler、NPM)来对依赖进行显式的声明,而不该在部署环境中隐式的实现依赖。

配置

配置或其他随发布环境(如部署、staging、生产)而变更的部分应当作为操作系统级的环境变量注入。

后端服务

后端服务,例如数据库、消息代理应视为附加资源,并在所有环境中同等看待。

编译、发布、运行

构建一个可部署的app组件并将它与配置绑定,根据这个组件/配置的组合来启动一个或者多个进程,这两个阶段是严格分离的。

进程

该app执行一个或者多个无状态进程(例如master/work),它们之间不需要共享任何东西。任何需要的状态都置于后端服务(例如cache、对象存储等)。

端口绑定

该应用程序是独立的,并通过端口绑定(包括HTTP)导出任何/所有服务。

并发

并发通常通过水平扩展应用程序进程来实现(尽管如果需要的话进程也可以通过内部管理的线程多路复用来实现)。

可任意处置性

通过快速迅速启动和优雅的终止进程,可以最大程度上的实现鲁棒性。这些方面允许快速弹性缩放、部署更改和从崩溃中恢复。

开发/生产平等

通过保持开发、staging和生产环境尽可能的相同来实现持续交付和部署。

日志

不管理日志文件,将日志视为事件流,允许执行环境通过集中式服务收集、聚合、索引和分析事件。

管理进程

行政或管理类任务(如数据库迁移),应该在与app长期运行的相同的环境中一次性完成。

这些特性很适合快速部署应用程序,因为它们不需要对将要部署的环境做任何假定。对环境假设能够允许底层云平台使用简单而一致的机制,轻松实现自动化,快速配置新环境,并部署应用。以这种方式,十二因素应用模式能够帮我们优化应用的部署速度。

这些特性也很好地适用于突发需求,或者低成本地“丢弃”应用程序。应用程序环境本身是100%一次性的,因为任何应用程序状态,无论是内存还是持久性,都被提取到后端服务。这允许应用程序以易于自动化的非常简单和弹性的方式进行伸缩。在大多数情况下,底层平台只需将现有环境复制到所需的数目并启动进程。缩容是通过暂停正在运行的进程和删除环境来完成,无需设法地实现备份或以其他方式保存这些环境的状态。就这样,12因素应用模式帮助我们实现规模优化。

最后,应用程序的可处理性使得底层平台能够非常快速地从故障事件中恢复。

此外,将日志作为事件流处理能够极大程度上的增强应用程序运行时底层行为的可见性。

强制环境之间的等同、配置机制的一致性和后端服务管理使云平台能够为应用程序运行时架构的各个方面提供丰富的可见性。以这种方式,十二因素应用模式能够优化安全性。

微服务

微服务将单体业务系统分解为多个“仅做好一件事”的可独立部署的服务。这件事通常代表某项业务能力,或者最小可提供业务价值的“原子“服务单元。

微服务架构通过以下几种方式为速度、安全、可扩展性赋能:

  • 当我们将业务领域分解为可独立部署的有限能力的环境的同时,也将相关的变更周期解耦。只要变更限于单一有限的环境,并且服务继续履行其现有合约,那么这些更改可以独立于与其他业务来进行和部署。结果是实现了更频繁和快速的部署,从而实现了持续的价值流动。
  • 通过扩展部署组织本身可以加快部署。由于沟通和协调的开销,添加更多的人,往往会使软件构建变得更加苦难。 弗雷德·布鲁克斯(Fred Brooks,人月神话作者)很多年前就教导我们,在软件项目的晚期增加更多的人力将会时软件项目更加延期。 然而,我们可以通过在有限的环境中构建更多的沙箱,而不是将所有的开发者都放在同一个沙箱中。
  • 由于学习业务领域和现有代码的认知负担减少,并建立了与较小团队的关系,因此我们添加到每个沙箱的新开发人员可以更快速地提高并变得更高效。
  • 可以加快采用新技术的步伐。大型单体应用程序架构通常与对技术堆栈的长期保证有关。这些保证的存在是为了减轻采用新技术的风险。技术采用错误在单体架构中的代价更为昂贵,因为这些错误可能会影响整个企业架构。如果我们可以在单个整体的范围内采用新技术,将隔离并最大限度地降低风险,就像隔离和最小运行时故障的风险一样。
  • 微服务提供独立、高效的服务扩展。单体架构也可以扩展,但要求我们扩展所有组件,而不仅仅是那些负载较重的组件。当且仅当相关联的负载需要它时,微服务才会被缩放。

自服务敏捷架构

使用云原生应用架构的团队通畅负责其应用的部署和持续运营。云原生应用的成功采纳者已经为团队提供了自服务平台。

正如我们创建业务能力团队为每个有界的环境构建微服务一样,我们还创建了一个能力小组,负责提供一个部署和运行这些微服务的平台。

这些平台中最大好处是为消费者提供主要的抽象层。通过基础架构即服务(IAAS),我们要求API创建虚拟服务器实例、网络和存储,然后应用各种形式的配置管理和自动化,以使我们的应用程序和支持服务能够运行。现在这种允许我们自定义应用和支持服务的平台正在不断涌现。

应用程序代码简单地以预构建的工件(可能是作为持续交付管道的一部分生成的)或Git远程的原始源代码的形式“推送”。 然后,平台构建应用程序工件,构建应用程序环境,部署应用程序,并启动必要的进程。 团队不必考虑他们的代码在哪里运行或如何到达那里,这些对用户都是透明得,因为平台会关注这些。

这样的模型同样适合于后端服务。需要数据库? 消息队列或邮件服务器? 只需要求平台来配合您的需求。平台现在支持各种SQL/NoSQL数据存储、消息队列、搜索引擎、缓存和其他重要的后端服务。这些服务实例然后可以“绑定”到您的应用程序,必要的凭据会自动注入到应用程序的环境中以供其使用。从而消除了大量凌乱而易出错的定制自动化。

这些平台还经常提供广泛的额外操作能力:

  • 应用程序实例的自动化和按需扩展
  • 应用健康管理
  • 请求到或跨应用程序实例间的动态路由和负载均衡
  • 日志和指标的聚合

这种工具的组合确保了能力团队能够根据敏捷原则开发和运行服务,从而实现速度,安全性和规模化。

基于API的协作

在云原生应用程序架构中,服务之间的唯一互动模式是通过已发布和版本化的API。这些API通常是具有JSON序列化的HTTP REST风格,但也可以是其他协议和序列化格式。

只要有需要,在不会破坏任何现有的API协议的前提下,团队就可以部署新的功能,而不需要与其他团队进行同步。 自助服务基础设施平台的主要交互模式也是通过API,就像其他业务服务一样。供给、缩放和维护应用程序基础设施的方式不是通过提交票据,而是将这些请求提交给提供该服务的API。

通过消费者驱动的协议,可以在服务间交互的双方验证协议的合规性。服务消费者不能访问其依赖关系的私有实现细节,或者直接访问其依赖关系的数据存储。实际上,只允许有一个服务能够直接访问任何数据存储。这种强制解耦直接支持云原生的速度目标。

抗脆弱性

Nassim Taleb在他的Antifragile(Random House)一书中介绍了抗脆弱性的概念。如果脆弱性是受到压力源的弱化或破坏的质量系统,那么与之相反呢?许多人会以稳健性或弹性作出回应——在遭受压力时不会被破坏或变弱。然而,Taleb引入了与脆弱性相反的抗脆弱性概念,或者在受到压力源时变得更强的质量系统。什么系统会这样工作?联想下人体免疫系统,当接触病原体时,其免疫力变强,隔离时较弱。我们可以像这样建立架构吗?云原生架构的采用者们已经设法构建它们了。Netflix Simian Army项目就是个例子,其中着名的子模块“混沌猴”,它将随机故障注入到生产组件中,目的是识别和消除架构中的缺陷。通过明确地寻求应用程序架构中的弱点,注入故障并强制进行修复,架构自然会随着时间的推移而更大程度地收敛。

本章小结

本章中,我们讨论了希望通过软件赋予我们业务的能力并迁移到云原生应用架构的动机:

速度

比我们的竞争对手更快速得创新、试验并传递价值。

安全

在保持稳定性、可用性和持久性的同时,具有快速行动的能力。

扩展

根据需求变化弹性扩展。

移动性

客户可以随时随地通过任何设备无缝的跟我们交互。

我们还研究了云原生应用架构的独特特征,以及如何赋予我们这些能力:

12因素应用程序

一套优化应用程序设计速度,安全性和规模的模式。

微服务

一种架构模式,可帮助我们将部署单位与业务能力保持一致,使每个业务能够独立和自主地移动,这样一来也更快更安全。

自服务敏捷基础设施

云平台使开发团队能够在应用程序和服务抽象层面上运行,提供基础架构级速度,安全性和扩展性。

基于API的协作

将服务间交互定义为可自动验证协议的架构模式,通过简化的集成工作实现速度和安全性。

抗脆弱性

随着速度和规模扩大,系统的压力随之增加,系统的响应能力和安全性也随之提高。

在下一章中,我们将探讨大多数企业为采用云原生应用程序架构而需要做出哪些改变。