云原生概念

云原生概念12個因素

簡介

如今缭付,軟件通常會作為一種服務(wù)來交付拆火,它們被稱為網(wǎng)絡(luò)應(yīng)用程序干毅,或軟件即服務(wù)(SaaS)宜猜。12-Factor 為構(gòu)建如下的 SaaS 應(yīng)用提供了方法論:

  • 使用標(biāo)準(zhǔn)化流程自動配置,從而使新的開發(fā)者花費(fèi)最少的學(xué)習(xí)成本加入這個項目硝逢。
  • 和操作系統(tǒng)之間盡可能的劃清界限姨拥,在各個系統(tǒng)中提供最大的可移植性。
  • 適合部署在現(xiàn)代的云計算平臺渠鸽,從而在服務(wù)器和系統(tǒng)管理方面節(jié)省資源叫乌。
  • 將開發(fā)環(huán)境和生產(chǎn)環(huán)境的差異降至最低,并使用持續(xù)交付實施敏捷開發(fā)徽缚。
  • 可以在工具憨奸、架構(gòu)和開發(fā)流程不發(fā)生明顯變化的前提下實現(xiàn)擴(kuò)展。
  • 這套理論適用于任意語言和后端服務(wù)(數(shù)據(jù)庫凿试、消息隊列排宰、緩存等)開發(fā)的應(yīng)用程序。

云原生應(yīng)用的12要素红省,原文

The Twelve Factors

下面詳細(xì)介紹具體的因素:

I. 基準(zhǔn)代碼

