APICloud开发者进阶|云原生架构及设计原则

云原生(Cloud Native)的概念,由来自Pivotal的MattStine于2013年首次提出,被一直延续使用至今。这个概念是Matt Stine根据其多年的架构和咨询经验总结出来的一个思想集合,并获得了社区的不断完善,内容很是多,包括DevOps、持续交付(Continuous Delivery)、微服务(MicroServices)、敏捷基础设施(Agile Infrastructure)和12要素(TheTwelve-Factor App)等几大主题,不但包括根据业务能力对公司进行文化、组织架构的重组与建设,也包括方法论与原则,还有具体的操做工具。采用基于云原生的技术和管理方法,能够更好地把业务生于“云”或迁移到云平台,从而享受“云”的高效和持续的服务能力。docker

顾名思义,云原生是面向“云”而设计的应用,所以技术部分依赖于在传统云计算的3层概念(基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS)),例如,敏捷的不可变基础设施交付相似于IaaS,用来提供计算网络存储等基础资源,这些资源是可编程且不可变的,直接经过API能够对外提供服务;有些应用经过PaaS服务原本就能组合成不一样的业务能力,不必定须要从头开始建设;还有一些软件只须要“云”的资源就能直接运行起来为云用户提供服务,即SaaS能力,用户直接面对的就是原生的应用。数据库

应用基于云服务进行架构设计,对技术人员的要求更高,除了对业务场景的考虑外,对隔离故障、容错、自动恢复等非功能需求会考虑更多。借助云服务提供的能力也能实现更优雅的设计,好比弹性资源的需求、跨机房的高可用、11个9(99.999999999%)的数据可靠性等特性,基本是云计算服务自己就提供的能力,开发者直接选择对应的服务便可,通常不须要过多考虑自己机房的问题。若是架构设计自己又能支持多云的设计,可用性会进一步提升,好比Netflix能处理在AWS的某个机房没法正常工做的状况,还能为用户提供服务,这就是“云”带来的魔力,固然,云也会带来更多的隔离等问题。如图1-4所示,目前业界公认的云原生主要包括如下几个层面的内容。编程

图1-4 云原生的内容后端

--缓存

敏捷基础设施安全

正如经过业务代码可以实现产品需求、经过版本化的管理可以保证业务的快速变动,基于云计算的开发模式也要考虑如何保证基础资源的提供可以根据代码自动实现需求,并实现记录变动,保证环境的一致性。使用软件工程中的原则、实践和工具来提供基础资源的生命周期管理,这意味着工做人员能够更频繁地构建更强可控或更稳定的基础设施,开发人员能够随时拉取一套基础设施来服务于开发、测试、联调和灰度上线等需求。固然,同时要求业务开发具备较好的架构设计,不须要依赖本地数据进行持久化,全部的资源都是能够随时拉起,随时释放,同时以API的方式提供弹性、按需的计算、存储能力。服务器


技术人员部署服务器、管理服务器模板、更新服务器和定义基础设施的模式都是经过代码来完成的,而且是自动化的,不能经过手工安装或克隆的方式来管理服务器资源,运维人员和开发人员一块儿以资源配置的应用代码为中心,再也不是一台台机器。基础设施经过代码来进行更改、测试,在每次变动后执行测试的自动化流程中,确保能维护稳定的基础设施服务。网络

此外,基础设施的范围也会更加普遍,不只包括机器,还包括不一样的机柜或交换机、同城多机房、异地多机房等,这些内容也会在后续章节中逐一进行部分讨论。架构


持续交付并发

为了知足业务需求频繁变更,经过快速迭代,产品能作到随时都能发布的能力,是一系列的开发实践方法。它分为持续集成、持续部署、持续发布等阶段,用来确保从需求的提出到设计开发和测试,再到让代码快速、安全地部署到产品环境中。


持续集成是指每当开发人员提交了一次改动,就马上进行构建、自动化测试,确保业务应用和服务能符合预期,从而能够肯定新代码和原有代码可否正确地集成在一块儿。持续交付是软件发布的能力,在持续集成完成以后,可以提供到预发布之类系统上,达到生产环境的条件,持续部署是指使用彻底的自动化过程来把每一个变动自动提交到测试环境中,而后将应用安全地部署到产品环境中,打通开发、测试、生产的各个环节,自动持续、增量地交付产品,也是大量产品追求的最终目的,固然,在实际运行的过程当中,有些产品会增长灰度发布等环境。总之,它更可能是表明一种软件交付的能力,过程示例请参考图1-5。

