云原生应用程序的15个要点
阅读笔记,原文链接
One Codebase, One Application
云原生应用程序必须始终由在版本控制系统中跟踪的单个代码库组成。代码库是共享公共根的源代码存储库或一组存储库。
应用程序的单个代码库用于生成任何数量的不可变发行版1,这些发行版旨在用于不同的环境。遵循这一特定纪律,团队必须分析其应用程序的接缝,并潜在地确定应拆分为微服务的整体。2如果您有多个代码库,则您有一个需要分解的系统,而不是单个应用程序。
当一个代码库用于生成多个应用程序时,可以打破此规则。例如,单个代码库在单个包装器模块中具有多个启动脚本甚至多个执行点。
单个代码库中的多个应用程序通常表明多个团队正在维护一个代码库,这可能由于多种原因而变得难看。
换句话说,一个代码库,一个应用程序并不意味着不允许您在多个应用程序之间共享代码。它只是意味着共享代码是另一个代码库。
这也不意味着所有共享代码都必须是微服务。相反,您应该评估共享代码是否应被视为单独发布的产品。
API First
假设您已经完全接受了本书中讨论的所有其他因素。您正在构建本机云应用程序,将代码签入到存储库后,将自动运行测试,并且可以在几分钟之内在实验室环境中运行候选发布版本。
现在,您组织中的另一个团队开始构建与您的代码进行交互的服务。然后,另一个团队看到了,他们加入了团队并带来了他们的服务。很快,您将有多个团队共同构建具有水平依赖项的服务,这些服务均位于不同的发布节奏上。
如果没有纪律约束会发生集成失败的噩梦。为避免这些集成失败,并正式将您的API识别为开发过程的一流工件,API首先使团队能够与彼此的公共合同进行合作,而不会干扰内部开发过程。
“ *移动优先”*的概念越来越受关注。它指的是从项目一开始就所做的所有事情都围绕着这样的想法,即所构建的是移动设备要消费的产品。同样,API首先意味着您要构建的是供客户端应用程序和服务使用的API。
通过首先设计您的API,您可以很轻松地与您的利益相关者(您的内部团队,客户或组织中可能要使用您的API的其他团队)进行讨论,直到您将自己编码成无法返回的地步。然后,通过这种协作,您可以构建用户案例,模拟API并生成可用于进一步社交化所构建服务的意图和功能的文档。
所有这些都可以完成,以审查(和测试!)您的方向和计划,而无需在支持给定API的管道上投入过多的资金。
此模式是合同优先开发模式的扩展,在此模式中,开发人员专注于首先构建其应用程序的边缘或接缝。通过CI服务器对集成点进行持续测试,两个团队可以使用自己的服务,并且仍保持合理的保证,即所有组件都可以正常工作。
API首先将组织从瀑布,精心设计的系统中解放出来,该系统遵循预先计划的编排模式,并允许产品演化为有机的,自组织的生态系统,可以增长以应对新的和不可预见的需求。
Dependency Management
云是经典企业模型的成熟,因此,我们的应用程序需要成长才能利用云。应用程序不能假定服务器或应用程序容器将拥有所需的一切。相反,应用程序需要随身携带依赖项。
大多数当代编程语言都有一些用于管理应用程序依赖项的工具。Maven
和Gradle
是两个在Java世界上最流行的工具。无论使用哪种工具,这些实用程序都提供一组通用功能:它们允许开发人员声明依赖关系,并让该工具负责确保满足这些依赖关系。
这些工具中的许多工具还具有隔离依赖项的能力。这是通过分析已声明的依赖项并将这些依赖项捆绑(也称为vendoring)到应用程序构件本身下方或内部的某个子结构中来完成的。
不能正确隔离依赖项会导致无法解决的问题。在一些最常见的依赖关系有关的问题,你可以有一个开发者版本X上工作的的工作站上一些依赖库,但版本X + 1该库已安装在生产的中心位置。这可能导致从运行时故障一直到阴险且难以诊断的细微故障的所有原因。如果不加以处理,这些类型的故障可能会导致整个服务器瘫痪,或者由于无法诊断的数据损坏而使公司损失数百万美元。
正确地管理应用程序的依赖关系是关于可重复部署的概念。不应认为部署应用程序的运行时不是自动化的。在理想的情况下,应用程序的容器被捆绑(或被引导,如某些框架所称)在应用程序的发布构件中,或者更好的是,应用程序根本没有容器。
Design, Build, Release, Run
构建,发布,运行要求严格区分开发的构建和运行阶段。这是极好的建议,如果不遵守该准则,可能会给您带来将来的困难。除了三要素的构建,发布,运行三重奏外,离散的设计步骤也至关重要。
从设计到代码再到运行的过程是一个反复的过程,可以在您的团队可以处理的很小或更长的时间内发生。如果团队拥有成熟的CI / CD流程,则从设计到投入生产可能需要几分钟的时间。
在构建过程中将使用单个代码库来生成已编译的工件。然后,该工件与应用程序外部的配置信息合并,以生成不可变的发行版。然后将不可变版本发布到云环境(开发,QA,生产等)并运行。本章的重点是,以下每个部署阶段都是隔离的,并且分别发生。
设计
在瀑布式应用程序开发的世界中,在编写一行代码之前,我们花费大量的时间来设计应用程序。这种类型的软件开发生命周期不能很好地适应需要经常发布的现代应用程序的需求。
但是,这并不意味着我们根本不设计。取而代之的是,这意味着我们设计了要发布的小功能,并且我们有一个高级设计用于通知我们所做的每件事。但是我们也知道设计会发生变化,少量的设计是每个迭代的一部分,而不是完全预先完成。
应用程序开发人员最能理解应用程序的依赖关系,并且在设计阶段就进行了声明,以声明依赖关系以及将这些依赖关系出售或捆绑到应用程序的方式。换句话说,开发人员决定应用程序将使用哪些库,以及最终如何将这些库捆绑成一个不可变的发行版。
建立
在构建阶段,将代码存储库转换为版本化的二进制工件。在此阶段,将在设计阶段声明的依赖项提取并捆绑到构建工件中(通常简称为“构建”)。在Java世界中,构建可能是WAR 1或JAR文件,或者可能是ZIP文件或其他语言和框架的二进制可执行文件。
理想情况下,构建是由Continuous Integration服务器创建的,并且构建和部署之间存在1:许多关系。一个单一的构建应该能够发布或部署到任意数量的环境中,并且每个未修改的构建都应该能够按预期工作。该工件的不变性以及对其他因素的遵守(尤其是环境平价)使您有信心,如果您的应用程序可以在质量检查中运行,那么它将在生产环境中运行。
如果您发现自己对“在我的机器上工作”的问题进行故障排除,则很明显地表明,此过程的四个阶段可能没有应有的分开。
发布
在云原生世界中,发布通常是通过推送到您的云环境来完成的。构建阶段的输出与特定于环境和特定于应用程序的配置信息结合在一起,以产生另一个不变的工件,即发行版。
版本必须是唯一的,并且理想情况下,每个版本都应使用某种唯一的ID(例如时间戳或自动递增编号)进行标记。
假设您的CI系统刚刚构建了您的应用程序并标记了该工件build-1234
。然后,CI系统可以将该应用程序发布到开发,登台和生产环境中。该方案取决于您,但是每个发行版都应该是唯一的,因为每个发行版都将原始版本与特定于环境的配置设置结合在一起。
如果出现问题,您希望能够审核已发布到给定环境的内容,并在必要时回滚到先前的版本。这是使发布保持不变和唯一标识的另一个关键原因。
运行
运行阶段通常也由云提供商完成(尽管开发人员需要能够在本地运行应用程序)。提供商之间的详细信息有所不同,但是通常的模式是将您的应用程序放置在某种容器(Docker,Garden,Warden等)中,然后启动一个过程来启动您的应用程序。
值得注意的是,要确保开发人员可以在自己的工作站上本地运行应用程序,同时仍然允许其通过CD管道将其部署到多个云中,通常是很难解决的问题。但是,这值得解决,因为开发人员在处理原生云应用程序时需要不受阻碍。
当应用程序运行时,云运行时将负责保持其运行状态,监视其运行状况并聚合其日志,以及大量其他管理任务,例如动态扩展和容错。
Configuration, Credentials, and Code
构型化学
将配置,凭证和代码视为易挥发的物质,这些物质在结合时会爆炸。
这听起来可能有点苛刻,但是如果不遵循此规则,可能会导致您无比沮丧,这只会使您的应用程序更接近生产环境。
为了使配置与代码和凭据分开,我们需要对配置进行非常清晰的定义。配置是指可以随部署而变化的任何值(例如,开发人员工作站,QA和生产)。这可能包括:
- URL和其他有关后备服务的信息,例如Web服务和SMTP服务器
- 查找和连接数据库所需的信息
- 第三方服务(例如Amazon AWS)或API(例如Google Maps,Twitter和Facebook)的凭据
- 通常可能捆绑在属性文件或配置XML或YML中的信息
配置并没有包括它是应用程序本身的一部分的内部信息。同样,如果该值在所有部署中都保持不变(这是您不可变的构建构件的一部分),则它不是配置。
凭证是极其敏感的信息,在代码库中绝对没有事务。通常,开发人员会从已编译的源代码中提取凭证,并将其放入属性文件或XML配置中,但这实际上并没有解决问题。包括XML和属性文件在内的捆绑资源仍然是代码库的一部分。这意味着捆绑在您的应用程序附带的资源文件中的凭据仍然违反此规则。
像开源一样对待您的应用
查看您是否已适当地外部化了凭据和配置,以想象将应用程序源代码推送到GitHub的后果。
如果公众可以访问您的代码,您是否公开了有关应用程序所依赖的资源或服务的敏感信息?人们是否可以看到内部URL,支持服务的凭证或其他与不在目标环境中工作的人敏感或无关的信息?
如果您可以在不暴露敏感信息或特定于环境的信息的情况下开源代码库,那么您可能已经很好地隔离了代码,配置和凭据。
显而易见,我们不想公开凭据,但是对外部配置的需求通常并不那么明显。外部配置支持我们通过CD管道将不可变版本自动部署到多个环境的能力,并有助于我们保持开发/生产环境的均等性。
外化配置
说您的应用程序的配置应该外部化是一回事,但是实际要做的却是另一回事。如果使用的是Java应用程序,则可能会将发布工件与属性文件捆绑在一起。其他类型的应用程序和语言倾向于使用YAML文件,而.NET应用程序传统上是从基于XML的web.config和machine.config文件中获取配置的。
您应该将所有这些都视为云的反模式。所有这些情况都使您无法在环境之间更改配置,同时仍保持不变的发行工件。
外部化配置的暴力方法是摆脱所有配置文件,然后遍历代码库并对其进行修改,以期望所有这些值都由环境变量提供。环境变量被认为是外部化配置的最佳实践,尤其是在Cloud Foundry或Heroku等云平台上。
根据您的云提供商,您可能可以使用其工具来管理后备服务或绑定服务,以安全的方式向应用程序公开包含服务凭证和URL的结构化环境变量。
强烈建议您将配置外部化的另一个方法是实际使用旨在公开配置的服务器产品。这样的开源服务器之一就是Spring Cloud Configuration Server,但是有无数其他可用的产品。购买配置服务器产品时应注意的一件事是支持版本控制。如果要对配置进行外部化,则应该能够保护数据更改并获得由谁进行更改以及何时进行更改的历史记录。正是这一要求使得位于版本控制存储库(如*git)*顶部的配置服务器具有吸引力。
Logs
日志应视为事件流,也就是说,日志是按时间顺序从应用程序发出的事件序列。以云原生方式处理日志的关键在于,真正的云原生应用程序永远不会将自己的输出流路由或存储。
云应用程序不能对其运行所在的文件系统做出任何假设,除非它是短暂的。原生云应用程序将其所有日志条目写入stdout
和stderr
。这可能会吓到很多人,担心这意味着失去控制。
您应该将日志的聚合,处理和存储视为一项非功能性要求,该要求不是由您的应用程序满足,而是由您的云提供商或与平台合作运行的其他工具套件满足。
当您的应用程序与日志存储,处理和分析的知识脱钩时,您的代码将变得更加简单,并且您可以依靠行业标准的工具和堆栈来处理日志。此外,如果您需要更改存储和处理日志的方式,则无需修改应用程序即可*。*
您的应用程序不应控制其日志的最终命运的众多原因之一是由于可伸缩性。当您在固定数量的服务器上具有固定数量的实例时,将日志存储在磁盘上似乎很有意义。但是,当您的应用程序可以从1个正在运行的实例动态变为100个,并且您不知道这些实例在哪里运行时,您需要您的云提供商来代表您汇总这些日志。
简化应用程序的日志发出过程可以使您减少代码库,并更加关注应用程序的核心业务价值。
Disposability
在云实例上,应用程序的生命与支持它的基础架构一样短暂。云原生应用程序的流程是一次性的,这意味着它们可以快速启动或停止。如果应用程序无法快速启动和正常关闭,则无法快速扩展,部署,释放或恢复。我们需要构建不仅意识到这一点的应用程序,而且还必须拥抱它以充分利用该平台。
如果您正在启动一个应用程序,并且要花几分钟才能进入稳定状态,那么在当今的高流量世界中,这可能意味着在启动应用程序时拒绝了成百上千个请求。更重要的是,视应用程序部署所在的平台而定,如此缓慢的启动时间实际上可能会触发警报或警告,因为应用程序无法通过其运行状况检查。极慢的启动时间甚至可能阻止您的应用完全在云中启动。
如果您的应用程序正在承受越来越大的负载,并且您需要快速启动更多实例来处理该负载,则启动过程中的任何延迟都可能会阻碍其处理该负载的能力。如果该应用程序无法快速正常关闭,也可能会阻止失败后再次将其重新启动的功能。无法足够快地关闭系统还可能带来无法处理资源的风险,这可能会破坏数据。
编写许多应用程序时,它们会在启动过程中执行许多长时间运行的活动,例如获取数据以填充缓存或准备其他运行时依赖项。为了真正地接受云原生架构,需要单独处理这种活动。例如,*您可以将缓存外部化为*支持服务,以便您的应用程序可以快速执行上下操作,而无需执行前载操作。
Backing Services(支持服务)
一个支撑服务是您的应用程序依赖于它的功能性的任何服务。这是一个相当广泛的定义,其广泛的范围是有意的。一些最常见的支持服务类型包括数据存储,消息传递系统,缓存系统以及许多其他类型的服务,包括执行业务功能或安全性的服务。
在构建旨在在必须将文件系统视为短暂的云环境中运行的应用程序时,您还需要将文件存储或磁盘视为后备服务。您不应该像使用常规企业应用程序那样读取或写入磁盘上的文件。相反,文件存储应该是作为资源绑定到您的应用程序的支持服务。
一个应用程序,一组支持服务以及这些服务的资源绑定(连接线)。绑定资源实际上只是将您的应用程序连接到支持服务的一种方式。数据库的资源绑定可能包括用户名,密码和允许您的应用程序使用该资源的URL。
我们应该具有外部化的配置(与凭据和代码分开),并且我们的发行产品必须是不可变的。将这些其他规则应用于应用程序使用后台服务的方式,我们最终得到一些用于资源绑定的规则:
- 应用程序应声明其对给定支持服务的需求,但应允许云环境执行实际的资源绑定。
- 应用程序与其支持服务的绑定应通过外部配置完成。
- 应该可以随意从应用程序附加和分离支持服务,而无需重新部署应用程序。
例如,假设您有一个需要与Oracle数据库进行通信的应用程序。你编写你的应用程序,使得其特定的Oracle数据库的依赖声明(这对声明的方式通常是针对某一种语言或工具集)*。*应用程序的源代码假定资源绑定的配置发生在应用程序外部。
这意味着您的应用程序中绝不会存在将应用程序紧密耦合到特定支持服务的代码行。同样,您可能还具有用于发送电子邮件的支持服务,因此您知道将通过SMTP与之通信。但是,邮件服务器的确切实现对您的应用程序没有影响,您的应用程序也不应依赖于存在于特定位置或具有特定凭据的SMTP服务器。
Environment Parity
尽管一些组织已经做出了更大的发展,但我们中的许多人可能都在这样的环境中工作:共享开发环境与QA相比具有不同的伸缩性和可靠性配置文件,而QA与生产环境也有所不同。dev和QA中使用的数据库驱动程序与生产版本不同。安全规则,防火墙和其他环境配置设置也有所不同。有些人能够部署到某些环境,而其他人则没有。最后,最糟糕的是,人们害怕部署,他们几乎没有信心,如果该产品在一种环境中工作,它将在另一种环境中工作。
在讨论设计,构建,发布,运行周期时,我提出了“在我的机器上运行”方案是云原生反模式的概念。对于我们在损失数小时或数天的消防和故障排除之前就已经听到的其他短语,也是如此:“它在质量保证中起作用”和“在产品中起作用”。
对环境均等性应用严格和纪律的目的是使您的团队和整个组织有信心该应用程序可以在任何地方使用。1个
虽然在环境之间造成差距的机会几乎是无限的,但最常见的罪魁祸首通常是:
- 时间
- 人
- 资源
时间
在许多组织中,从开发人员检入代码到生产完成为止,可能要花费数周或数月的时间。在这样的组织中,您经常会听到诸如“第三季度版本”或“ 20xx年12月版本”之类的短语。这样的短语对于任何关注的人都是一个警告信号。
当出现这样的时间间隔时,人们通常会忘记发布中进行了哪些更改(即使有足够的发布说明),更重要的是,开发人员已经忘记了代码的外观。
采用现代方法,组织应努力减少从签入到生产的时间间隔,从数周或数月缩短到数分钟或数小时。正确的CD流水线的结尾应该是在不同环境中执行自动测试,直到将更改自动推向生产环境为止。借助支持零停机时间部署的云,这种模式可以成为常态。
人
人类绝对不应该部署应用程序,至少不应该将其部署到除自己的工作站或实验室以外的任何环境中。如果存在正确的构建管道,则将根据CI工具和目标云实例内的安全限制,将应用程序自动部署到所有适用的环境,并可以将其手动部署到其他环境。
实际上,即使您的目标是公共云提供商,也仍然可以使用CloudBees或Wercker等云托管CD工具来自动化您的测试和部署。
尽管总是有例外,但我认为,如果您无法通过按一下按钮或自动响应某些事件来进行部署,那么您做错了。
资源
我们使用和提供支持服务的方式通常是一种这样的折衷方案。我们的应用程序可能需要一个数据库,并且我们知道在生产中我们会将其连接到Oracle或Postgres服务器,但是将其设置为可在本地用于开发非常麻烦,因此我们将妥协和使用内存数据库是的那种像目标数据库。
每次我们做出这些折衷之一时,我们就会扩大开发和生产环境之间的差距。差距越大,我们对应用程序工作方式的可预测性就越差。随着可预测性的下降,可靠性也会下降。如果可靠性下降,我们将失去从代码检入到生产部署的连续流程。它使我们所做的一切都变得脆弱。最糟糕的是,我们通常不知道增加dev / prod差距的后果,直到为时已晚。
在构建本地云应用程序时评估开发生命周期中的每个步骤时,都需要标记和质疑增加部署环境之间功能差距的每项决定,并且您需要抵制通过允许您的环境来减轻此问题的冲动即使当时差异似乎微不足道,也可以保持差异。
Administrative Processes
在某些情况下,使用管理流程实际上不是一个好主意,您应该始终在问自己:管理流程是否是您想要的,或者不同的设计或体系结构是否更适合您的需求。可能应重构为其他内容的管理过程的示例包括:
- 数据库迁移
- 交互式编程控制台(REPL)
- 运行定时脚本,例如每晚批处理作业或每小时导入
- 运行一次仅执行一次自定义代码的一次性工作
首先,让我们看一下计时器的问题(通常由Autosys或Cron等应用程序管理)。一种想法可能是只内部化计时器,让您的应用程序每n小时唤醒一次以执行其批处理操作。从表面上看,这似乎是一个很好的解决方案,但是当一个可用性区域中运行有20个应用程序实例,而另一区域中运行了另外15个实例时,会发生什么呢?如果他们都在计时器上执行相同的批处理操作,那么此时您基本上是在引起混乱,并且损坏或重复的数据将只是此模式引起的许多可怕事件之一。
交互式外壳由于多种原因也存在问题,但是最大的原因是,即使有可能到达该外壳,您也只能与单个实例的临时内存进行交互。如果应用程序是作为无状态进程正确构建的,那么我认为对于进程内省公开REPL几乎没有任何价值。2
接下来,让我们看一下触发定时或批处理管理过程的机制。这通常是由于某些外部计时器刺激(例如cron
或)执行shell脚本而发生的Autosys
。在云中,您不能指望能够调用这些命令,因此您需要找到其他方法来触发应用程序中的临时活动。
有多种解决方案,但是我发现最吸引人的一种解决方案是,公开一个RESTful终结点,可用于调用即席功能,特别是在将应用程序的其余部分迁移为云原生时,这一点尤其明显。
这仍然允许随意调用定时功能,但是将此操作的刺激因素移到了应用程序之外。此外,此方法还解决了动态缩放实例上内部计时器最多只能执行一次的问题。批处理操作由一个应用程序实例处理一次,然后可以与其他支持服务进行交互以完成任务。保护批处理端点也应该相当简单,以便只能由授权人员操作。更为有用的是,您的批处理操作现在可以灵活地扩展并利用所有其他云优势。
如果仍然觉得需要利用管理流程,则应确保以与云提供商所提供的功能一致的方式使用管理流程。换句话说,不要使用您喜欢的编程语言来产生新的流程来运行您的工作;使用旨在以云原生方式运行一次性任务的工具。
Port Binding
避开容器确定的端口
Web应用程序(尤其是已经在企业内部运行的Web应用程序)通常在某种服务器容器中执行。Java世界充满了Tomcat,JBoss,Liberty和WebSphere等容器。其他Web应用程序可能在其他容器中运行,例如Microsoft Internet信息服务器(IIS)。
在非云环境中,Web应用程序已部署到这些容器中,然后容器负责在应用程序启动时为其分配端口。
在管理自己的Web服务器的企业中,一种极为常见的模式是将多个应用程序托管在同一容器中,通过端口号(或URL层次结构)分隔应用程序,然后使用DNS在该服务器周围提供用户友好的外观。例如,你可能有一个叫(虚拟或物理)主机appserver
,以及已分配的端口8080通过8090,而不是让用户记住端口号,使用DNS主机名关联像一些应用程序的app1
使用appserver:8080
,app2
用appserver:8081
,等等。
避免微管理端口分配
这里采用平台即服务,使开发人员和开发人员都不必再执行这种微管理。您的云提供商应该为您管理端口分配,因为它还可能管理路由,扩展,高可用性和容错能力,所有这些都需要云提供商管理网络的某些方面,包括将主机名路由到端口和将外部端口号映射到容器内部端口。
最初的12个用于端口绑定的因素之所以使用“ 导出 ”一词,是因为假定云本机应用程序是独立的,并且从未注入到任何类型的外部应用程序服务器或容器中。
实用性和现有企业应用程序的性质可能使以这种方式构建应用程序变得困难或不可能。结果,限制性的准则稍微少了一点,即应用程序和应用程序服务器之间必须始终保持1:1的关联。换句话说,您的云提供商可能支持Web应用程序容器,但极不可能支持在同一容器中托管多个应用程序,因为这几乎不可能实现持久性,可伸缩性和弹性。
对于现代应用程序,端口绑定对开发人员的影响非常简单:您的应用程序可以http://localhost:12001
在开发人员的工作站上运行,而在质量检查中,它可以运行在http://192.168.1.10:2000
,在生产环境中运行http://app.company.com
。考虑到导出端口绑定而开发的应用程序支持此特定于环境的端口绑定,而无需更改任何代码。
应用程序是支持服务
最后,为允许外部化的运行时端口绑定而开发的应用程序可以充当另一个应用程序的支持服务。这种灵活性以及在云上运行的所有其他好处非常强大。
无状态过程
无状态的实用定义
我经常提出的一个问题是由于对无状态概念的困惑。人们想知道如何建立一个无状态的流程。毕竟,每个应用程序都需要某种状态,对吗?即使是最简单的应用程序,也会留下一些数据浮动,那么您如何才能拥有一个真正的无状态进程?
无状态应用程序在处理请求之前不会对内存的内容做任何假设,在处理该请求之后也不会对内存的内容做任何假设。在处理请求或处理事务的过程中,应用程序可以创建和使用瞬态,但是到客户端收到响应时,数据应该全部消失。
简单地说,所有持久状态必须在应用程序的外部,由后备服务提供。
例如,公开用于用户管理的功能的微服务必须是无状态的,因此所有用户的列表都在支持服务(例如Oracle或MongoDB数据库)中维护。由于明显的原因,数据库无状态是没有意义的。
无共享模式
进程通常通过共享公共资源相互通信。即使不考虑迁移到云计算,采用无共享模式也会有很多好处。
首先,过程之间共享的任何东西都是使所有这些过程更加脆弱的责任。在许多高可用性模式中,流程将通过多种技术共享数据,以选择集群领导者,确定流程是主要流程还是备份流程,等等。
在云中运行时,需要避免所有这些选项。您的流程可能会在没有任何警告的情况下立即消失,这是一件好事。过程来来去去,在水平和垂直方向上缩放,并且高度一次性。这意味着进程之间共享的任何内容也可能消失,从而可能导致级联故障。
不用说,但是文件系统不是后备服务。这意味着您不能将文件视为应用程序共享数据的一种方式。云中的磁盘是临时磁盘,在某些情况下甚至是只读磁盘。
如果进程需要共享数据,例如形成Web场的一组进程的会话状态,则应将该会话状态外部化,并通过真正的支持服务使其可用。
资料快取
特别是在基于容器的长期运行的Web应用程序中,一种常见的模式是在流程启动期间缓存常用数据。本书已经提到,进程需要快速启动和停止,而花很长时间填充内存中的高速缓存违反了这一原则。
更糟糕的是,存储您的应用程序认为始终可用的内存中缓存可能会使您的应用程序肿,从而使您的每个实例(应该可以弹性伸缩)占用的内存远远超过了所需的内存。
有数十种第三方缓存产品,包括Gemfire和Redis,它们都旨在充当应用程序的后备服务缓存。它们可用于会话状态,但也可用于缓存启动过程中可能需要的数据,并避免进程之间紧密耦合的数据共享。
并发
并发性,建议我们使用流程模型扩展本地云应用程序。有时,如果应用程序达到其容量极限,解决方案就是增加其大小。如果应用程序每分钟只能处理一定数量的请求,那么首选解决方案是简单地使应用程序更大。
在单个整体应用程序中添加CPU,RAM和其他资源(虚拟或物理)称为垂直扩展,这种类型的行为在当今的文明社会中通常不受欢迎。
一个更现代的方法,一个理想的那种弹性可扩展性的云支持,是扩大了,或者水平。您可以创建多个进程,而不是将一个大进程变得更大,然后在这些进程之间分配应用程序的负载。
大多数云提供商已经完善了此功能,甚至可以配置规则,这些规则将根据系统中可用的负载或其他运行时遥测来动态扩展应用程序实例的数量。
如果您要构建一次性的,无状态的,无共享的流程,那么您将可以充分利用水平扩展并运行应用程序的多个并发实例
遥测
在监视应用程序时,通常有几种不同类别的数据:
- 应用程序性能监控(APM)
- 特定领域遥测
- 运行状况和系统日志
第一个是APM,由一系列事件组成,云外部的工具可以使用这些事件来监视应用程序的运行状况。这是您要负责的事情,因为性能的定义和水印特定于您的应用程序和标准。用于提供APM仪表板的数据通常是相当通用的,并且可以来自跨多个业务线的多个应用程序。
第二,特定领域的遥测也由您决定。这是指对您的业务有意义的事件和数据流,可用于自己的分析和报告。这类事件流通常被馈送到“大数据”系统中,以进行仓储,分析和预测。
APM和特定领域遥测之间的区别可能不会立即显现。可以这样考虑:APM可以为您提供应用程序每秒处理的HTTP请求的平均数量,而特定领域的遥测可以告诉您最近20分钟内卖给iPad使用者的小部件数量。
最后,运行状况和系统日志应由您的云提供商提供。它们组成了一系列事件,例如应用程序启动,关闭,扩展,Web请求跟踪以及定期运行状况检查的结果。
云计算让很多简单的事情,但监测和遥测仍然是困难的,甚至可能更加困难比传统的企业应用程序的监控。当您盯着包含常规运行状况检查,请求审核,业务级别事件以及跟踪数据和性能指标的流中的流水线时,这是令人难以置信的数据量。
在计划监视策略时,您需要考虑要汇总的信息量,输入的速度以及要存储的信息量。如果您的应用程序从1个实例动态扩展到100个实例,这也可能导致日志流量增加一百倍。
审计和监视云应用程序通常被忽略,但可能是为生产部署进行计划和正确执行的一些最重要的事情。如果您不会盲目地将卫星发射到轨道上而无法对其进行监视,那么您就不应对云应用程序执行同样的操作。
身份验证和授权
安全性是任何应用程序和云环境的重要组成部分。安全绝不是事后的想法。
很多时候,我们非常关注于实现应用程序的功能需求,以至于忽略了交付任何应用程序的最重要方面之一,无论该应用程序是面向企业,移动设备还是面向应用程序。云。
云原生应用程序是安全的应用程序。您的代码(无论是编译的还是原始的)都跨多个数据中心传输,在多个容器中执行,并被无数的客户端(某些合法,最有害的客户端)访问。
即使在应用程序中实现安全性的唯一原因是,您可以对哪个用户进行了哪些数据更改进行审核跟踪,仅此一项就足以证明为保护应用程序端点安全所需的时间和精力相对较少。
在理想情况下,所有云原生应用程序都将使用RBAC(基于角色的访问控制)保护其所有端点。每个对应用程序资源的请求都应该知道谁在发出请求,以及该使用者所属的角色。这些角色指示主叫客户端是否具有足够的权限来允许应用程序满足请求。
借助OAuth2,OpenID Connect,各种SSO服务器和标准之类的工具,以及几乎无限提供的特定于语言的身份验证和授权库,从一开始就应将安全性纳入应用程序的开发中,而不应一并添加应用程序在生产中运行后的螺栓固定项目。
云原生
什么是云原生?
诸如“ SOA”,“云原生”和“微服务”之类的流行语和短语都开始出现,因为我们需要一种更快,更有效的方式来传达我们对某个主题的想法。这对于促进有关复杂主题的有意义的对话至关重要,我们最终建立了共享的上下文或通用的语言。
这些流行语的问题在于它们依赖多方之间的共同或共同理解。类似的经典游戏电话1上了空前的规模,这个所谓的共享迅速了解恶化到相互混淆。
我们通过SOA(面向服务的体系结构)看到了这一点,并通过云原生的概念再次看到了这一点。似乎每次共享此概念时,含义都会改变,直到我们对云原生的看法和IT专业人员一样多。
要了解“云原生”,我们必须首先了解“云”。许多人认为“云”是公开不受限制地公开访问互联网的代名词。尽管有一些这样的云产品,但还远远没有一个完整的定义。
在本书的上下文中,云指的是平台即服务。PaaS提供程序公开了一个平台,该平台向应用程序开发人员隐藏基础结构详细信息,该平台位于基础结构即服务(IaaS)之上。PaaS提供程序的示例包括Google App Engine,Redhat Open Shift,Pivotal Cloud Foundry,Heroku,AppHarbor和Amazon AWS。
关键要点是,云不一定是公共的同义词,企业正在自己的IaaS或第三方IaaS提供商(例如VMware或Citrix)的数据中心中建立自己的私有云。
对“ cloud native”一词中的“ native”一词表示怀疑。这造成了一种错误的印象,即只有在云内部原生开发的全新的绿色应用程序才可以被视为云原生。这是完全不正确的。
云原生应用程序是一种已设计和实现为在“平台即服务”安装上运行并包含水平弹性缩放的应用程序。
为什么要使用Cloud Native?
不久以前,将应用程序部署在物理服务器上就被认为是构建应用程序的规范—从空调房中的大型塔楼到实际数据中心中安装的超薄1U设备,一应俱全。
裸机部署充满了问题和风险:我们无法动态扩展应用程序,部署过程很困难,硬件的更改可能会导致应用程序故障,而硬件故障通常会导致大量数据丢失和大量停机。
这引发了虚拟化革命。每个人都同意不再使用裸机,因此管理程序诞生了。业界决定在硬件之上放置一个抽象层,以便我们可以简化部署,横向扩展应用程序,并希望避免大量的停机时间和对硬件故障的敏感性。
在当今始终连接在一起的智能设备甚至是更智能的软件世界中,您必须漫长而艰难地寻找一家没有某种软件开发流程作为其基石的公司。即使是传统的制造行业,即公司制造坚硬的物理产品,如果没有软件,制造也不会发生。没有软件,就无法组织人们高效,大规模地构建事物,没有软件,您当然无法参与全球市场。
无论您身处哪个行业,如果没有迅速交付不会失败的软件的能力,就无法在当今的市场中竞争。它需要能够动态扩展以处理以前闻所未闻的数据量。如果您无法处理大数据,那么您的竞争对手就会。如果您无法生产能够处理大量负载,保持响应能力并与市场一样快的变化的软件,那么您的竞争对手将找到一种方法来做到这一点。
这将我们带到了云原生的本质。过去,公司可以通过在DevOps任务上花费过多的时间和资源,在构建和维护脆弱的基础架构上,以及担心仅每个蓝月亮才发生一次的生产部署带来的后果而摆脱分散注意力的日子。
这是云计算的时代,我们需要以一种包含这种方式的方式来构建应用程序。我们需要构建应用程序,以便我们可以将大部分时间用于刺猬(一件大事)上,并让某人或其他人来照顾狐狸的许多小事情。超快速上市时间已不再是一个好时机;有必要避免被我们的竞争者甩在后面。我们希望能够将资源投入我们的业务领域,并让其他专家处理他们比我们做得更好的事情。
通过采用云原生架构,并假设一切都是服务,并且将它们部署在云环境中,就可以构建我们的应用程序,我们可以获得所有这些好处以及更多。问题不是为什么云原生?您必须问自己的问题是,为什么不拥抱云原生?