一份基準(zhǔn)代碼(Codebase)额各,多份部署(deploy

12-Factor應(yīng)用(譯者注:應(yīng)該是說一個使用本文概念來設(shè)計的應(yīng)用,下同)通常會使用版本控制系統(tǒng)加以管理吧恃,如Git, Mercurial, Subversion虾啦。一份用來跟蹤代碼所有修訂版本的數(shù)據(jù)庫被稱作 代碼庫(code repository, code repo, repo)。

在類似 SVN 這樣的集中式版本控制系統(tǒng)中痕寓,基準(zhǔn)代碼 就是指控制系統(tǒng)中的這一份代碼庫傲醉;而在 Git 那樣的分布式版本控制系統(tǒng)中,基準(zhǔn)代碼 則是指最上游的那份代碼庫呻率。

一份代碼庫對應(yīng)多份部署

基準(zhǔn)代碼和應(yīng)用之間總是保持一一對應(yīng)的關(guān)系:

  • 一旦有多個基準(zhǔn)代碼硬毕,就不能稱為一個應(yīng)用,而是一個分布式系統(tǒng)礼仗。分布式系統(tǒng)中的每一個組件都是一個應(yīng)用吐咳,每一個應(yīng)用可以分別使用 12-Factor 進(jìn)行開發(fā)逻悠。
  • 多個應(yīng)用共享一份基準(zhǔn)代碼是有悖于 12-Factor 原則的。解決方案是將共享的代碼拆分為獨(dú)立的類庫韭脊,然后使用 依賴管理 策略去加載它們童谒。

盡管每個應(yīng)用只對應(yīng)一份基準(zhǔn)代碼,但可以同時存在多份部署沪羔。每份 部署 相當(dāng)于運(yùn)行了一個應(yīng)用的實例饥伊。通常會有一個生產(chǎn)環(huán)境,一個或多個預(yù)發(fā)布環(huán)境蔫饰。此外琅豆,每個開發(fā)人員都會在自己本地環(huán)境運(yùn)行一個應(yīng)用實例,這些都相當(dāng)于一份部署篓吁。

所有部署的基準(zhǔn)代碼相同茫因,但每份部署可以使用其不同的版本喘鸟。比如呆细,開發(fā)人員可能有一些提交還沒有同步至預(yù)發(fā)布環(huán)境;預(yù)發(fā)布環(huán)境也有一些提交沒有同步至生產(chǎn)環(huán)境麸澜。但它們都共享一份基準(zhǔn)代碼摘盆,我們就認(rèn)為它們只是相同應(yīng)用的不同部署而已翼雀。

II. 依賴

顯式聲明依賴關(guān)系( dependency

大多數(shù)編程語言都會提供一個打包系統(tǒng),用來為各個類庫提供打包服務(wù)孩擂,就像 Perl 的 CPAN 或是 Ruby 的 Rubygems 狼渊。通過打包系統(tǒng)安裝的類庫可以是系統(tǒng)級的(稱之為 “site packages”),或僅供某個應(yīng)用程序使用类垦,部署在相應(yīng)的目錄中(稱之為 “vendoring” 或 “bunding”)狈邑。

12-Factor規(guī)則下的應(yīng)用程序不會隱式依賴系統(tǒng)級的類庫。 它一定通過 依賴清單 蚤认,確切地聲明所有依賴項米苹。此外,在運(yùn)行過程中通過 依賴隔離 工具來確保程序不會調(diào)用系統(tǒng)中存在但清單中未聲明的依賴項砰琢。這一做法會統(tǒng)一應(yīng)用到生產(chǎn)和開發(fā)環(huán)境蘸嘶。

例如, Ruby 的 Bundler 使用 Gemfile 作為依賴項聲明清單陪汽,使用 bundle exec 來進(jìn)行依賴隔離训唱。Python 中則可分別使用兩種工具 – Pip 用作依賴聲明, Virtualenv 用作依賴隔離挚冤。甚至 C 語言也有類似工具况增, Autoconf 用作依賴聲明,靜態(tài)鏈接庫用作依賴隔離训挡。無論用什么工具澳骤,依賴聲明和依賴隔離必須一起使用歧强,否則無法滿足 12-Factor 規(guī)范。

顯式聲明依賴的優(yōu)點(diǎn)之一是為新進(jìn)開發(fā)者簡化了環(huán)境配置流程宴凉。新進(jìn)開發(fā)者可以檢出應(yīng)用程序的基準(zhǔn)代碼誊锭,安裝編程語言環(huán)境和它對應(yīng)的依賴管理工具表悬,只需通過一個 構(gòu)建命令 來安裝所有的依賴項弥锄,即可開始工作。例如蟆沫,Ruby/Bundler 下使用 bundle install籽暇,而 Clojure/Leiningen 則是 lein deps

12-Factor 應(yīng)用同樣不會隱式依賴某些系統(tǒng)工具饭庞,如 ImageMagick 或是curl戒悠。即使這些工具存在于幾乎所有系統(tǒng),但終究無法保證所有未來的系統(tǒng)都能支持應(yīng)用順利運(yùn)行舟山,或是能夠和應(yīng)用兼容绸狐。如果應(yīng)用必須使用到某些系統(tǒng)工具,那么這些工具應(yīng)該被包含在應(yīng)用之中累盗。

III. 配置

在環(huán)境中存儲配置

通常寒矿,應(yīng)用的 配置 在不同 部署 (預(yù)發(fā)布、生產(chǎn)環(huán)境若债、開發(fā)環(huán)境等等)間會有很大差異符相。這其中包括:

  • 數(shù)據(jù)庫,Memcached蠢琳,以及其他 后端服務(wù) 的配置
  • 第三方服務(wù)的證書啊终,如 Amazon S3、Twitter 等
  • 每份部署特有的配置傲须,如域名等

有些應(yīng)用在代碼中使用常量保存配置蓝牲,這與 12-Factor 所要求的代碼和配置嚴(yán)格分離顯然大相徑庭。配置文件在各部署間存在大幅差異泰讽,代碼卻完全一致例衍。

判斷一個應(yīng)用是否正確地將配置排除在代碼之外,一個簡單的方法是看該應(yīng)用的基準(zhǔn)代碼是否可以立刻開源菇绵,而不用擔(dān)心會暴露任何敏感的信息肄渗。

需要指出的是,這里定義的“配置”并包括應(yīng)用的內(nèi)部配置咬最,比如 Rails 的 config/routes.rb翎嫡,或是使用 Spring代碼模塊間的依賴注入關(guān)系 。這類配置在不同部署間不存在差異永乌,所以應(yīng)該寫入代碼惑申。

另外一個解決方法是使用配置文件具伍,但不把它們納入版本控制系統(tǒng),就像 Rails 的 config/database.yml圈驼。這相對于在代碼中使用常量已經(jīng)是長足進(jìn)步人芽,但仍然有缺點(diǎn):總是會不小心將配置文件簽入了代碼庫;配置文件的可能會分散在不同的目錄绩脆,并有著不同的格式萤厅,這讓找出一個地方來統(tǒng)一管理所有配置變的不太現(xiàn)實。更糟的是靴迫,這些格式通常是語言或框架特定的惕味。

12-Factor推薦將應(yīng)用的配置存儲于 環(huán)境變量 中env vars, env )。環(huán)境變量可以非常方便地在不同的部署間做修改玉锌,卻不動一行代碼名挥;與配置文件不同,不小心把它們簽入代碼庫的概率微乎其微主守;與一些傳統(tǒng)的解決配置問題的機(jī)制(比如 Java 的屬性配置文件)相比禀倔,環(huán)境變量與語言和系統(tǒng)無關(guān)。

配置管理的另一個方面是分組参淫。有時應(yīng)用會將配置按照特定部署進(jìn)行分組(或叫做“環(huán)境”)救湖,例如Rails中的 development,test, 和 production 環(huán)境。這種方法無法輕易擴(kuò)展:更多部署意味著更多新的環(huán)境黄刚,例如 stagingqa捎谨。 隨著項目的不斷深入,開發(fā)人員可能還會添加他們自己的環(huán)境憔维,比如 joes-staging 涛救,這將導(dǎo)致各種配置組合的激增,從而給管理部署增加了很多不確定因素业扒。

12-Factor 應(yīng)用中检吆,環(huán)境變量的粒度要足夠小,且相對獨(dú)立程储。它們永遠(yuǎn)也不會組合成一個所謂的“環(huán)境”蹭沛,而是獨(dú)立存在于每個部署之中。當(dāng)應(yīng)用程序不斷擴(kuò)展章鲤,需要更多種類的部署時摊灭,這種配置管理方式能夠做到平滑過渡。

IV. 后端服務(wù)

把后端服務(wù)(backing services)當(dāng)作附加資源

后端服務(wù)是指程序運(yùn)行所需要的通過網(wǎng)絡(luò)調(diào)用的各種服務(wù)败徊,如數(shù)據(jù)庫(MySQL帚呼,CouchDB),消息/隊列系統(tǒng)(RabbitMQBeanstalkd)煤杀,SMTP 郵件發(fā)送服務(wù)(Postfix)眷蜈,以及緩存系統(tǒng)(Memcached)。

類似數(shù)據(jù)庫的后端服務(wù)沈自,通常由部署應(yīng)用程序的系統(tǒng)管理員一起管理酌儒。除了本地服務(wù)之外,應(yīng)用程序有可能使用了第三方發(fā)布和管理的服務(wù)枯途。示例包括 SMTP(例如 Postmark)忌怎,數(shù)據(jù)收集服務(wù)(例如 New RelicLoggly),數(shù)據(jù)存儲服務(wù)(如 Amazon S3)柔袁,以及使用 API 訪問的服務(wù)(例如 Twitter, Google Maps, Last.fm)呆躲。

12-Factor 應(yīng)用不會區(qū)別對待本地或第三方服務(wù)。 對應(yīng)用程序而言捶索,兩種都是附加資源,通過一個 url 或是其他存儲在 配置中的服務(wù)定位/服務(wù)證書來獲取數(shù)據(jù)灰瞻。12-Factor 應(yīng)用的任意 部署 腥例,都應(yīng)該可以在不進(jìn)行任何代碼改動的情況下,將本地 MySQL 數(shù)據(jù)庫換成第三方服務(wù)(例如 Amazon RDS)酝润。類似的燎竖,本地 SMTP 服務(wù)應(yīng)該也可以和第三方 SMTP 服務(wù)(例如 Postmark )互換。上述 2 個例子中要销,僅需修改配置中的資源地址构回。

每個不同的后端服務(wù)是一份 資源 。例如疏咐,一個 MySQL 數(shù)據(jù)庫是一個資源纤掸,兩個 MySQL 數(shù)據(jù)庫(用來數(shù)據(jù)分區(qū))就被當(dāng)作是 2 個不同的資源。12-Factor 應(yīng)用將這些數(shù)據(jù)庫都視作 附加資源 浑塞,這些資源和它們附屬的部署保持松耦合借跪。

一種部署附加4個后端服務(wù)

部署可以按需加載或卸載資源。例如酌壕,如果應(yīng)用的數(shù)據(jù)庫服務(wù)由于硬件問題出現(xiàn)異常掏愁,管理員可以從最近的備份中恢復(fù)一個數(shù)據(jù)庫,卸載當(dāng)前的數(shù)據(jù)庫卵牍,然后加載新的數(shù)據(jù)庫 – 整個過程都不需要修改代碼果港。

V. 構(gòu)建,發(fā)布糊昙,運(yùn)行

嚴(yán)格分離構(gòu)建和運(yùn)行

基準(zhǔn)代碼 轉(zhuǎn)化為一份部署(非開發(fā)環(huán)境)需要以下三個階段:

  • 構(gòu)建階段 是指將代碼倉庫轉(zhuǎn)化為可執(zhí)行包的過程辛掠。構(gòu)建時會使用指定版本的代碼,獲取和打包 依賴項溅蛉,編譯成二進(jìn)制文件和資源文件公浪。
  • 發(fā)布階段 會將構(gòu)建的結(jié)果和當(dāng)前部署所需 配置 相結(jié)合他宛,并能夠立刻在運(yùn)行環(huán)境中投入使用。
  • 運(yùn)行階段 (或者說“運(yùn)行時”)是指針對選定的發(fā)布版本欠气,在執(zhí)行環(huán)境中啟動一系列應(yīng)用程序 進(jìn)程厅各。

代碼被構(gòu)建预柒,然后和配置結(jié)合成為發(fā)布版本

12-facfor 應(yīng)用嚴(yán)格區(qū)分構(gòu)建队塘,發(fā)布,運(yùn)行這三個步驟宜鸯。 舉例來說憔古,直接修改處于運(yùn)行狀態(tài)的代碼是非常不可取的做法,因為這些修改很難再同步回構(gòu)建步驟淋袖。

部署工具通常都提供了發(fā)布管理工具鸿市,最引人注目的功能是退回至較舊的發(fā)布版本。比如即碗, Capistrano 將所有發(fā)布版本都存儲在一個叫 releases 的子目錄中焰情,當(dāng)前的在線版本只需映射至對應(yīng)的目錄即可。該工具的 rollback 命令可以很容易地實現(xiàn)回退版本的功能剥懒。

每一個發(fā)布版本必須對應(yīng)一個唯一的發(fā)布 ID内舟,例如可以使用發(fā)布時的時間戳(2011-04-06-20:32:17),亦或是一個增長的數(shù)字(v100)初橘。發(fā)布的版本就像一本只能追加的賬本验游,一旦發(fā)布就不可修改,任何的變動都應(yīng)該產(chǎn)生一個新的發(fā)布版本保檐。

新的代碼在部署之前耕蝉,需要開發(fā)人員觸發(fā)構(gòu)建操作。但是展东,運(yùn)行階段不一定需要人為觸發(fā)赔硫,而是可以自動進(jìn)行。如服務(wù)器重啟盐肃,或是進(jìn)程管理器重啟了一個崩潰的進(jìn)程爪膊。因此,運(yùn)行階段應(yīng)該保持盡可能少的模塊砸王,這樣假設(shè)半夜發(fā)生系統(tǒng)故障而開發(fā)人員又捉襟見肘也不會引起太大問題推盛。構(gòu)建階段是可以相對復(fù)雜一些的,因為錯誤信息能夠立刻展示在開發(fā)人員面前谦铃,從而得到妥善處理耘成。

VI. 進(jìn)程

以一個或多個無狀態(tài)進(jìn)程運(yùn)行應(yīng)用

運(yùn)行環(huán)境中,應(yīng)用程序通常是以一個和多個 進(jìn)程 運(yùn)行的。

最簡單的場景中瘪菌,代碼是一個獨(dú)立的腳本撒会,運(yùn)行環(huán)境是開發(fā)人員自己的筆記本電腦,進(jìn)程由一條命令行(例如python my_script.py)师妙。另外一個極端情況是诵肛,復(fù)雜的應(yīng)用可能會使用很多 進(jìn)程類型 ,也就是零個或多個進(jìn)程實例默穴。

12-Factor 應(yīng)用的進(jìn)程必須無狀態(tài)且 無共享 怔檩。 任何需要持久化的數(shù)據(jù)都要存儲在 后端服務(wù) 內(nèi),比如數(shù)據(jù)庫蓄诽。

內(nèi)存區(qū)域或磁盤空間可以作為進(jìn)程在做某種事務(wù)型操作時的緩存薛训,例如下載一個很大的文件,對其操作并將結(jié)果寫入數(shù)據(jù)庫的過程仑氛。12-Factor應(yīng)用根本不用考慮這些緩存的內(nèi)容是不是可以保留給之后的請求來使用乙埃,這是因為應(yīng)用啟動了多種類型的進(jìn)程,將來的請求多半會由其他進(jìn)程來服務(wù)调衰。即使在只有一個進(jìn)程的情形下膊爪,先前保存的數(shù)據(jù)(內(nèi)存或文件系統(tǒng)中)也會因為重啟(如代碼部署、配置更改嚎莉、或運(yùn)行環(huán)境將進(jìn)程調(diào)度至另一個物理區(qū)域執(zhí)行)而丟失。

源文件打包工具(Jammit, django-compressor) 使用文件系統(tǒng)來緩存編譯過的源文件沛豌。12-Factor 應(yīng)用更傾向于在 構(gòu)建步驟做此動作——正如 Rails資源管道 趋箩,而不是在運(yùn)行階段。

一些互聯(lián)網(wǎng)系統(tǒng)依賴于 “粘性 session”加派, 這是指將用戶 session 中的數(shù)據(jù)緩存至某進(jìn)程的內(nèi)存中叫确,并將同一用戶的后續(xù)請求路由到同一個進(jìn)程。粘性 session 是 12-Factor 極力反對的芍锦。Session 中的數(shù)據(jù)應(yīng)該保存在諸如 MemcachedRedis 這樣的帶有過期時間的緩存中竹勉。

VII. 端口綁定

通過端口綁定(Port binding)來提供服務(wù)

互聯(lián)網(wǎng)應(yīng)用有時會運(yùn)行于服務(wù)器的容器之中。例如 PHP 經(jīng)常作為 Apache HTTPD 的一個模塊來運(yùn)行娄琉,正如 Java 運(yùn)行于 Tomcat 次乓。

12-Factor 應(yīng)用完全自我加載 而不依賴于任何網(wǎng)絡(luò)服務(wù)器就可以創(chuàng)建一個面向網(wǎng)絡(luò)的服務(wù)∧跛互聯(lián)網(wǎng)應(yīng)用 通過端口綁定來提供服務(wù) 票腰,并監(jiān)聽發(fā)送至該端口的請求。

本地環(huán)境中女气,開發(fā)人員通過類似http://localhost:5000/的地址來訪問服務(wù)杏慰。在線上環(huán)境中,請求統(tǒng)一發(fā)送至公共域名而后路由至綁定了端口的網(wǎng)絡(luò)進(jìn)程。

通常的實現(xiàn)思路是缘滥,將網(wǎng)絡(luò)服務(wù)器類庫通過 依賴聲明 載入應(yīng)用轰胁。例如,Python 的 Tornado, Ruby 的Thin , Java 以及其他基于 JVM 語言的 Jetty朝扼。完全由 用戶端 赃阀,確切的說應(yīng)該是應(yīng)用的代碼,發(fā)起請求吟税。和運(yùn)行環(huán)境約定好綁定的端口即可處理這些請求凹耙。

HTTP 并不是唯一一個可以由端口綁定提供的服務(wù)。其實幾乎所有服務(wù)器軟件都可以通過進(jìn)程綁定端口來等待請求肠仪。例如肖抱,使用 XMPPejabberd , 以及使用 Redis 協(xié)議Redis 异旧。

還要指出的是意述,端口綁定這種方式也意味著一個應(yīng)用可以成為另外一個應(yīng)用的 后端服務(wù) ,調(diào)用方將服務(wù)方提供的相應(yīng) URL 當(dāng)作資源存入 配置 以備將來調(diào)用吮蛹。

VIII. 并發(fā)

通過進(jìn)程模型進(jìn)行擴(kuò)展

任何計算機(jī)程序荤崇,一旦啟動,就會生成一個或多個進(jìn)程潮针∈趸纾互聯(lián)網(wǎng)應(yīng)用采用多種進(jìn)程運(yùn)行方式。例如每篷,PHP 進(jìn)程作為 Apache 的子進(jìn)程存在瓣戚,隨請求按需啟動。Java 進(jìn)程則采取了相反的方式焦读,在程序啟動之初 JVM 就提供了一個超級進(jìn)程儲備了大量的系統(tǒng)資源(CPU 和內(nèi)存)子库,并通過多線程實現(xiàn)內(nèi)部的并發(fā)管理。上述 2 個例子中矗晃,進(jìn)程是開發(fā)人員可以操作的最小單位仑嗅。

擴(kuò)展表現(xiàn)為運(yùn)行中的進(jìn)程仓技,工作多樣性表現(xiàn)為進(jìn)程類型。

在 12-factor 應(yīng)用中吠冤,進(jìn)程是一等公民浑彰。12-Factor 應(yīng)用的進(jìn)程主要借鑒于 unix 守護(hù)進(jìn)程模型 。開發(fā)人員可以運(yùn)用這個模型去設(shè)計應(yīng)用架構(gòu)拯辙,將不同的工作分配給不同的 進(jìn)程類型 郭变。例如颜价,HTTP 請求可以交給 web 進(jìn)程來處理,而常駐的后臺工作則交由 worker 進(jìn)程負(fù)責(zé)诉濒。

這并不包括個別較為特殊的進(jìn)程周伦,例如通過虛擬機(jī)的線程處理并發(fā)的內(nèi)部運(yùn)算,或是使用諸如 EventMachine, Twisted, Node.js 的異步/事件觸發(fā)模型未荒。但一臺獨(dú)立的虛擬機(jī)的擴(kuò)展有瓶頸(垂直擴(kuò)展)专挪,所以應(yīng)用程序必須可以在多臺物理機(jī)器間跨進(jìn)程工作。

上述進(jìn)程模型會在系統(tǒng)急需擴(kuò)展時大放異彩片排。 12-Factor 應(yīng)用的進(jìn)程所具備的無共享寨腔,水平分區(qū)的特性 意味著添加并發(fā)會變得簡單而穩(wěn)妥。這些進(jìn)程的類型以及每個類型中進(jìn)程的數(shù)量就被稱作 進(jìn)程構(gòu)成 率寡。

12-Factor 應(yīng)用的進(jìn)程 不需要守護(hù)進(jìn)程 或是寫入 PID 文件迫卢。相反的,應(yīng)該借助操作系統(tǒng)的進(jìn)程管理器(例如 Upstart 冶共,分布式的進(jìn)程管理云平臺乾蛤,或是類似 Foreman 的工具),來管理 輸出流 捅僵,響應(yīng)崩潰的進(jìn)程家卖,以及處理用戶觸發(fā)的重啟和關(guān)閉超級進(jìn)程的請求。

IX. 易處理

快速啟動和優(yōu)雅終止可最大化健壯性

12-Factor 應(yīng)用的 進(jìn)程 是 易處理(disposable)的庙楚,意思是說它們可以瞬間開啟或停止上荡。 這有利于快速、彈性的伸縮應(yīng)用馒闷,迅速部署變化的 代碼配置 榛臼,穩(wěn)健的部署應(yīng)用。

進(jìn)程應(yīng)當(dāng)追求 最小啟動時間 窜司。 理想狀態(tài)下,進(jìn)程從敲下命令到真正啟動并等待請求的時間應(yīng)該只需很短的時間航揉。更少的啟動時間提供了更敏捷的 發(fā)布 以及擴(kuò)展過程塞祈,此外還增加了健壯性,因為進(jìn)程管理器可以在授權(quán)情形下容易的將進(jìn)程搬到新的物理機(jī)器上帅涂。

進(jìn)程 一旦接收 終止信號(SIGTERM) 就會優(yōu)雅的終止 议薪。就網(wǎng)絡(luò)進(jìn)程而言,優(yōu)雅終止是指停止監(jiān)聽服務(wù)的端口媳友,即拒絕所有新的請求斯议,并繼續(xù)執(zhí)行當(dāng)前已接收的請求,然后退出醇锚。此類型的進(jìn)程所隱含的要求是HTTP請求大多都很短(不會超過幾秒鐘)哼御,而在長時間輪詢中坯临,客戶端在丟失連接后應(yīng)該馬上嘗試重連。

對于 worker 進(jìn)程來說恋昼,優(yōu)雅終止是指將當(dāng)前任務(wù)退回隊列看靠。例如,RabbitMQ 中液肌,worker 可以發(fā)送一個NACK信號挟炬。 Beanstalkd 中,任務(wù)終止并退回隊列會在worker斷開時自動觸發(fā)嗦哆。有鎖機(jī)制的系統(tǒng)諸如 Delayed Job 則需要確定釋放了系統(tǒng)資源谤祖。此類型的進(jìn)程所隱含的要求是,任務(wù)都應(yīng)該 可重復(fù)執(zhí)行 老速, 這主要由將結(jié)果包裝進(jìn)事務(wù)或是使重復(fù)操作 冪等 來實現(xiàn)粥喜。

進(jìn)程還應(yīng)當(dāng)在面對突然死亡時保持健壯,例如底層硬件故障烁峭。雖然這種情況比起優(yōu)雅終止來說少之又少容客,但終究有可能發(fā)生。一種推薦的方式是使用一個健壯的后端隊列约郁,例如 Beanstalkd 缩挑,它可以在客戶端斷開或超時后自動退回任務(wù)。無論如何鬓梅,12-Factor 應(yīng)用都應(yīng)該可以設(shè)計能夠應(yīng)對意外的供置、不優(yōu)雅的終結(jié)。Crash-only design 將這種概念轉(zhuǎn)化為 合乎邏輯的理論绽快。

X. 開發(fā)環(huán)境與線上環(huán)境等價

盡可能的保持開發(fā)芥丧,預(yù)發(fā)布,線上環(huán)境相同

從以往經(jīng)驗來看坊罢,開發(fā)環(huán)境(即開發(fā)人員的本地 部署)和線上環(huán)境(外部用戶訪問的真實部署)之間存在著很多差異续担。這些差異表現(xiàn)在以下三個方面:

  • 時間差異: 開發(fā)人員正在編寫的代碼可能需要幾天,幾周活孩,甚至幾個月才會上線物遇。
  • 人員差異: 開發(fā)人員編寫代碼,運(yùn)維人員部署代碼憾儒。
  • 工具差異: 開發(fā)人員或許使用 Nginx询兴,SQLite,OS X起趾,而線上環(huán)境使用 Apache诗舰,MySQL 以及 Linux。

12-Factor 應(yīng)用想要做到 持續(xù)部署 就必須縮小本地與線上差異训裆。 再回頭看上面所描述的三個差異:

  • 縮小時間差異:開發(fā)人員可以幾小時眶根,甚至幾分鐘就部署代碼蜀铲。
  • 縮小人員差異:開發(fā)人員不只要編寫代碼,更應(yīng)該密切參與部署過程以及代碼在線上的表現(xiàn)汛闸。
  • 縮小工具差異:盡量保證開發(fā)環(huán)境以及線上環(huán)境的一致性蝙茶。

將上述總結(jié)變?yōu)橐粋€表格如下:

