云原生(Cloud Native)最初是由 Pivotal 公司的 Matt Stine 于 2013 年提出的。Pivotal 公司 先后开源了云原生的 Java 开发框架 Spring Boot 和 Spring Cloud。随后,Google 在 2015 年成立 了 CNCF(Cloud Native Computing Foundation),使得云原生受到越来越多的关注。
概述
要想理解什么是云原生,我们需要先理解什么是云。
有人认为“云”的同义词是“可公开所有信息的互联网”,这个说法是不正确的。云一般指 的是一个提供资源的平台,云计算的本质是按需分配资源和弹性计算。
顾名思义,云原生应用即专门为在云平台部署和运行而设计的应用。云原生应用并非完全颠覆传统的应用,采用云原生的设计模式可以优化和改进传统应用模式,使应用更加适合在云平台上运行。
在云计算越来越流行的今天,云原生成了一个必然的导向。云原生存在的意义是解放开发和运维,而不是让开发和运维工作变得更加复杂和繁重。
其实,大部分传统应用即便不做任何改动,也可以在基于 Linux 操作系统内核的云平台上 部署和运行,但是仅以能够部署和运行为主要目的,将云主机当作物理机一样使用,是无法充 分利用云平台的能力的。
让应用能够利用云平台实现资源的按需分配和弹性伸缩,是云原生应用被重点关注的地方。 云原生还关注规模,分布式系统应该具备将节点扩展到成千上万个的能力,并且这些节点应具 有多租户和自愈能力。
云原生使得应用本身具有“柔性”,即面对强大压力的缓解能力以及压力过后的恢复能力。 正所谓“刚而易折,柔则长存”,对于一个单机处理能力很强的“刚性”系统而言,一旦崩溃, 则很难恢复;而通过云原生实现的关注分布式与可水平伸缩的“柔性”系统,是不太容易全线 覆灭的。
从本质上来说,云原生是一种设计模式,它要求云原生应用具备可用性和伸缩性,以及自动化部署和管理的能力,可随处运行,并且能够通过持续集成、持续交付工具提升研发、测试与发布的效率。
在云原生体系中,有下面两组词语用于形容应用。
无状态(stateless)、牲畜(cattle)、无名(nameless)、可丢弃(disposable):表示应用 并未采用本地内存和磁盘存储状态和日志,因此可以将应用随意部署到另一个全新的 环境中,在本书中我们将这类应用统称为无状态应用。
有状态(stateful)、宠物(pet)、有名(having name)、不可丢弃(non-disposable):表 示应用状态将依赖于本地的运行环境,因此无法将应用随意部署至其他环境,应用是 不能随意扩展的,在本书中我们将这类应用统称为有状态应用。
云原生与十二要素
十二要素(The Twelve Factors)是由 Heroku 团队提出的云应用设计理念,它为构建流程标 准化和高可移植的 SaaS 应用提供了完善的方法论。遵循十二要素设计的应用具备云原生应用的 所有特征。十二要素适用于任何语言开发的后端应用服务,它提供的方法论和核心思想如下。
将流程自动化和标准化,降低新员工的学习成本。
划清与底层操作系统间的界限,以保证最大的可移植性。
适合部署在现代云平台上,避免对服务器与操作系统进行管理。
将开发环境与生产环境的差异降至最低,便于实施持续交付和敏捷开发。
应用可以在不改变现有工具、架构或开发流程的情况下,方便地进行水平伸缩。
十二要素重点关注应用程序的健康成长,开发者之间的有效代码协作,以及避免软件腐蚀。 十二要素的内容如图 1-8 所示。
下面我们来逐条介绍一下十二要素。
1.基准代码(Codebase)
同一应用对应同一套基准代码,并能够多次部署。
部署到不同环境的同一个应用,其基准代码库应该相同,但每份部署可以包含各自环境中的不同配置。一次部署对应一个运行起来的应用程序,应用与部署的关系是一对多的,这体现了应用代码的可重用性。同一套基准代码可以重用到多次部署中去,共享的是代码,而不同的仅仅是配置。从另一个角度来说,非运行时的应用对应的是代码仓库,它的每一个运行时实例都对应一次部署,同一代码仓库可以保障应用的复原能力。
推荐使用 Git、SVN 等优秀的源代码管理工具作为基准代码库。基准代码与部署的关系如 图 1-9 所示。
2.依赖(Dependencies)
显式声明第三方依赖。
随着技术的发展,应用程序的开发已不再是一个从零开始的过程,大量的第三方类库使得工程师们可以站在巨人的肩膀上进行增量式开发。应用程序不应隐式地依赖类库,而是应该通过依赖清单明确地声明其依赖项。
显式声明依赖简化了环境配置流程,开发工程师仅需要安装编程语言环境和它对应的依赖管理工具,并从代码库中检索出代码,即可通过一个命令来构建所有的依赖项,从而轻松地开始工作。
十二要素要求应用同样不应该隐式依赖某些系统工具,比如 curl。即使这些系统工具存在 于所有的现代操作系统中,也无法保证未来的操作系统都能支持或兼容现有应用的使用方式。
现代编程语言都会提供依赖打包管理工具,如 Java 语言的 Maven、Gradle 以及早期的 Ant 等。
3.配置(Config)
将配置存储至环境变量。
应用的配置在不同环境中部署时也会有所差异,若应用将配置以编码的方式写入程序的常量,则会造成代码与配置混淆。十二要素强调配置应该与代码分离,不应在源码中包含任何与环境相关的敏感信息。
虽然将配置提炼到属性文件可以实现将其与代码分离,但属性文件仍然可能会被不小心地提交至源码仓库。因此,十二要素推荐将配置存储于环境变量中,这样可以非常方便地在不同的部署环境间修改,而无须改动代码。
与配置文件相比,环境变量与语言和系统无关。将配置存储在环境变量中能够方便与 Docker 等基于容器的应用配合使用,也易于与 Kubernetes 的 ConfigMap 配合使用。将配置排除在代码 之外的标准取决于,应用是否可以立刻开源且不必担心暴露任何系统的敏感信息。
十二要素并不赞同采用配置分组的方式管理配置。有些开发团队愿意将应用的配置按照特 定的环境(如开发环境、测试环境和生产环境)进行分组。采用配置分组方式不利于扩展,当 工程师添加他们自己的开发环境(例如 john-dev)时,将导致各种配置组合激增,给管理部署 增加额外的不确定性。
十二要素要求环境变量的粒度足够小且相对独立,它们不应该作为环境组合使用,而是应该独立存在于每个部署之中。当应用程序拥有更多种类的配置项或进行环境部署时,采用这种配置管理方式更容易实现平滑过渡。
需要特别指出的是,这里所指的配置并不包括应用程序的内部配置。举例来说,Spring 容 器中 Bean 的依赖注入配置,或者 Servlet 的映射配置文件 web.xml 等,它们更应该被认为是代 码的一部分。
4.后端服务(Backing Services)
将后端服务作为松耦合的资源。
后端服务是指应用程序所依赖的通过网络调用的远程服务,如数据库、缓存、消息中间件 以及文件系统等,不同后端服务之间的区别仅仅在于资源的 URL 不同。
十二要素要求应用程序不应该区别对待本地服务和远程服务,它们同样都属于附加资源。 应用程序可以在不改动任何代码、仅修改资源地址的情况下,将出现硬件问题的数据库切换为 备份数据库,或将本地数据库切换为云数据库。应用程序与这些附加资源应该保持松耦合的状 态。图 1-10 展示了后端服务松耦合的状态。
5.构建、发布、运行(Build、Release、Run)
严格分离构建阶段与运行阶段。
分离构建阶段与运行阶段的根本在于,要严格区分应用的非运行时状态和运行时状态。构建是将应用的源代码编译打包成可执行软件的过程,属于非运行时行为。将基准代码转化为一份部署一般要经过构建阶段、发布阶段和运行阶段。构建阶段是将源码从编译状态转化为可执行的二进制文件的过程;发布阶段是将构建结果与当前部署所需要的配置相结合,并分发至运行环境的过程;运行阶段是在执行环境中启动一系列发布完毕的应用程序进程的过程。
十二要素规定,禁止在运行阶段改动代码,这样做会导致基准代码失去同步。建议每个发 布版本对应一个唯一的发布 ID,发布版本只能追加而不能修改,除了回滚,其他变动都应该产 生新的发布版本。构建与发布的流程如图 1-11 所示。
6.进程(Processes)
将应用作为无状态的进程运行。
应用进程应该是无状态的。只有无状态的应用才能做到水平伸缩,从而利用云平台弹性伸缩的能力,而需要持久化的数据应该存储于后端服务中。
在有些遗留系统的设计中,Web 应用通常会将用户会话中的数据缓存至内存,并保证将同 一用户的后续请求路由到同一个进程,这种会话被称为黏性会话。十二要素并不推荐这种做法, 会话数据应该保存至 Redis 这样的带有过期时间的缓存中,并作为后端服务提供服务。
7.端口绑定(Port Binding)
通过端口绑定对外发布服务。
应用本身对于发布服务的环境不应该有过多的要求,不需要依赖云平台提供应用运行容器, 只要云平台分配某个端口对外发布服务即可。通过端口绑定访问服务也意味着任何应用都可以 成为另一个应用的后端服务。
例如,可以利用 Jetty 这种内嵌的 Web 服务器或 Spring Boot 等快速开发框架来开发包含可 发布 HTTP 服务的应用。
8.并发(Concurrency)
能够通过水平伸缩应用程序进程来实现并发。
云平台操作系统与 UNIX 操作系统类似,运行在系统之上的不同进程彼此独立并且共享操作系统管理的硬件资源。不同的应用彼此独立、互不干扰地运行在一个云平台上,可以充分利用云平台的整体计算能力。这样的进程模型对于系统扩容非常实用。
开发人员应该将不同类型的工作分配给不同的进程,例如,将 HTTP 请求交给 Web 服务器 的进程来处理,将常驻后台进程交给 worker 进程负责,将定时任务交给 clock 进程负责。这条 原则与微服务的设计原则有异曲同工之妙,它希望应用开发者将应用的职责尽可能进行拆分。 图 1-12 清晰地展示了如何通过增加不同类型的应用进程来实现系统的水平伸缩。
9.已处理(Disposability)
可以快速启动和优雅关闭应用。
快速启动是为了充分利用云平台根据需要调度资源的能力,在需要的时候,以最小的延时扩展计算能力,提供服务。优雅关闭是为了保证应用逻辑的完整性,将该完成的任务正确完成并释放资源,将未能完成的任务重新交回系统由其他应用的运行实例来继续完成。随时可能有大量部署在云平台上的应用实例启动、运行和关闭,因此快速启动和优雅关闭应用对于维持系统的高性能和稳定性尤为重要。
10.开发环境与线上环境等价(Dev/Prod parity)
要保持开发环境与线上环境等价。
开发环境和线上环境之间存在着很多差异,主要包括代码差异和操作差异。开发人员正在编写的代码可能需要很长时间才会上线,这将导致开发环境和线上环境的代码差异很大。在开发环境中,代码一般由开发人员编写并调试,而在线上环境中,代码则由运维人员部署,不同的操作方式也可能带来环境的差异。
保持环境一致,可以提高功能测试和集成测试的有效性,避免出现开发环境测试正常但生 产环境出现问题的情况。推荐使用 Jenkins 等持续集成工具来缩短生产代码和代码库中的代码不 一致的时间,并采用自动化部署的方式避免操作差异。
11.日志(Logs)
使用事件流处理日志。
运行在云平台上的应用处在复杂的分布式基础设施之上,如果日志仍然写在硬盘的一个文件中,将给系统排错或通过日志挖掘信息带来很大的困难,并且当日志与应用绑定时,应用不能作为无状态进程,也就无法充分利用云平台的扩容能力了。
为了解决以上问题,我们应采取相应措施——应用将日志输出到标准输出(STDOUT),然 后由云平台统一收集并处理。在线上环境中,进程的输出事件流由运行环境截获,运行环境会 将所有输出事件流整合在一起,然后发送给一个或多个最终的处理程序,用于查看或长期存档。
推荐使用 Flume、Filebeat 或 fluentd 等日志收集工具。日志事件流最终可以被发送到 Elasticsearch 或 Splunk 这样的日志索引及分析系统中,用于排错查询和后期分析。
12.管理进程(Admin Processes)
将后台管理任务当作一次性进程运行。
与用来处理应用的常规业务进程不同,工程师经常希望执行一些用于管理或维护应用的一次性任务,这类任务被称为后台管理任务,例如检查和清理环境、迁移数据等。
这些后台管理任务应该作为一次性进程,与常驻进程使用同样的环境,基于同样的代码库和配置发布运行。总而言之,一次性进程同样应该遵循前面提到的十一个要素。
遵循十二要素的应用程序环境是一次性且可复制的。由于应用程序的状态均通过后端服务持有,因此无状态的应用有助于编排系统自动化扩展。扩容时,编排系统仅须将应用程序的运行时环境数量扩充到期望位并直接启动进程即可;缩容时,则需要停止应用进程并删除环境,无须进行环境状态备份。
要想了解有关十二要素的详细内容,请参见官方网站:https://www.12factor.net/。
相关文章:
本文节选自图书《未来架构:从服务化到云原生》第一章。本书对快速演进中的云原生数据架构、典型分布式数据库中间件进行了剖析,重点介绍 Service Mesh 等新兴概念,创新性地提出了 Database Mesh 的理念,深度揭秘 Apache 项目——ShardingSphere。
购买链接: https://u.jd.com/sbmG4Y
作者简介:
张亮
京东数科数据研发负责人,Apache ShardingSphere 发起人兼 PPMC 成员。热爱分享,拥抱开源,主张代码优雅化,擅长以 Java 为主的分布式架构以及以 Kubernetes 和 Mesos 为主的云平台的构建。ShardingSphere 已进入 Apache 软件基金会,是京东集团首个进入 Apache 的开源项目,也是 Apache 首个分布式数据库中间件。
吴晟
Apache SkyWalking 创始人及 PPMC 成员,Apache ShardingSphere 原型作者及 PPMC 成员,Apache Zipkin 贡献者,Apache 孵化器导师,CNCF 基金会 OpenTracing 标准化委员会成员,W3C Trace Context 规范贡献者。擅长分布式架构、性能监控与诊断、分布式追踪、云原生监控等领域。
敖小剑
具有十七年软件开发经验,资深码农,微服务专家,Cloud Native 拥护者,敏捷实践者,Service Mesh 布道师,ServiceMesher 中文社区联合创始人。专注于基础架构建设,对微服务、云计算等相关技术有着深入研究和独到见解。
宋净超
蚂蚁金服云原生布道师,ServiceMesher 中文社区联合创始人,Kubernetes 社区成员,Istio 社区成员,《Cloud Native Go》《Python 云原生》《云原生 Java》等图书译者。
评论 1 条评论