图1-5  持续交付流程


DevOps

DevOps若是从字面上来理解只是Dev(开发人员)+Ops(运维人员),实际上,它是一组过程、方法与系统的统称,其概念从2009年首次提出发展到如今,内容也很是丰富,有理论也有实践,包括组织文化、自动化、精益、反馈和分享等不一样方面。


首先,组织架构、企业文化与理念等,须要自上而下设计,用于促进开发部门、运维部门和质量保障部门之间的沟通、协做与整合,简单而言组织形式相似于系统分层设计。其次,自动化是指全部的操做都不须要人工参与,所有依赖系统自动完成,好比上述的持续交付过程必须自动化才有可能完成快速迭代。再次,DevOps的出现是因为软件行业日益清晰地认识到,为了按时交付软件产品和服务,开发部门和运维部门必须紧密合做。总之,如图1-6所示,DevOps强调的是高效组织团队之间如何经过自动化的工具协做和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。

图1-6  DevOps强调组织的沟通与协做


微服务

随着企业的业务发展,传统业务架构面临着不少问题。


其一,单体架构在需求愈来愈多的时候没法知足其变动要求,开发人员对大量代码的变动会愈来愈困难,同时也没法很好地评估风险,因此迭代速度慢;


其二,系统常常会由于某处业务的瓶颈致使整个业务瘫痪,架构没法扩展,木桶效应严重,没法知足业务的可用性要求;


最后,总体组织效率低下,没法很好地利用资源,存在大量的浪费。所以,组织迫切须要进行变革。随着大量开源技术的成熟和云计算的发展,服务化的改造应运而生,不一样的架构设计风格随之涌现,最有表明性的是Netflix公司,它是国外最先基于云进行服务化架构改造的公司,2008年由于全站瘫痪被迫停业3天后,它痛下决心改造,通过将近10年的努力,实现了从单架构到微服务全球化的变迁,知足了业务的千倍增加(如图1-7所示),并产生了一系列的最佳实践。

图1-7  Netflix微服务化支撑业务千倍增加

随着微服务化架构的优点展示和快速发展,2013年,MartinFlower对微服务概念进行了比较系统的理论阐述,总结了相关的技术特征。首先,微服务是一种架构风格,也是一种服务;其次,微服务的颗粒比较小,一个大型复杂软件应用由多个微服务组成,好比Netflix目前由500多个的微服务组成;最后,它采用UNIX设计的哲学,每种服务只作一件事,是一种松耦合的可以被独立开发和部署的无状态化服务(独立扩展、升级和可替换)。微服务架构如图1-8所示。

图1-8  微服务架构示例

由微服务的定义分析可知,一个微服务基本是一个能独立发布的应用服务,所以能够做为独立组件升级、灰度或复用等,对整个大应用的影响也较小,每一个服务能够由专门的组织来单独完成,依赖方只要定好输入和输出口便可彻底开发,甚至整个团队的组织架构也会更精简,所以沟通成本低、效率高。根据业务的需求,不一样的服务能够根据业务特性进行不一样的技术选型,是计算密集型仍是I/O密集型应用均可以依赖不一样的语言编程模型,各团队能够根据自己的特点独自运做。服务在压力较大时,也能够有更多容错或限流服务。

微服务架构确实有不少吸引人的地方,然而它的引入也是有成本的,它并非银弹,使用它会引入更多技术挑战,好比性能延迟、分布式事务、集成测试、故障诊断等方面,企业须要根据业务的不一样的阶段进行合理的引入,不能彻底为了微服务而“微服务”,本书第5章也会对如何解决这些问题提供对应不一样方案的权衡。

--

12要素

“12要素”英文全称是The Twelve-Factor App,最初由Heroku的工程师整理起步,是集体贡献总结的智慧,如图1-9所示。根据基于云的软件开发模式,12要素比较贴切地描述了软件应用的原型,并诠释了使用原生云应用架构的缘由。