傳統(tǒng)應(yīng)用 12-Factor 應(yīng)用
每次部署間隔 數(shù)周 幾小時
開發(fā)人員 vs 運(yùn)維人員 不同的人 相同的人
開發(fā)環(huán)境 vs 線上環(huán)境 不同 盡量接近

后端服務(wù) 是保持開發(fā)與線上等價的重要部分,例如數(shù)據(jù)庫诸老,隊列系統(tǒng)隆夯,以及緩存。許多語言都提供了簡化獲取后端服務(wù)的類庫别伏,例如不同類型服務(wù)的 適配器 蹄衷。下列表格提供了一些例子。

類型 語言 類庫 適配器
數(shù)據(jù)庫 Ruby/Rails ActiveRecord MySQL, PostgreSQL, SQLite
隊列 Python/Django Celery RabbitMQ, Beanstalkd, Redis
緩存 Ruby/Rails ActiveSupport::Cache Memory, filesystem, Memcached

開發(fā)人員有時會覺得在本地環(huán)境中使用輕量的后端服務(wù)具有很強(qiáng)的吸引力厘肮,而那些更重量級的健壯的后端服務(wù)應(yīng)該使用在生產(chǎn)環(huán)境愧口。例如,本地使用 SQLite 線上使用 PostgreSQL类茂;又如本地緩存在進(jìn)程內(nèi)存中而線上存入 Memcached耍属。

