云原生应用架构设计原则
1.前言
12 要素应用程序 (12-Factor App) 是由 Heroku 的开发人员定义的用于构建云原生应用程序的一组原则。
然而,它诞生已超过十年,云技术自最初创建以来一直在发展。为了使应用程序能够真正利用现代云基础设施和工具,并在云中蓬勃发展,Kevin Hoffman 修订了最初的12个要素原则,并增加了三项,该书由 O’Reilly 出版社出版。书名是:Beyond the Twelve-Factor App
下面简要介绍这 15 个设计原则。
云原生计算基金会(CNCF)关于云原生技术的定义:
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。
2. 15个架构设计原则
2.1 One codebase, one application 一个应用,一个代码仓库
一个应用一个代码仓库,这里的应用也指微服务,一个微服务通常是具有一定业务边界的功能服务,当我们的软件系统有大量微服务组件时,每个微服务应该有自己的代码仓库。如果多个微服务有共享模块,那么这个共享模块也应该有独立的代码仓库,并使用依赖管理策略去加载它。
2.2 API first API优先
设计 API 时遵循 API 设计规范 OpenAPI v3规范
2.3 Dependency management 依赖管理
在 Java 项目中,依赖管理的两个流行的工具是 Maven 和 Gradle。工具有助于简化依赖管理的复杂性,开发人员能够声明他们的依赖关系,然后让工具负责实际确保这些依赖关系得到满足。
2.4 Design, build, release, and run 设计,构建,发布,运行
这条准则的目标是要最大化的提升发布速度,同时通过自动测试和自动部署来让我们对发布抱有信心。
2.5 Configuration, credentials, and code 配置,证书,和代码
配置指会随着部署环境发生变化的值,包括:
- 后端服务的 URLs 和其他信息,比如 web service 和 SMTP 服务
- 连接到数据库的必要信息
- 调用第三方服务的证书
- 可能需要放到 XMl 或者 YMAL 配置文件的其他属性
配置并不包括程序本身的内部信息,也就是说,如果某一个值在所有的部署环境都是一样的,它就不是配置。
证书是极其敏感的与代码无关的信息,通常来说,程序员会把证书从程序源代码里面提取出来放到属性文件里面,但是这样做并没有解决问题。 因为配置文件本身仍然是代码仓库的一部分,这意味着证书与程序一起发布,这本身就打破了这条规则。
一个最简单的检验证书和配置是否合理的方式,就是假设现在需要把源代码 push 到 GitHub 上面, 如果外面的人需要访问你的代码,你是否把你依赖的服务的敏感信息给暴露出去了呢?不是你的组织内部的人是否看到了内部后端服务的 URLs,证书或者其他敏感的信息呢?
如果能够在不暴露任何敏感信息的情况下去开源你的代码,那么你可能在隔离你的代码、配置、证书方面做的很好了。
外化配置的方式是 可以使用一个配置中心,比如开源的 Spring Cloud Configuration Server,或者其他的配置服务产品。
2.6 Logs 日志
将日志视为事件流,Logs 应该被当作一种事件流,也就是说, logs 是程序内部发出来的时间有序的事件序列。一个真正云原生的应用从来不关心如何路由和存储它的输出流。
应该将日志的聚合,处理和存储视为一项非功能性要求,该要求不是由应用程序满足,而是由云提供商或平台上面的其他工具套件来满足。可以使用ELK技术栈(ElasticSearch,Logstash 和 Kibana),Splunk,Sumologic 等工具或任何其他工具来捕获和分析日志。
2.7 Disposability 易处理
通过快速启动和优雅关机最大限度地提高稳健性。 如果一个应用程序不能快速的重启和停止,那么它就不能快速的扩展,部署,发布和恢复。要在构建应用的时候想到这一点。
如果应用程序正在一个高负载的场景下,就需要快速的启动更多的实例去处理这个负载,但是慢启动会阻碍通过扩展去处理较高的负载。如果应用程序不能快速和优雅的关闭,会失去失败场景下快速恢复的能力,不能快速关闭的能力同样 会有耗尽资源的风险。
许多应用程序会在启动过程中有一些耗时较长的动作,例如获取数据缓存起来或者加载一些依赖项。需要单独处理这种动作。例如,可以将缓存外部化为后端服务,以便应用程序可以快速启动和关闭,而无需执行启动前加载动作。
2.8 Backing services 支持服务
将支持服务视为附加资源,将外部组件(如数据库、电子邮件服务器、消息代理和系统人员可以提供和维护的独立服务)视为附加资源。将资源视为支持服务可以提高软件开发生命周期中的灵活性和效率。
这意味着应用程序没有一行代码会与某个特定的服务耦合到一起,可能会有一个用来发送邮件的后端服务,需要通过 SMTP 连接到邮件服务。但是邮件服务的实现细节不会影响到应用,同时应用也不会依赖于某个固定位置的 SMTP 服务器。
2.9 Environment parity 同等环境
尽可能的保持开发,预发布,线上环境相同,这一点很重要,以便可以确保所有潜在的错误/故障都可以在开发和测试中识别出来,而不是在应用程序投入生产时暴漏出来。
TestContainers 工具使我们能够确保测试环境也尽可能接近生产环境。
2.10 Administrative processes 管理进程
后台管理任务当作一次性进程运行。
不鼓励将一次性管理或管理任务放在微服务中。包括迁移数据库和运行一次性脚本来进行清理。这些应该作为一次性进程运行,它们可以作为 kubernetes 任务运行。 这样,服务可以专注于业务逻辑。
管理进程示例包括:
- 数据迁移
- 运行定时脚本,比如一个凌晨的批量任务
- 运行一次性的自定义的程序
2.11 Port binding 端口绑定
云原生应用通过端口绑定的方式暴露服务。网络可以通过端口号而不是域名来识别服务或应用程序。其原因是,域名和相关的IP地址可以通过手动操作和自动服务发现机制即时分配。因此,将它们用作参考点是不可靠的。根据端口号将服务或应用程序暴露给网络更可靠,也更容易管理。至少,由于网络私有端口号分配和另一个进程公开使用相同端口号之间的冲突而导致的潜在问题可以通过端口转发来避免。
2.12 Stateless processes 无状态进程
云原生应用程序应该是一个单一的无状态进程。所有持久状态都必须在应用程序外部,由后端服务提供。因此,无状态不是说不存在状态,而是说状态不能在应用程序中维护。
例如,一个提供用户管理功能的微服务是无状态的,因此所有用户的列表都在后端服务(例如 MongoDB 数据库)中维护。
2.13. Concurrency 并发
向一个大块的单体应用增加CPU核数,增加内存和其他的资源(虚拟的或者物理的),这种做法被称之为垂直扩展,这种做法不适用于云原生应用。
一个更加理想的扩展方式是水平扩展,相比较于把一个本来就很大的服务进程弄的越来越大,可以创建多个进程,然后在这些进程中分配负载。
大多数云提供商已经完善了这一功能,可以配置规则,根据负载或系统中可用的其他运行时遥测动态扩展应用程序实例的数量。
kubernetes 为我们提供了完善的设施来解决水平扩展的问题。
2.14 Telemetry 遥测
遥测的字面定义是使用特殊设备对某物进行特定测量,然后使用无线通讯将这些测量传输到其它地方。遥测点到源头的测量是需要通过远程,远距离,无实物连接的方式来完成的。
这里特指监控和测量我们的云原生应用。当需要监控应用的时候,这里通常会有多种不同类型的数据:
- 定期健康检查
- 请求审核
- 业务级别事件
- 性能指标和系统日志
在规划监控策略时,要考虑清楚到底需要聚合多少信息、信息传入的速率以及要存储多少信息。如果应用程序从1个实例动态扩展到100个实例,那么也会导致日志流量增加百倍。
开源行业标准 OpenTelemeter 是在应用程序中实现有效分布式跟踪的工具,OpenTelemetry 是各类 API、SDK 和工具形成的集合。可用于插桩、生成、采集和导出遥测数据(链路、指标和日志),帮助你分析软件的性能和行为。
2.15 Authentication and authorization 认证和授权
在理想情况下,所有云原生应用程序都将使用 RBAC(基于角色的访问控制)保护其所有 API 。对应用程序资源的每个请求都应该知道是谁发出请求,以及该使用者所属的角色。这些角色决定调用客户端是否有足够的权限让应用程序接受请求。
有了 OAuth2、OpenID Connect 等工具,各种SSO服务器和标准,以及各种语言特定的身份验证和授权库,安全性应该从一开始就融入到应用程序的开发中,而不应该是在应用程序在生产环境中运行一段时间之后再加上的一个功能。
3. 参考
[1] 云原生计算基金会(CNCF)
[2] 12 要素应用程序 (12-Factor App)
[3] Kevin Hoffman. Beyond the Twelve-Factor App. O’Reilly
[4] Beyond the Twelve-Factor App 中文版
[5] An illustrated guide to 12 Factor Apps
[6] Creating cloud-native applications: 12-factor applications
[7] Beyond the 12 factors: 15-factor cloud-native Java applications
[8] OpenAPI 英文官网
[9] OpenAPI 中文官网
[10] kubernetes
[11] TestContainers
[12] OpenTelemeter
[13] OAuth 2.0
[14] Master OAuth 2.0 from this guide with modern use cases and real-world examples