好比,一个优雅的互联网应用在设计过程当中,须要遵循的一些基本原则和云原生有殊途同归之处。经过强化详细配置和规范,相似Rails的基于“约定优于配置”(convention over configuration)的原则,特别在大规模的软件生产实践中,这些约定很是重要,从无状态共享到水平扩展的过程,从松耦合架构关系到部署环境。基于12要素的上下文关联,软件生产就变成了一个个单一的部署单元;多个联合部署的单元组成一个应用,多个应用之间的关系就能够组成一个复杂的分布式系统应用。


图1-9  12要素

下面简要介绍图1-9中的这些原则。相信不少开发者在实际开发工做中已经很好地应用了其中的一些原则,只是没有意识到概念自己。对这些原则比较陌生的开发者,若是想了解更多的操做过程,请参阅《云原生时代下的12要素(12-Factor)应用与实践》一文。

基准代码

每个部署的应用都在版本控制代码库中被追踪。在多个部署环境中,会有多种部署实例,单个应用只有一份代码库,多份部署至关于运行了该应用的多个实例,好比开发环境一个实例,测试环境、生产环境都有一个实例。

实际上,在云计算架构中,全部的基础设施都是代码配置,即Infrastructure as Code(IaC),整个应用经过配置文件就能够编排出来,而再也不须要手工的干预,作到基础服务也是能够追踪的。

依赖

应用程序不会隐式依赖系统级的类库,经过依赖清单声明全部依赖项,经过依赖隔离工具确保程序不会调用系统中存在,但清单中未声明依赖项,并统一应用到生产和开发环境。好比经过合适的工具(例如Maven、Bundler、NPM),应用能够很清晰地对部署环境公开和隔绝依赖性,而不是模糊地对部署环境产生依赖性。

在容器应用中,全部应用的依赖和安装都是经过DockerFile来完成声明的,经过配置能明确把依赖关系,包括版本都明确地图形化展现出来,不存在黑盒。

配置

环境变量是一种清楚、容易理解和标准化的配置方法,将应用的配置存储于环境变量中,保证配置排除在代码以外,或者其余可能在部署环境(例如研发、展现、生产)之间区别的任何代码,能够经过操做系统级的环境变量来注入。

实例根据不一样的环境配置运行在不一样的环境中,此外,实现配置即代码,在云环境中,不管是统一的配置中心仍是分布式的配置中心都有好的实践方式,好比Docker的环境变量使用。

后端服务

不用区别对待本地或第三方服务,统一把依赖的后端做为一种服务来对待,例如数据库或者消息代理,做为附加资源,同等地在各类环境中被消耗。好比在云架构的基础服务中,计算、网络、存储资源均可以看做是一种服务去对待使用便可,不用区分是远程仍是本地的。

构建、发布、运行

应用严格区分构建、发布、运行这3个阶段。3个阶段是严格分开的,一个阶段对应作一件事情,每一个阶段有很明确的实现功能。云原生应用的构建流程能够把发布配置挪到开发阶段,包括实际的代码构建和运行应用所需的生产环境配置。在云原生应用中,基于容器的Build-Ship-Run和这3个阶段彻底吻合,也是Docker对本原则的最佳实践。

进程

进程必须无状态且无共享,即云应用以一个或多个无状态不共享的程序运行。任何须要状态都被服务化到后端服务中(缓存、对象存储等)。

全部的应用在设计时就认为随时随地会失败,面向失败而设计,所以进程可能会被随时拉起或消失,特别是在弹性扩容的阶段。

端口绑定

不依赖于任何网络服务器就能够建立一个面向网络的服务,每一个应用的功能都很齐全,经过端口绑定对外提供全部服务,好比Web应用经过端口绑定(Port binding)来提供服务,并监听发送至该端口的请求(包括HTTP)。

在容器应用中,应用统一经过暴露端口来服务,尽可能避免经过本地文件或进程来通讯,每种服务经过服务发现而服务。

并发

进程能够看做一等公民,并发性便可以依靠水平扩展应用程序来实现,经过进程模型进行扩展,而且具有无共享、水平分区的特性。

在互联网的服务中,业务的爆发性随时可能发生,所以不太可能经过硬件扩容来随时提供扩容服务,须要依赖横向扩展能力进行扩容。

易处理

全部应用的架构设计都须要支持能随时销毁的特色,和状态的无关性保持一致,容许系统快速弹性扩展、改变部署及故障恢复等。