12-Factor 應(yīng)用的開發(fā)人員應(yīng)該反對在不同環(huán)境間使用不同的后端服務(wù) ,即使適配器已經(jīng)可以幾乎消除使用上的差異巩检。這是因為厚骗,不同的后端服務(wù)意味著會突然出現(xiàn)的不兼容,從而導(dǎo)致測試兢哭、預(yù)發(fā)布都正常的代碼在線上出現(xiàn)問題领舰。這些錯誤會給持續(xù)部署帶來阻力。從應(yīng)用程序的生命周期來看迟螺,消除這種阻力需要花費(fèi)很大的代價冲秽。

與此同時,輕量的本地服務(wù)也不像以前那樣引人注目矩父。借助于Homebrew锉桑,apt-get等現(xiàn)代的打包系統(tǒng),諸如Memcached窍株、PostgreSQL刨仑、RabbitMQ 等后端服務(wù)的安裝與運(yùn)行也并不復(fù)雜。此外夹姥,使用類似 ChefPuppet 的聲明式配置工具,結(jié)合像 Vagrant 這樣輕量的虛擬環(huán)境就可以使得開發(fā)人員的本地環(huán)境與線上環(huán)境無限接近辙诞。與同步環(huán)境和持續(xù)部署所帶來的益處相比辙售,安裝這些系統(tǒng)顯然是值得的。

