12-Factor - 构建SaaS应用提供了方法论

1. 构建网络应用程序或软件即服务(SaaS)应用提供的方法论

这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序, 初衷是分享在现代软件开发过程中发现的一些系统性问题,并加深对这些问题的认识。

  • 使用标准化流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。
  • 和操作系统之间尽可能的划清界限,在各个系统中提供最大的可移植性。
  • 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
  • 将开发环境和生产环境的差异降至最低,并使用持续交付实施敏捷开发。
  • 可以在工具、架构和开发流程不发生明显变化的前提下实现扩展。

2. 构建SaaS服务的12-Factor

2.1. 基准代码:一份基准代码(Codebase),多份部署(deploy)

  • 代码库(code repository, code repo, repo)
  • 基准代码:git最上游的那份代码库,svn中心代码库
  • 基准代码和应用之间总是保持一一对应的关系
  • 部署: 每份部署相当于运行了一个应用的实例,每份部署可以使用其不同的版本

2.2. 依赖:显示申明依赖

  • 打包系统
  • 包类型:site packages、 vendoring| bunding
  • 依赖清单: 12-Factor规则下的应用程序不会隐式依赖系统级的类库
  • 依赖隔离:无论用什么工具,依赖声明和依赖隔离必须一起使用,否则无法满足 12-Factor 规范
  • 构建命令:显式声明依赖的优点之一是为新进开发者简化了环境配置流程。

2.3. 配置:在环境中存储配置

  • 应用的配置在不同 部署 (预发布、生产环境、开发环境等等)间会有很大差异(缓存、DB、证书、服务配置、域名等)
  • 判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。
  • 12-Factor推荐将应用的配置存储于环境变量中( env vars, env),而非常量或者环境差异文件中
  • 12-Factor 应用中,环境变量的粒度要足够小,且相对独立。它们永远也不会组合成一个所谓的“环境”,而是独立存在于每个部署之中。当应用程序不断扩展,需要更多种类的部署时,这种配置管理方式能够做到平滑过渡。

2.4. 后端服务:把后端服务当做附加资源

  • 后端服务是指程序运行所需要的通过网络调用的各种服务,如数据库(MySQL,CouchDB),消息/队列系统(RabbitMQ,Beanstalkd),SMTP 邮件发送服务(Postfix),以及缓存系统(Memcached)。
  • 除了本地服务之外,应用程序有可能使用了第三方发布和管理的服务。
  • 12-Factor应用不会区别对待本地或第三方服务(切换的话仅需修改配置中的资源地址。)
  • 附加资源:部署可以按需加载或卸载资源。

2.5. 构建、发布、运行:严格分离构建和运行

  • 构建阶段: 指将代码仓库转化为可执行包的过程
  • 发布阶段: 将构建的结果和当前部署所需 配置 相结合, 并能够立刻在运行环境中投入使用
  • 运行阶段: 针对选定的发布版本,在执行环境中启动一系列应用程序 进程
  • 12-factor应用严格区分构建,发布,运行这三个步骤。

2.6. 进程:以一个或多个无状态进程运行应用

  • 运行环境中,应用程序通常是以一个和多个进程运行的。
  • 12-Factor 应用的进程必须无状态且 无共享 (进程可能会重启)
  • 12-Factor 应用更倾向于在 构建步骤 中做类似于文件系统来缓存编译过的源文件的此动作,而不是在运行阶段
  • 粘性session是12-Factor极力反对的。(Session 中的数据应该保存在诸如 Memcached 或 Redis 这样的带有过期时间的缓存中。)

2.7. 端口绑定:通过端口绑定提供服务

  • 互联网应用有时会运行于服务器的容器之中。 例如 PHP 经常作为 Apache HTTPD 的一个模块来运行,正如 Java 运行于 Tomcat 。
  • 12-Factor应用完全自我加载,而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用通过端口绑定来提供服务,并监听发送至该端口的请求。( 应用的代码,发起请求,和运行环境约定好绑定的端口即可处理这些请求。)

