摘要:將開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境的差異降至最低,并使用持續(xù)交付實(shí)施敏捷開(kāi)發(fā)??梢栽诠ぞ呒軜?gòu)和開(kāi)發(fā)流程不發(fā)生明顯變化的前提下實(shí)現(xiàn)擴(kuò)展。我們的初衷是分享在現(xiàn)代軟件開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)的一些系統(tǒng)性問(wèn)題,并加深對(duì)這些問(wèn)題的認(rèn)識(shí)。
簡(jiǎn)介
如今,軟件通常會(huì)作為一種服務(wù)來(lái)交付,它們被稱為網(wǎng)絡(luò)應(yīng)用程序,或軟件即服務(wù)(SaaS)。12-Factor 為構(gòu)建如下的 SaaS 應(yīng)用提供了方法論:
使用標(biāo)準(zhǔn)化流程自動(dòng)配置,從而使新的開(kāi)發(fā)者花費(fèi)最少的學(xué)習(xí)成本加入這個(gè)項(xiàng)目。
和操作系統(tǒng)之間盡可能的劃清界限,在各個(gè)系統(tǒng)中提供最大的可移植性。
適合部署在現(xiàn)代的云計(jì)算平臺(tái),從而在服務(wù)器和系統(tǒng)管理方面節(jié)省資源。
將開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境的差異降至最低,并使用持續(xù)交付實(shí)施敏捷開(kāi)發(fā)。
可以在工具、架構(gòu)和開(kāi)發(fā)流程不發(fā)生明顯變化的前提下實(shí)現(xiàn)擴(kuò)展。
這套理論適用于任意語(yǔ)言和后端服務(wù)(數(shù)據(jù)庫(kù)、消息隊(duì)列、緩存等)開(kāi)發(fā)的應(yīng)用程序。
背景本文的貢獻(xiàn)者參與過(guò)數(shù)以百計(jì)的應(yīng)用程序的開(kāi)發(fā)和部署,并通過(guò) Heroku 平臺(tái)間接見(jiàn)證了數(shù)十萬(wàn)應(yīng)用程序的開(kāi)發(fā),運(yùn)作以及擴(kuò)展的過(guò)程。
本文綜合了我們關(guān)于 SaaS 應(yīng)用幾乎所有的經(jīng)驗(yàn)和智慧,是開(kāi)發(fā)此類應(yīng)用的理想實(shí)踐標(biāo)準(zhǔn),并特別關(guān)注于應(yīng)用程序如何保持良性成長(zhǎng),開(kāi)發(fā)者之間如何進(jìn)行有效的代碼協(xié)作,以及如何 避免軟件污染 。
我們的初衷是分享在現(xiàn)代軟件開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)的一些系統(tǒng)性問(wèn)題,并加深對(duì)這些問(wèn)題的認(rèn)識(shí)。我們提供了討論這些問(wèn)題時(shí)所需的共享詞匯,同時(shí)使用相關(guān)術(shù)語(yǔ)給出一套針對(duì)這些問(wèn)題的廣義解決方案。本文格式的靈感來(lái)自于 Martin Fowler 的書(shū)籍: Patterns of Enterprise Application Architecture , Refactoring 。
讀者應(yīng)該是哪些人?任何 SaaS 應(yīng)用的開(kāi)發(fā)人員。部署和管理此類應(yīng)用的運(yùn)維工程師。
12因素應(yīng)用(12-Factor)具體流程如下基準(zhǔn)代碼
依賴
配置
后端服務(wù)
構(gòu)建,發(fā)布,運(yùn)行
進(jìn)程
端口綁定
并發(fā)
易處理
開(kāi)發(fā)環(huán)境與線上環(huán)境等價(jià)
日志
管理進(jìn)程
1. 基準(zhǔn)代碼一份基準(zhǔn)代碼(Codebase),多份部署(deploy)
12-Factor應(yīng)用(譯者注:應(yīng)該是說(shuō)一個(gè)使用本文概念來(lái)設(shè)計(jì)的應(yīng)用,下同)通常會(huì)使用版本控制系統(tǒng)加以管理,如Git,?Mercurial,?Subversion。一份用來(lái)跟蹤代碼所有修訂版本的數(shù)據(jù)庫(kù)被稱作?代碼庫(kù)(code repository, code repo, repo)。
在類似 SVN 這樣的集中式版本控制系統(tǒng)中,基準(zhǔn)代碼?就是指控制系統(tǒng)中的這一份代碼庫(kù);而在 Git 那樣的分布式版本控制系統(tǒng)中,基準(zhǔn)代碼?則是指最上游的那份代碼庫(kù)。
基準(zhǔn)代碼和應(yīng)用之間總是保持一一對(duì)應(yīng)的關(guān)系:
一旦有多個(gè)基準(zhǔn)代碼,就不能稱為一個(gè)應(yīng)用,而是一個(gè)分布式系統(tǒng)。分布式系統(tǒng)中的每一個(gè)組件都是一個(gè)應(yīng)用,每一個(gè)應(yīng)用可以分別使用 12-Factor 進(jìn)行開(kāi)發(fā)。
多個(gè)應(yīng)用共享一份基準(zhǔn)代碼是有悖于 12-Factor 原則的。解決方案是將共享的代碼拆分為獨(dú)立的類庫(kù),然后使用?依賴管理?策略去加載它們。
盡管每個(gè)應(yīng)用只對(duì)應(yīng)一份基準(zhǔn)代碼,但可以同時(shí)存在多份部署。每份?部署?相當(dāng)于運(yùn)行了一個(gè)應(yīng)用的實(shí)例。通常會(huì)有一個(gè)生產(chǎn)環(huán)境,一個(gè)或多個(gè)預(yù)發(fā)布環(huán)境。此外,每個(gè)開(kāi)發(fā)人員都會(huì)在自己本地環(huán)境運(yùn)行一個(gè)應(yīng)用實(shí)例,這些都相當(dāng)于一份部署。
所有部署的基準(zhǔn)代碼相同,但每份部署可以使用其不同的版本。比如,開(kāi)發(fā)人員可能有一些提交還沒(méi)有同步至預(yù)發(fā)布環(huán)境;預(yù)發(fā)布環(huán)境也有一些提交沒(méi)有同步至生產(chǎn)環(huán)境。但它們都共享一份基準(zhǔn)代碼,我們就認(rèn)為它們只是相同應(yīng)用的不同部署而已。
2. 依賴顯式聲明依賴關(guān)系( dependency )
大多數(shù)編程語(yǔ)言都會(huì)提供一個(gè)打包系統(tǒng),用來(lái)為各個(gè)類庫(kù)提供打包服務(wù),就像 Perl 的 CPAN 或是 Ruby 的 Rubygems 。通過(guò)打包系統(tǒng)安裝的類庫(kù)可以是系統(tǒng)級(jí)的(稱之為 “site packages”),或僅供某個(gè)應(yīng)用程序使用,部署在相應(yīng)的目錄中(稱之為 “vendoring” 或 “bunding”)。
12-Factor規(guī)則下的應(yīng)用程序不會(huì)隱式依賴系統(tǒng)級(jí)的類庫(kù)。 它一定通過(guò) 依賴清單 ,確切地聲明所有依賴項(xiàng)。此外,在運(yùn)行過(guò)程中通過(guò) 依賴隔離 工具來(lái)確保程序不會(huì)調(diào)用系統(tǒng)中存在但清單中未聲明的依賴項(xiàng)。這一做法會(huì)統(tǒng)一應(yīng)用到生產(chǎn)和開(kāi)發(fā)環(huán)境。
例如, Ruby 的 Bundler 使用 Gemfile 作為依賴項(xiàng)聲明清單,使用 bundle exec 來(lái)進(jìn)行依賴隔離。Python 中則可分別使用兩種工具 – Pip 用作依賴聲明, Virtualenv 用作依賴隔離。甚至 C 語(yǔ)言也有類似工具, Autoconf 用作依賴聲明,靜態(tài)鏈接庫(kù)用作依賴隔離。無(wú)論用什么工具,依賴聲明和依賴隔離必須一起使用,否則無(wú)法滿足 12-Factor 規(guī)范。
顯式聲明依賴的優(yōu)點(diǎn)之一是為新進(jìn)開(kāi)發(fā)者簡(jiǎn)化了環(huán)境配置流程。新進(jìn)開(kāi)發(fā)者可以檢出應(yīng)用程序的基準(zhǔn)代碼,安裝編程語(yǔ)言環(huán)境和它對(duì)應(yīng)的依賴管理工具,只需通過(guò)一個(gè) 構(gòu)建命令 來(lái)安裝所有的依賴項(xiàng),即可開(kāi)始工作。例如,Ruby/Bundler 下使用 bundle install,而 Clojure/Leiningen 則是 lein deps。
12-Factor 應(yīng)用同樣不會(huì)隱式依賴某些系統(tǒng)工具,如 ImageMagick 或是 curl。即使這些工具存在于幾乎所有系統(tǒng),但終究無(wú)法保證所有未來(lái)的系統(tǒng)都能支持應(yīng)用順利運(yùn)行,或是能夠和應(yīng)用兼容。如果應(yīng)用必須使用到某些系統(tǒng)工具,那么這些工具應(yīng)該被包含在應(yīng)用之中。
3. 配置在環(huán)境中存儲(chǔ)配置
通常,應(yīng)用的 配置 在不同 部署 (預(yù)發(fā)布、生產(chǎn)環(huán)境、開(kāi)發(fā)環(huán)境等等)間會(huì)有很大差異。這其中包括:
數(shù)據(jù)庫(kù),Memcached,以及其他 后端服務(wù) 的配置
第三方服務(wù)的證書(shū),如 Amazon S3、Twitter 等
每份部署特有的配置,如域名等
有些應(yīng)用在代碼中使用常量保存配置,這與 12-Factor 所要求的代碼和配置嚴(yán)格分離顯然大相徑庭。配置文件在各部署間存在大幅差異,代碼卻完全一致。
判斷一個(gè)應(yīng)用是否正確地將配置排除在代碼之外,一個(gè)簡(jiǎn)單的方法是看該應(yīng)用的基準(zhǔn)代碼是否可以立刻開(kāi)源,而不用擔(dān)心會(huì)暴露任何敏感的信息。
需要指出的是,這里定義的“配置”并不包括應(yīng)用的內(nèi)部配置,比如 Rails 的 config/routes.rb,或是使用 Spring 時(shí) 代碼模塊間的依賴注入關(guān)系 。這類配置在不同部署間不存在差異,所以應(yīng)該寫(xiě)入代碼。
另外一個(gè)解決方法是使用配置文件,但不把它們納入版本控制系統(tǒng),就像 Rails 的 config/database.yml 。這相對(duì)于在代碼中使用常量已經(jīng)是長(zhǎng)足進(jìn)步,但仍然有缺點(diǎn):總是會(huì)不小心將配置文件簽入了代碼庫(kù);配置文件的可能會(huì)分散在不同的目錄,并有著不同的格式,這讓找出一個(gè)地方來(lái)統(tǒng)一管理所有配置變的不太現(xiàn)實(shí)。更糟的是,這些格式通常是語(yǔ)言或框架特定的。
12-Factor推薦將應(yīng)用的配置存儲(chǔ)于 環(huán)境變量 中( env vars, env )。環(huán)境變量可以非常方便地在不同的部署間做修改,卻不動(dòng)一行代碼;與配置文件不同,不小心把它們簽入代碼庫(kù)的概率微乎其微;與一些傳統(tǒng)的解決配置問(wèn)題的機(jī)制(比如 Java 的屬性配置文件)相比,環(huán)境變量與語(yǔ)言和系統(tǒng)無(wú)關(guān)。
配置管理的另一個(gè)方面是分組。有時(shí)應(yīng)用會(huì)將配置按照特定部署進(jìn)行分組(或叫做“環(huán)境”),例如Rails中的 development, test, 和 production 環(huán)境。這種方法無(wú)法輕易擴(kuò)展:更多部署意味著更多新的環(huán)境,例如 staging 或 qa 。 隨著項(xiàng)目的不斷深入,開(kāi)發(fā)人員可能還會(huì)添加他們自己的環(huán)境,比如 joes-staging ,這將導(dǎo)致各種配置組合的激增,從而給管理部署增加了很多不確定因素。
12-Factor 應(yīng)用中,環(huán)境變量的粒度要足夠小,且相對(duì)獨(dú)立。它們永遠(yuǎn)也不會(huì)組合成一個(gè)所謂的“環(huán)境”,而是獨(dú)立存在于每個(gè)部署之中。當(dāng)應(yīng)用程序不斷擴(kuò)展,需要更多種類的部署時(shí),這種配置管理方式能夠做到平滑過(guò)渡。
4. 后端服務(wù)把后端服務(wù)(backing services)當(dāng)作附加資源
后端服務(wù)是指程序運(yùn)行所需要的通過(guò)網(wǎng)絡(luò)調(diào)用的各種服務(wù),如數(shù)據(jù)庫(kù)(MySQL,CouchDB),消息/隊(duì)列系統(tǒng)(RabbitMQ,Beanstalkd),SMTP 郵件發(fā)送服務(wù)(Postfix),以及緩存系統(tǒng)(Memcached)。
類似數(shù)據(jù)庫(kù)的后端服務(wù),通常由部署應(yīng)用程序的系統(tǒng)管理員一起管理。除了本地服務(wù)之外,應(yīng)用程序有可能使用了第三方發(fā)布和管理的服務(wù)。示例包括 SMTP(例如 Postmark),數(shù)據(jù)收集服務(wù)(例如 New Relic 或 Loggly),數(shù)據(jù)存儲(chǔ)服務(wù)(如 Amazon S3),以及使用 API 訪問(wèn)的服務(wù)(例如 Twitter, Google Maps, Last.fm)。
12-Factor 應(yīng)用不會(huì)區(qū)別對(duì)待本地或第三方服務(wù)。 對(duì)應(yīng)用程序而言,兩種都是附加資源,通過(guò)一個(gè) url 或是其他存儲(chǔ)在 配置 中的服務(wù)定位/服務(wù)證書(shū)來(lái)獲取數(shù)據(jù)。12-Factor 應(yīng)用的任意 部署 ,都應(yīng)該可以在不進(jìn)行任何代碼改動(dòng)的情況下,將本地 MySQL 數(shù)據(jù)庫(kù)換成第三方服務(wù)(例如 Amazon RDS)。類似的,本地 SMTP 服務(wù)應(yīng)該也可以和第三方 SMTP 服務(wù)(例如 Postmark )互換。上述 2 個(gè)例子中,僅需修改配置中的資源地址。
每個(gè)不同的后端服務(wù)是一份 資源 。例如,一個(gè) MySQL 數(shù)據(jù)庫(kù)是一個(gè)資源,兩個(gè) MySQL 數(shù)據(jù)庫(kù)(用來(lái)數(shù)據(jù)分區(qū))就被當(dāng)作是 2 個(gè)不同的資源。12-Factor 應(yīng)用將這些數(shù)據(jù)庫(kù)都視作 附加資源 ,這些資源和它們附屬的部署保持松耦合。
部署可以按需加載或卸載資源。例如,如果應(yīng)用的數(shù)據(jù)庫(kù)服務(wù)由于硬件問(wèn)題出現(xiàn)異常,管理員可以從最近的備份中恢復(fù)一個(gè)數(shù)據(jù)庫(kù),卸載當(dāng)前的數(shù)據(jù)庫(kù),然后加載新的數(shù)據(jù)庫(kù) – 整個(gè)過(guò)程都不需要修改代碼。
5. 構(gòu)建,發(fā)布,運(yùn)行嚴(yán)格分離構(gòu)建和運(yùn)行
基準(zhǔn)代碼 轉(zhuǎn)化為一份部署(非開(kāi)發(fā)環(huán)境)需要以下三個(gè)階段:
構(gòu)建階段 是指將代碼倉(cāng)庫(kù)轉(zhuǎn)化為可執(zhí)行包的過(guò)程。構(gòu)建時(shí)會(huì)使用指定版本的代碼,獲取和打包 依賴項(xiàng),編譯成二進(jìn)制文件和資源文件。
發(fā)布階段 會(huì)將構(gòu)建的結(jié)果和當(dāng)前部署所需 配置 相結(jié)合,并能夠立刻在運(yùn)行環(huán)境中投入使用。
運(yùn)行階段 (或者說(shuō)“運(yùn)行時(shí)”)是指針對(duì)選定的發(fā)布版本,在執(zhí)行環(huán)境中啟動(dòng)一系列應(yīng)用程序 進(jìn)程。
12-factor 應(yīng)用嚴(yán)格區(qū)分構(gòu)建,發(fā)布,運(yùn)行這三個(gè)步驟。 舉例來(lái)說(shuō),直接修改處于運(yùn)行狀態(tài)的代碼是非常不可取的做法,因?yàn)檫@些修改很難再同步回構(gòu)建步驟。
部署工具通常都提供了發(fā)布管理工具,最引人注目的功能是退回至較舊的發(fā)布版本。比如, Capistrano 將所有發(fā)布版本都存儲(chǔ)在一個(gè)叫 releases 的子目錄中,當(dāng)前的在線版本只需映射至對(duì)應(yīng)的目錄即可。該工具的 rollback 命令可以很容易地實(shí)現(xiàn)回退版本的功能。
每一個(gè)發(fā)布版本必須對(duì)應(yīng)一個(gè)唯一的發(fā)布 ID,例如可以使用發(fā)布時(shí)的時(shí)間戳(2011-04-06-20:32:17),亦或是一個(gè)增長(zhǎng)的數(shù)字(v100)。發(fā)布的版本就像一本只能追加的賬本,一旦發(fā)布就不可修改,任何的變動(dòng)都應(yīng)該產(chǎn)生一個(gè)新的發(fā)布版本。
新的代碼在部署之前,需要開(kāi)發(fā)人員觸發(fā)構(gòu)建操作。但是,運(yùn)行階段不一定需要人為觸發(fā),而是可以自動(dòng)進(jìn)行。如服務(wù)器重啟,或是進(jìn)程管理器重啟了一個(gè)崩潰的進(jìn)程。因此,運(yùn)行階段應(yīng)該保持盡可能少的模塊,這樣假設(shè)半夜發(fā)生系統(tǒng)故障而開(kāi)發(fā)人員又捉襟見(jiàn)肘也不會(huì)引起太大問(wèn)題。構(gòu)建階段是可以相對(duì)復(fù)雜一些的,因?yàn)殄e(cuò)誤信息能夠立刻展示在開(kāi)發(fā)人員面前,從而得到妥善處理。
6. 進(jìn)程以一個(gè)或多個(gè)無(wú)狀態(tài)進(jìn)程運(yùn)行應(yīng)用
運(yùn)行環(huán)境中,應(yīng)用程序通常是以一個(gè)和多個(gè) 進(jìn)程 運(yùn)行的。
最簡(jiǎn)單的場(chǎng)景中,代碼是一個(gè)獨(dú)立的腳本,運(yùn)行環(huán)境是開(kāi)發(fā)人員自己的筆記本電腦,進(jìn)程由一條命令行(例如 python my_script.py)。另外一個(gè)極端情況是,復(fù)雜的應(yīng)用可能會(huì)使用很多 進(jìn)程類型 ,也就是零個(gè)或多個(gè)進(jìn)程實(shí)例。
12-Factor 應(yīng)用的進(jìn)程必須無(wú)狀態(tài)且 無(wú)共享 。 任何需要持久化的數(shù)據(jù)都要存儲(chǔ)在 后端服務(wù) 內(nèi),比如數(shù)據(jù)庫(kù)。
內(nèi)存區(qū)域或磁盤(pán)空間可以作為進(jìn)程在做某種事務(wù)型操作時(shí)的緩存,例如下載一個(gè)很大的文件,對(duì)其操作并將結(jié)果寫(xiě)入數(shù)據(jù)庫(kù)的過(guò)程。12-Factor應(yīng)用根本不用考慮這些緩存的內(nèi)容是不是可以保留給之后的請(qǐng)求來(lái)使用,這是因?yàn)閼?yīng)用啟動(dòng)了多種類型的進(jìn)程,將來(lái)的請(qǐng)求多半會(huì)由其他進(jìn)程來(lái)服務(wù)。即使在只有一個(gè)進(jìn)程的情形下,先前保存的數(shù)據(jù)(內(nèi)存或文件系統(tǒng)中)也會(huì)因?yàn)橹貑ⅲㄈ绱a部署、配置更改、或運(yùn)行環(huán)境將進(jìn)程調(diào)度至另一個(gè)物理區(qū)域執(zhí)行)而丟失。
源文件打包工具(Jammit, django-compressor) 使用文件系統(tǒng)來(lái)緩存編譯過(guò)的源文件。12-Factor 應(yīng)用更傾向于在 構(gòu)建步驟 做此動(dòng)作——正如 Rails資源管道 ,而不是在運(yùn)行階段。
一些互聯(lián)網(wǎng)系統(tǒng)依賴于 “粘性 session”, 這是指將用戶 session 中的數(shù)據(jù)緩存至某進(jìn)程的內(nèi)存中,并將同一用戶的后續(xù)請(qǐng)求路由到同一個(gè)進(jìn)程。粘性 session 是 12-Factor 極力反對(duì)的。Session 中的數(shù)據(jù)應(yīng)該保存在諸如 Memcached 或 Redis 這樣的帶有過(guò)期時(shí)間的緩存中。
7. 端口綁定通過(guò)端口綁定(Port binding)來(lái)提供服務(wù)
互聯(lián)網(wǎng)應(yīng)用有時(shí)會(huì)運(yùn)行于服務(wù)器的容器之中。例如 PHP 經(jīng)常作為 Apache HTTPD 的一個(gè)模塊來(lái)運(yùn)行,正如 Java 運(yùn)行于 Tomcat 。
12-Factor 應(yīng)用完全自我加載 而不依賴于任何網(wǎng)絡(luò)服務(wù)器就可以創(chuàng)建一個(gè)面向網(wǎng)絡(luò)的服務(wù)?;ヂ?lián)網(wǎng)應(yīng)用 通過(guò)端口綁定來(lái)提供服務(wù) ,并監(jiān)聽(tīng)發(fā)送至該端口的請(qǐng)求。
本地環(huán)境中,開(kāi)發(fā)人員通過(guò)類似 http://localhost:5000/ 的地址來(lái)訪問(wèn)服務(wù)。在線上環(huán)境中,請(qǐng)求統(tǒng)一發(fā)送至公共域名而后路由至綁定了端口的網(wǎng)絡(luò)進(jìn)程。
通常的實(shí)現(xiàn)思路是,將網(wǎng)絡(luò)服務(wù)器類庫(kù)通過(guò) 依賴聲明 載入應(yīng)用。例如,Golang的 gin 或 echo, Python 的 Tornado, Ruby 的Thin , Java 以及其他基于 JVM 語(yǔ)言的 Jetty。完全由 用戶端 ,確切的說(shuō)應(yīng)該是應(yīng)用的代碼,發(fā)起請(qǐng)求。和運(yùn)行環(huán)境約定好綁定的端口即可處理這些請(qǐng)求。
HTTP 并不是唯一一個(gè)可以由端口綁定提供的服務(wù)。其實(shí)幾乎所有服務(wù)器軟件都可以通過(guò)進(jìn)程綁定端口來(lái)等待請(qǐng)求。例如,使用 XMPP 的 ejabberd , 以及使用 Redis 協(xié)議 的 Redis 。
還要指出的是,端口綁定這種方式也意味著一個(gè)應(yīng)用可以成為另外一個(gè)應(yīng)用的 后端服務(wù) ,調(diào)用方將服務(wù)方提供的相應(yīng) URL 當(dāng)作資源存入 配置 以備將來(lái)調(diào)用。
8. 并發(fā)通過(guò)進(jìn)程模型進(jìn)行擴(kuò)展
任何計(jì)算機(jī)程序,一旦啟動(dòng),就會(huì)生成一個(gè)或多個(gè)進(jìn)程?;ヂ?lián)網(wǎng)應(yīng)用采用多種進(jìn)程運(yùn)行方式。例如,PHP 進(jìn)程作為 Apache 的子進(jìn)程存在,隨請(qǐng)求按需啟動(dòng)。Java 進(jìn)程則采取了相反的方式,在程序啟動(dòng)之初 JVM 就提供了一個(gè)超級(jí)進(jìn)程儲(chǔ)備了大量的系統(tǒng)資源(CPU 和內(nèi)存),并通過(guò)多線程實(shí)現(xiàn)內(nèi)部的并發(fā)管理。上述 2 個(gè)例子中,進(jìn)程是開(kāi)發(fā)人員可以操作的最小單位。
在 12-factor 應(yīng)用中,進(jìn)程是一等公民。 12-Factor 應(yīng)用的進(jìn)程主要借鑒于?unix 守護(hù)進(jìn)程模型?。
開(kāi)發(fā)人員可以運(yùn)用這個(gè)模型去設(shè)計(jì)應(yīng)用架構(gòu),將不同的工作分配給不同的?進(jìn)程類型?。例如,HTTP 請(qǐng)求可以交給 web 進(jìn)程來(lái)處理,而常駐的后臺(tái)工作則交由 worker 進(jìn)程負(fù)責(zé)。
這并不包括個(gè)別較為特殊的進(jìn)程,例如通過(guò)虛擬機(jī)的線程處理并發(fā)的內(nèi)部運(yùn)算,或是使用諸如?EventMachine,?Twisted,?Node.js?的異步/事件觸發(fā)模型。但一臺(tái)獨(dú)立的虛擬機(jī)的擴(kuò)展有瓶頸(垂直擴(kuò)展),所以應(yīng)用程序必須可以在多臺(tái)物理機(jī)器間跨進(jìn)程工作。
上述進(jìn)程模型會(huì)在系統(tǒng)急需擴(kuò)展時(shí)大放異彩。?12-Factor 應(yīng)用的進(jìn)程所具備的無(wú)共享,水平分區(qū)的特性?意味著添加并發(fā)會(huì)變得簡(jiǎn)單而穩(wěn)妥。這些進(jìn)程的類型以及每個(gè)類型中進(jìn)程的數(shù)量就被稱作?進(jìn)程構(gòu)成?。
12-Factor 應(yīng)用的進(jìn)程?不需要守護(hù)進(jìn)程?或是寫(xiě)入 PID 文件。相反的,應(yīng)該借助操作系統(tǒng)的進(jìn)程管理器(例如?systemd?,分布式的進(jìn)程管理云平臺(tái),或是類似?Foreman?的工具),來(lái)管理?輸出流?,響應(yīng)崩潰的進(jìn)程,以及處理用戶觸發(fā)的重啟和關(guān)閉超級(jí)進(jìn)程的請(qǐng)求。
9. 易處理快速啟動(dòng)和優(yōu)雅終止可最大化健壯性
12-Factor 應(yīng)用的 進(jìn)程 是 易處理(disposable)的,意思是說(shuō)它們可以瞬間開(kāi)啟或停止。 這有利于快速、彈性的伸縮應(yīng)用,迅速部署變化的 代碼 或 配置 ,穩(wěn)健的部署應(yīng)用。
進(jìn)程應(yīng)當(dāng)追求 最小啟動(dòng)時(shí)間 。 理想狀態(tài)下,進(jìn)程從敲下命令到真正啟動(dòng)并等待請(qǐng)求的時(shí)間應(yīng)該只需很短的時(shí)間。更少的啟動(dòng)時(shí)間提供了更敏捷的 發(fā)布 以及擴(kuò)展過(guò)程,此外還增加了健壯性,因?yàn)檫M(jìn)程管理器可以在授權(quán)情形下容易的將進(jìn)程搬到新的物理機(jī)器上。
進(jìn)程 一旦接收 終止信號(hào)(SIGTERM) 就會(huì)優(yōu)雅的終止。 就網(wǎng)絡(luò)進(jìn)程而言,優(yōu)雅終止是指停止監(jiān)聽(tīng)服務(wù)的端口,即拒絕所有新的請(qǐng)求,并繼續(xù)執(zhí)行當(dāng)前已接收的請(qǐng)求,然后退出。此類型的進(jìn)程所隱含的要求是HTTP請(qǐng)求大多都很短(不會(huì)超過(guò)幾秒鐘),而在長(zhǎng)時(shí)間輪詢中,客戶端在丟失連接后應(yīng)該馬上嘗試重連。
對(duì)于 worker 進(jìn)程來(lái)說(shuō),優(yōu)雅終止是指將當(dāng)前任務(wù)退回隊(duì)列。例如,RabbitMQ 中,worker 可以發(fā)送一個(gè)NACK 信號(hào)。 Beanstalkd 中,任務(wù)終止并退回隊(duì)列會(huì)在worker斷開(kāi)時(shí)自動(dòng)觸發(fā)。有鎖機(jī)制的系統(tǒng)諸如 Delayed Job 則需要確定釋放了系統(tǒng)資源。此類型的進(jìn)程所隱含的要求是,任務(wù)都應(yīng)該 可重復(fù)執(zhí)行 , 這主要由將結(jié)果包裝進(jìn)事務(wù)或是使重復(fù)操作 冪等 來(lái)實(shí)現(xiàn)。
進(jìn)程還應(yīng)當(dāng) 在面對(duì)突然死亡時(shí)保持健壯,例如底層硬件故障。雖然這種情況比起優(yōu)雅終止來(lái)說(shuō)少之又少,但終究有可能發(fā)生。一種推薦的方式是使用一個(gè)健壯的后端隊(duì)列,例如 Beanstalkd ,它可以在客戶端斷開(kāi)或超時(shí)后自動(dòng)退回任務(wù)。無(wú)論如何,12-Factor 應(yīng)用都應(yīng)該可以設(shè)計(jì)能夠應(yīng)對(duì)意外的、不優(yōu)雅的終結(jié)。Crash-only design 將這種概念轉(zhuǎn)化為 合乎邏輯的理論。
10. 開(kāi)發(fā)環(huán)境與線上環(huán)境等價(jià)盡可能的保持開(kāi)發(fā),預(yù)發(fā)布,線上環(huán)境相同
從以往經(jīng)驗(yàn)來(lái)看,開(kāi)發(fā)環(huán)境(即開(kāi)發(fā)人員的本地 部署)和線上環(huán)境(外部用戶訪問(wèn)的真實(shí)部署)之間存在著很多差異。這些差異表現(xiàn)在以下三個(gè)方面:
時(shí)間差異: 開(kāi)發(fā)人員正在編寫(xiě)的代碼可能需要幾天,幾周,甚至幾個(gè)月才會(huì)上線。
人員差異: 開(kāi)發(fā)人員編寫(xiě)代碼,運(yùn)維人員部署代碼。
工具差異: 開(kāi)發(fā)人員或許使用 Nginx,SQLite,OS X,而線上環(huán)境使用 Apache,MySQL 以及 Linux。
12-Factor 應(yīng)用想要做到 持續(xù)部署 就必須縮小本地與線上差異。 再回頭看上面所描述的三個(gè)差異:
縮小時(shí)間差異:開(kāi)發(fā)人員可以幾小時(shí),甚至幾分鐘就部署代碼。
縮小人員差異:開(kāi)發(fā)人員不只要編寫(xiě)代碼,更應(yīng)該密切參與部署過(guò)程以及代碼在線上的表現(xiàn)。
縮小工具差異:盡量保證開(kāi)發(fā)環(huán)境以及線上環(huán)境的一致性。
將上述總結(jié)變?yōu)橐粋€(gè)表格如下:
傳統(tǒng)應(yīng)用 | 12-Factor 應(yīng)用 | |
---|---|---|
每次部署間隔 | 數(shù)周 | 幾小時(shí) |
開(kāi)發(fā)人員 vs 運(yùn)維人員 | 不同的人 | 相同的人 |
開(kāi)發(fā)環(huán)境 vs 線上環(huán)境 | 不同 | 盡量接近 |
后端服務(wù) 是保持開(kāi)發(fā)與線上等價(jià)的重要部分,例如數(shù)據(jù)庫(kù),隊(duì)列系統(tǒng),以及緩存。許多語(yǔ)言都提供了簡(jiǎn)化獲取后端服務(wù)的類庫(kù),例如不同類型服務(wù)的 適配器 。下列表格提供了一些例子。
類型 | 語(yǔ)言 | 類庫(kù) | 適配器 |
---|---|---|---|
數(shù)據(jù)庫(kù) | Ruby/Rails | ActiveRecord | MySQL, PostgreSQL, SQLite |
隊(duì)列 | Python/Django | Celery | RabbitMQ, Beanstalkd, Redis |
緩存 | Ruby/Rails | ActiveSupport::Cache | Memory, filesystem, Memcached |
開(kāi)發(fā)人員有時(shí)會(huì)覺(jué)得在本地環(huán)境中使用輕量的后端服務(wù)具有很強(qiáng)的吸引力,而那些更重量級(jí)的健壯的后端服務(wù)應(yīng)該使用在生產(chǎn)環(huán)境。例如,本地使用 SQLite 線上使用 PostgreSQL;又如本地緩存在進(jìn)程內(nèi)存中而線上存入 Memcached。
12-Factor 應(yīng)用的開(kāi)發(fā)人員應(yīng)該反對(duì)在不同環(huán)境間使用不同的后端服務(wù) ,即使適配器已經(jīng)可以幾乎消除使用上的差異。這是因?yàn)?,不同的后端服?wù)意味著會(huì)突然出現(xiàn)的不兼容,從而導(dǎo)致測(cè)試、預(yù)發(fā)布都正常的代碼在線上出現(xiàn)問(wèn)題。這些錯(cuò)誤會(huì)給持續(xù)部署帶來(lái)阻力。從應(yīng)用程序的生命周期來(lái)看,消除這種阻力需要花費(fèi)很大的代價(jià)。
與此同時(shí),輕量的本地服務(wù)也不像以前那樣引人注目。借助于 Homebrew,apt-get等現(xiàn)代的打包系統(tǒng),諸如Memcached、PostgreSQL、RabbitMQ 等后端服務(wù)的安裝與運(yùn)行也并不復(fù)雜。此外,使用類似 Chef 和 Puppet 的聲明式配置工具,結(jié)合像 Vagrant 這樣輕量的虛擬環(huán)境就可以使得開(kāi)發(fā)人員的本地環(huán)境與線上環(huán)境無(wú)限接近。與同步環(huán)境和持續(xù)部署所帶來(lái)的益處相比,安裝這些系統(tǒng)顯然是值得的。
不同后端服務(wù)的適配器仍然是有用的,因?yàn)樗鼈兛梢允挂浦埠蠖朔?wù)變得簡(jiǎn)單。但應(yīng)用的所有部署,這其中包括開(kāi)發(fā)、預(yù)發(fā)布以及線上環(huán)境,都應(yīng)該使用同一個(gè)后端服務(wù)的相同版本。
11. 日志把日志當(dāng)作事件流
日志 使得應(yīng)用程序運(yùn)行的動(dòng)作變得透明。在基于服務(wù)器的環(huán)境中,日志通常被寫(xiě)在硬盤(pán)的一個(gè)文件里,但這只是一種輸出格式。
日志應(yīng)該是 事件流 的匯總,將所有運(yùn)行中進(jìn)程和后端服務(wù)的輸出流按照時(shí)間順序收集起來(lái)。盡管在回溯問(wèn)題時(shí)可能需要看很多行,日志最原始的格式確實(shí)是一個(gè)事件一行。日志沒(méi)有確定開(kāi)始和結(jié)束,但隨著應(yīng)用在運(yùn)行會(huì)持續(xù)的增加。
12-factor應(yīng)用本身從不考慮存儲(chǔ)自己的輸出流。 不應(yīng)該試圖去寫(xiě)或者管理日志文件。相反,每一個(gè)運(yùn)行的進(jìn)程都會(huì)直接的標(biāo)準(zhǔn)輸出(stdout)事件流。開(kāi)發(fā)環(huán)境中,開(kāi)發(fā)人員可以通過(guò)這些數(shù)據(jù)流,實(shí)時(shí)在終端看到應(yīng)用的活動(dòng)。
在預(yù)發(fā)布或線上部署中,每個(gè)進(jìn)程的輸出流由運(yùn)行環(huán)境截獲,并將其他輸出流整理在一起,然后一并發(fā)送給一個(gè)或多個(gè)最終的處理程序,用于查看或是長(zhǎng)期存檔。這些存檔路徑對(duì)于應(yīng)用來(lái)說(shuō)不可見(jiàn)也不可配置,而是完全交給程序的運(yùn)行環(huán)境管理。類似 Logplex 和 Fluentd 的開(kāi)源工具可以達(dá)到這個(gè)目的。
這些事件流可以輸出至文件,或者在終端實(shí)時(shí)觀察。最重要的,輸出流可以發(fā)送到 Splunk 這樣的日志索引及分析系統(tǒng),或 Hadoop/Hive 這樣的通用數(shù)據(jù)存儲(chǔ)系統(tǒng)。這些系統(tǒng)為查看應(yīng)用的歷史活動(dòng)提供了強(qiáng)大而靈活的功能,包括:
找出過(guò)去一段時(shí)間特殊的事件。
圖形化一個(gè)大規(guī)模的趨勢(shì),比如每分鐘的請(qǐng)求量。
根據(jù)用戶定義的條件實(shí)時(shí)觸發(fā)警報(bào),比如每分鐘的報(bào)錯(cuò)超過(guò)某個(gè)警戒線。
12. 管理進(jìn)程后臺(tái)管理任務(wù)當(dāng)作一次性進(jìn)程運(yùn)行
進(jìn)程構(gòu)成(process formation)是指用來(lái)處理應(yīng)用的常規(guī)業(yè)務(wù)(比如處理 web 請(qǐng)求)的一組進(jìn)程。與此不同,開(kāi)發(fā)人員經(jīng)常希望執(zhí)行一些管理或維護(hù)應(yīng)用的一次性任務(wù),例如:
運(yùn)行數(shù)據(jù)移植(Django 中的 manage.py migrate, Rails 中的 rake db:migrate)。
運(yùn)行一個(gè)控制臺(tái)(也被稱為 REPL shell),來(lái)執(zhí)行一些代碼或是針對(duì)線上數(shù)據(jù)庫(kù)做一些檢查。大多數(shù)語(yǔ)言都通過(guò)解釋器提供了一個(gè) REPL 工具(python 或 perl) ,或是其他命令(Ruby 使用 irb, Rails 使用 rails console)。
運(yùn)行一些提交到代碼倉(cāng)庫(kù)的一次性腳本。
一次性管理進(jìn)程應(yīng)該和正常的 常駐進(jìn)程 使用同樣的環(huán)境。這些管理進(jìn)程和任何其他的進(jìn)程一樣使用相同的 代碼 和 配置 ,基于某個(gè) 發(fā)布版本 運(yùn)行。后臺(tái)管理代碼應(yīng)該隨其他應(yīng)用程序代碼一起發(fā)布,從而避免同步問(wèn)題。
所有進(jìn)程類型應(yīng)該使用同樣的 依賴隔離 技術(shù)。例如,如果Ruby的web進(jìn)程使用了命令 bundle exec thin start ,那么數(shù)據(jù)庫(kù)移植應(yīng)使用 bundle exec rake db:migrate 。同樣的,如果一個(gè) Python 程序使用了 Virtualenv,則需要在運(yùn)行 Tornado Web 服務(wù)器和任何 manage.py 管理進(jìn)程時(shí)引入 bin/python 。
12-factor 尤其青睞那些提供了 REPL shell 的語(yǔ)言,因?yàn)槟菚?huì)讓運(yùn)行一次性腳本變得簡(jiǎn)單。在本地部署中,開(kāi)發(fā)人員直接在命令行使用 shell 命令調(diào)用一次性管理進(jìn)程。在線上部署中,開(kāi)發(fā)人員依舊可以使用ssh或是運(yùn)行環(huán)境提供的其他機(jī)制來(lái)運(yùn)行這樣的進(jìn)程。
文章來(lái)源:1024課堂
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76152.html
摘要:因子是一種構(gòu)建應(yīng)用的方法用聲明式的格式設(shè)置自動(dòng)化,最小化新開(kāi)發(fā)者加入項(xiàng)目的時(shí)間和成本。代碼庫(kù)一份被版本控制追蹤的代碼,多份部署因子應(yīng)用會(huì)一直放在版本控制中,如,或者。每個(gè)分布式系統(tǒng)中的組件是一個(gè)應(yīng)用,每一個(gè)都可以獨(dú)立遵守因子。 原文地址: https://12factor.net/12factor... 介紹 現(xiàn)在軟件通常交付為一個(gè)服務(wù):可以叫web應(yīng)用,或軟件即服務(wù)(SaaS)。1...
摘要:云原生的概念,由來(lái)自的于年首次提出,被一直延續(xù)使用至今。比如,一個(gè)優(yōu)雅的互聯(lián)網(wǎng)應(yīng)用在設(shè)計(jì)過(guò)程中,需要遵循的一些基本原則和云原生有異曲同工之處。 歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 云原生(Cloud Native)的概念,由來(lái)自Pivotal的MattStine于2013年首次提出,被一直延續(xù)使用至今。這個(gè)概念是Matt Stine根據(jù)其多年的架構(gòu)和咨詢經(jīng)驗(yàn)總結(jié)出來(lái)的...
摘要:云幫能解決什么問(wèn)題新一代企業(yè)平臺(tái)讓開(kāi)發(fā)人員輕松地開(kāi)發(fā)部署和運(yùn)維應(yīng)用,讓架構(gòu)師和運(yùn)營(yíng)人員利用熟知和可靠技術(shù)打造一個(gè)受控的運(yùn)行環(huán)境。有助于加速企業(yè)級(jí)應(yīng)用服務(wù)于市場(chǎng),實(shí)現(xiàn)內(nèi)部資源的有效利用。 云幫是什么? 云幫 是一款基于容器技術(shù)的應(yīng)用管理平臺(tái)。社區(qū)版針對(duì)個(gè)人、企業(yè)完全免費(fèi),您可以自由的下載與傳播,但需要遵循我們的社區(qū)版協(xié)議。 云幫從哪里來(lái)? 云幫是 北京好雨科技有限公司 結(jié)合容器技術(shù)整合的...
摘要:該標(biāo)準(zhǔn)主要分為運(yùn)行時(shí)標(biāo)準(zhǔn)和容器鏡像標(biāo)準(zhǔn)。事件注冊(cè)好之后,使用微服務(wù)架構(gòu)實(shí)現(xiàn)事件的監(jiān)聽(tīng)者消費(fèi)者。 大家好,今天非常高興能給大家做一個(gè)關(guān)于Kyma的技術(shù)分享。這個(gè)session的audience主要是針對(duì)使用咱們成都研究院使用Java和nodejs等技術(shù)棧做微服務(wù)開(kāi)發(fā)的同事們。對(duì)于在ABAP netweaver上做SAP傳統(tǒng)開(kāi)發(fā)的同事們來(lái)說(shuō),這個(gè)session可以讓大家開(kāi)闊一下眼界。 這是...
摘要:該標(biāo)準(zhǔn)主要分為運(yùn)行時(shí)標(biāo)準(zhǔn)和容器鏡像標(biāo)準(zhǔn)。事件注冊(cè)好之后,使用微服務(wù)架構(gòu)實(shí)現(xiàn)事件的監(jiān)聽(tīng)者消費(fèi)者。 大家好,今天非常高興能給大家做一個(gè)關(guān)于Kyma的技術(shù)分享。這個(gè)session的audience主要是針對(duì)使用咱們成都研究院使用Java和nodejs等技術(shù)棧做微服務(wù)開(kāi)發(fā)的同事們。對(duì)于在ABAP netweaver上做SAP傳統(tǒng)開(kāi)發(fā)的同事們來(lái)說(shuō),這個(gè)session可以讓大家開(kāi)闊一下眼界。 這是...
閱讀 820·2023-04-25 20:18
閱讀 2104·2021-11-22 13:54
閱讀 2547·2021-09-26 09:55
閱讀 3912·2021-09-22 15:28
閱讀 2982·2021-09-03 10:34
閱讀 1719·2021-07-28 00:15
閱讀 1645·2019-08-30 14:25
閱讀 1289·2019-08-29 17:16