不同后端服務(wù)的適配器仍然是有用的飞涂,因為它們可以使移植后端服務(wù)變得簡單旦部。但應(yīng)用的所有部署祈搜,這其中包括開發(fā)、預(yù)發(fā)布以及線上環(huán)境士八,都應(yīng)該使用同一個后端服務(wù)的相同版本容燕。

XI. 日志

把日志當(dāng)作事件流

日志 使得應(yīng)用程序運(yùn)行的動作變得透明。在基于服務(wù)器的環(huán)境中婚度,日志通常被寫在硬盤的一個文件里蘸秘,但這只是一種輸出格式。

日志應(yīng)該是 事件流 的匯總蝗茁,將所有運(yùn)行中進(jìn)程和后端服務(wù)的輸出流按照時間順序收集起來醋虏。盡管在回溯問題時可能需要看很多行,日志最原始的格式確實是一個事件一行哮翘。日志沒有確定開始和結(jié)束颈嚼,但隨著應(yīng)用在運(yùn)行會持續(xù)的增加。

12-factor應(yīng)用本身從不考慮存儲自己的輸出流饭寺。 不應(yīng)該試圖去寫或者管理日志文件阻课。相反,每一個運(yùn)行的進(jìn)程都會直接的標(biāo)準(zhǔn)輸出(stdout)事件流艰匙。開發(fā)環(huán)境中限煞,開發(fā)人員可以通過這些數(shù)據(jù)流,實時在終端看到應(yīng)用的活動旬薯。