在云环境中,因为业务的高低峰值常常须要能实现快速灵活、弹性的伸缩应用,以及不可控的硬件因素等,应用可能随时会发生故障,所以应用在架构设计上须要尽量无状态,应用能随时随地拉起,也能随时随地销毁,同时保证进程最小启动时间和架构的可弃性,也能够提供更敏捷的发布及扩展过程。

环境等价

必须缩小本地与线上差别,确保环境的一致性,保持研发、测试和生产环境尽量类似,这样能够提供应用的持续交付和部署服务。

在容器化应用中,经过文件构建的环境运行能作到版本化,所以保证各个不一样环境的差别性,同时还能大大减小环境不一样带来的排错等成本沟通问题。

日志

每个运行的进程都会直接标准输出(stdout)和错误输出(stderr)事件流,还能够将日志看成事件流做为数据源,经过集中服务,执行环境收集、聚合、索引和分析这些事件。

日志是系统运行状态的部分体现,不管在系统诊断、业务跟踪仍是后续大数据服务的必要条件中,Docker提供标准的日志服务,用户能够根据需求作自定义的插件开发来处理日志。

管理进程

管理或维护应用的运行状态是软件维护的基础部分,好比数据库迁移、健康检查、安全巡检等,在与应用长期运行的程序相同环境中,做为一次性程序运行。

在应用架构模式中,好比Kubernetes里面的Pod资源或者dockerexec,能够随着其余的应用程序一块儿发布或在出现异常诊断时能经过相关的程序去管理其状态。

云原生的内容很是普遍,目前没有系统的说明和完整的定义,上文介绍了云原生应用的基础组件和相关特色,可能读者对云原生应用的逻辑还存在一些困惑。为了更清楚地进行说明,咱们总结了其依赖关系,如图1-10所示。

图1-10  云原生内容的依赖关系

首先,为了抓住商业机会,业务须要快速迭代,不断试错,所以,企业须要依赖拥有持续交付的能力,这些不只包括技术需求还包括产品的需求,如何能拥有持续交付的能力,大而全的架构由于效率低下,显然是不合适的。因而演变出微服务架构来知足需求,经过把系统划分出一个个独立的个体,每一个个体服务的设计依赖须要经过12要素的原则来规范完成。

一样,若是系统被分红了几十个甚至几百个服务组件,则须要借助DevOps才能很好地知足业务协做和发布等流程。最后,DevOps的有效实施须要依赖必定的土壤,即敏捷的基础设施服务,现实只有云计算的模式才能知足总体要求。经过上述梳理,咱们总结出面向云原生应用的3个不一样层次的特色。

  • 高可用设计(Design for Availability),依据应用业务需求,高可用分为不一样级别,好比不一样区域、不一样机房(跨城或同城)、不一样机柜、不一样服务器和不一样进程的高可用,云原生应用应该根据业务的可用性要求设计不一样级别的架构支持。
  • _可扩展设计(Design for Scale)_,全部应用的设计是无状态的,使得业务天生具备扩展性,在业务流量高峰和低峰时期,依赖云的特性自动弹性扩容,知足业务需求。
  • _快速失败设计(Design for Failure)_,即包括系统间依赖的调用随时可能会失败,也包括硬件基础设施服务随时可能宕机,还有后端有状态服务的系统能力可能有瓶颈,总之在发生异常时可以快速失败,而后快速恢复,以保证业务永远在线,不能让业务半死不活地僵持着。

经过上面的基本描述及云原生应用的组成或特色,与容器技术(第2章将详细介绍)相比能够得知,容器的特性天生就是按这些原则进行设计的。随着互联网业务的架构不断演进,从单体应用到分布式应用,甚至微服务架构应用中,12要素较好地为构建互联网化应用提供了统一的方法论和标准化,具备强大的生命力,每一条原则都是应用开发的珠玑。固然,在实践过程当中,每个原则也不是一成不变的,随着新的理念和技术出现,原有的因素会获得延伸和发展,会出现新的原则和应用,这套理论也适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序,所以也做为云原生架构应用的基本指导原则之一。

注:本文节选自《云原生应用架构实践》,网易云基础服务架构团队著,全程详解单体到分布式服务化架构的演进。更多精彩内容,敬请期待下期分享。