2.8. 并发:通过进程模型进行扩展

  • 任何计算机程序,一旦启动,就会生成一个或多个进程。互联网应用采用多种进程运行方式。
  • 按需请求(APACHE+PHP)、预先配置JVM初始化(通过多线程实现内部并发管理)
  • 12-factor应用中,进程是一等公民。
  • 12-Factor应用的进程主要借鉴于 unix 守护进程模型 。
  • 12-Factor应用的进程所具备的无共享,水平分区的特性
  • 12-Factor应用的进程 不需要守护进程 或是写入PID文件,应该借助操作系统的进程管理器
  • 进程构成

2.9. 易处理:快速启动和优雅终止可最大化健壮性

  • 12-Factor应用的进程是易处理(disposable)的,意思是说它们可以瞬间开启或停止。这有利于快速、弹性的伸缩应用,迅速部署变化的 代码 或 配置 ,稳健的部署应用。
  • 进程应当追求最小启动时间
  • 进程一旦接收终止信号(SIGTERM)就会优雅的终止
  • 进程还应当在面对突然死亡时保持健壮,例如底层硬件故障
  • 12-Factor应用都应该可以设计能够应对意外的、不优雅的终结。

2.10. 开发环境与线上环境等价:尽可能的保持开发、测试、预发布、线上环境相同

  • 环境之间的差异:部署时间差异、人员分工差异、工具差异
  • 12-Factor应用想要做到持续部署就必须缩小本地与线上差异
  • 12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务
  • 使用类似 Chef 和 Puppet 的声明式配置工具,结合像 Vagrant 这样轻量的虚拟环境就可以使得开发人员的本地环境与线上环境无限接近。

2.11. 日志:把日志当做事件流

  • 日志使得应用程序运行的动作变得透明。在基于服务器的环境中,日志通常被写在硬盘的一个文件里,但这只是一种输出格式。
  • 日志应该是 事件流 的汇总,将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行,日志最原始的格式确实是一个事件一行。日志没有确定开始和结束,但随着应用在运行会持续的增加。
  • 12-factor应用本身从不考虑存储自己的输出流,不应该试图去写或者管理日志文件。
  • 在预发布或线上部署中,每个进程的输出流由运行环境截获,并将其他输出流整理在一起,然后一并发送给一个或多个最终的处理程序,用于查看或是长期存档。这些存档路径对于应用来说不可见也不可配置,而是完全交给程序的运行环境管理。类似 Logplex 和 Fluentd 的开源工具可以达到这个目的。
  • 这些事件流可以输出至文件,或者在终端实时观察。最重要的,输出流可以发送到 Splunk 这样的日志索引及分析系统,或 Hadoop/Hive 这样的通用数据存储系统。这些系统为查看应用的历史活动提供了强大而灵活的功能,包括:
    • 找出过去一段时间特殊的事件。
    • 图形化一个大规模的趋势,比如每分钟的请求量。
    • 根据用户定义的条件实时触发警报,比如每分钟的报错超过某个警戒线。

2.12. 管理进程:后台管理任务当做一次性进程运行

  • 进程构成(process formation)是指用来处理应用的常规业务(比如处理 web 请求)的一组进程。 与此不同,开发人员经常希望执行一些管理或维护应用的一次性任务,例如:
    • 运行数据移植(Django 中的 manage.py migrate, Rails 中的 rake db:migrate)。
    • 运行一个控制台(也被称为 REPL shell),来执行一些代码或是针对线上数据库做一些检查。大多数语言都通过解释器提供了一个 REPL 工具(python 或 perl) ,或是其他命令(Ruby 使用 irb, Rails 使用 rails console)。
    • 运行一些提交到代码仓库的一次性脚本。
  • 12-factor 尤其青睐那些提供了 REPL shell 的语言,因为那会让运行一次性脚本变得简单。

3. 参考

  • 官档:https://12factor.net/zh_cn/