在預(yù)發(fā)布或線上部署中晰骑,每個進(jìn)程的輸出流由運(yùn)行環(huán)境截獲,并將其他輸出流整理在一起绊序,然后一并發(fā)送給一個或多個最終的處理程序硕舆,用于查看或是長期存檔。這些存檔路徑對于應(yīng)用來說不可見也不可配置骤公,而是完全交給程序的運(yùn)行環(huán)境管理抚官。類似 LogplexFluent 的開源工具可以達(dá)到這個目的。

這些事件流可以輸出至文件阶捆,或者在終端實時觀察凌节。最重要的,輸出流可以發(fā)送到 Splunk 這樣的日志索引及分析系統(tǒng)洒试,或 Hadoop/Hive 這樣的通用數(shù)據(jù)存儲系統(tǒng)倍奢。這些系統(tǒng)為查看應(yīng)用的歷史活動提供了強(qiáng)大而靈活的功能,包括:

  • 找出過去一段時間特殊的事件垒棋。
  • 圖形化一個大規(guī)模的趨勢卒煞,比如每分鐘的請求量。
  • 根據(jù)用戶定義的條件實時觸發(fā)警報叼架,比如每分鐘的報錯超過某個警戒線畔裕。

XII. 管理進(jìn)程

后臺管理任務(wù)當(dāng)作一次性進(jìn)程運(yùn)行

進(jìn)程構(gòu)成(process formation)是指用來處理應(yīng)用的常規(guī)業(yè)務(wù)(比如處理 web 請求)的一組進(jìn)程衣撬。與此不同,開發(fā)人員經(jīng)常希望執(zhí)行一些管理或維護(hù)應(yīng)用的一次性任務(wù)扮饶,例如:

  • 運(yùn)行數(shù)據(jù)移植(Django 中的 manage.py migrate, Rails 中的 rake db:migrate)具练。
  • 運(yùn)行一個控制臺(也被稱為 REPL shell)婉商,來執(zhí)行一些代碼或是針對線上數(shù)據(jù)庫做一些檢查棍鳖。大多數(shù)語言都通過解釋器提供了一個 REPL 工具(pythonperl) ,或是其他命令(Ruby 使用 irb, Rails 使用 rails console)休傍。
  • 運(yùn)行一些提交到代碼倉庫的一次性腳本毫蚓。

一次性管理進(jìn)程應(yīng)該和正常的 常駐進(jìn)程 使用同樣的環(huán)境占键。這些管理進(jìn)程和任何其他的進(jìn)程一樣使用相同的 代碼配置 ,基于某個 發(fā)布版本 運(yùn)行元潘。后臺管理代碼應(yīng)該隨其他應(yīng)用程序代碼一起發(fā)布畔乙,從而避免同步問題。

所有進(jìn)程類型應(yīng)該使用同樣的 依賴隔離 技術(shù)翩概。例如牲距,如果Ruby的web進(jìn)程使用了命令 bundle exec thin start ,那么數(shù)據(jù)庫移植應(yīng)使用 bundle exec rake db:migrate 钥庇。同樣的牍鞠,如果一個 Python 程序使用了 Virtualenv,則需要在運(yùn)行 Tornado Web 服務(wù)器和任何 manage.py 管理進(jìn)程時引入 bin/python评姨。

12-factor 尤其青睞那些提供了 REPL shell 的語言难述,因為那會讓運(yùn)行一次性腳本變得簡單。在本地部署中吐句,開發(fā)人員直接在命令行使用 shell 命令調(diào)用一次性管理進(jìn)程胁后。在線上部署中,開發(fā)人員依舊可以使用ssh或是運(yùn)行環(huán)境提供的其他機(jī)制來運(yùn)行這樣的進(jìn)程嗦枢。

以上的規(guī)則實際的應(yīng)用與落地:


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攀芯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子文虏,更是在濱河造成了極大的恐慌侣诺,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氧秘,死亡現(xiàn)場離奇詭異年鸳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丸相,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門阻星,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事妥箕。” “怎么了更舞?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵畦幢,是天一觀的道長。 經(jīng)常有香客問我缆蝉,道長宇葱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任刊头,我火速辦了婚禮黍瞧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘原杂。我一直安慰自己印颤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布穿肄。 她就那樣靜靜地躺著年局,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咸产。 梳的紋絲不亂的頭發(fā)上矢否,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機(jī)與錄音脑溢,去河邊找鬼僵朗。 笑死,一個胖子當(dāng)著我的面吹牛屑彻,可吹牛的內(nèi)容都是我干的验庙。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼酱酬,長吁一口氣:“原來是場噩夢啊……” “哼壶谒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起膳沽,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤汗菜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挑社,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陨界,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年痛阻,在試婚紗的時候發(fā)現(xiàn)自己被綠了菌瘪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俏扩,靈堂內(nèi)的尸體忽然破棺而出糜工,到底是詐尸還是另有隱情,我是刑警寧澤录淡,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布捌木,位于F島的核電站,受9級特大地震影響嫉戚,放射性物質(zhì)發(fā)生泄漏刨裆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一彬檀、第九天 我趴在偏房一處隱蔽的房頂上張望帆啃。 院中可真熱鬧,春花似錦窍帝、人聲如沸努潘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慈俯。三九已至,卻和暖如春拥峦,著一層夾襖步出監(jiān)牢的瞬間贴膘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工略号, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刑峡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓玄柠,卻偏偏與公主長得像突梦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子羽利,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理宫患,服務(wù)發(fā)現(xiàn),斷路器这弧,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,799評論 25 707
  • 我們都聽過這樣一個故事:馬蹄踏過紫藤蘿娃闲,它把香氣留在了馬蹄上。 又有那膾炙人口的成語:贈人玫瑰匾浪,手有余香皇帮。 美國《...
    星塵下的貓咪閱讀 232評論 1 1
  • 日出破曉,一只麻雀出生了蛋辈。 聞鷹擊長空属拾,枯木高穴獨(dú)號。 抖擻雙翼向天奔,突破長空把鷹渺渐白。 驀然回首尊浓,雙腳并未離寸巢...
    空山喜雨閱讀 155評論 0 1
  • “螞蟻螞蟻,你在這干什么按垦堋眠砾?”小麻雀問螞蟻。 “噓托酸,你小點(diǎn)聲,一會大象就要走過來了柒巫,我要把它絆倒励堡。”螞蟻把身體藏了...
    阿布_771f閱讀 3,511評論 0 0