10 年後,再審視 Heroku 發佈的十二要素應用

你經常會聽說軟件開發和部署將變得更美好。這一趨勢的當前輪迴是 Heroku。不要誤會我的意思,Heroku 令人難以置信,它帶來了一種編寫 Web 應用和部署分佈式系統的新方法。他們肯定做對了很多。即使 10 年之後的今天,我們仍在努力實現同樣的開發便利性。

Heroku 的聯合創始人 Adam Wiggins 有一篇著名文章, 12 因素應用方法,它總結了許多有用並且我確信使得構建 Heroku 更有趣和有益的想法。

在這篇文章中,我想回顧一下 Adam 所涵蓋的 12 個因素中的每一個,它們是如何演變的,我們今天可以從它們身上學到什麼,以及它們如何改變了過去的狀態。

1 代碼庫

這個建議剛提出時,類似 GitHub 這樣的東西纔剛剛起步,代碼版本控制也並不常見。這可能看起來很殘酷,但這是事實。我記得剛開始時必須處理 Subversion 的問題。

代碼庫與其應用之間的關係顯著增長,包括從測試到部署的所有內容。然而,仍然存在高度爭議的一點是是否需要單倉。

如果有多個代碼庫,它就不是一個應用——它是一個分佈式系統。分佈式系統中的每個組件都是一個應用,每個組件都可以單獨遵守十二因素。

尤其是在以微服務爲中心的世界中,維護多個代碼庫所需的所有開銷都可能令人厭煩。

2 依賴項

我不確定你們中有多少人曾經在 Ansible 和 Puppet 等軟件可用之前處理過依賴系統。儘管如此,操作系統和各種版本的庫之間的特殊性絕對是一場噩夢。

這個因素抓住了關鍵,最終在很大程度上使得依賴可以被視爲一個已解決的問題。

通過引入各種清單文件,我們的應用可以以一致和準確的方式重新構建。此外,像 Bazel 這樣的構建工具進一步包含了許多強大的工具,供構建工程師創建可重現的版本。更不用說我們現在可以發佈簡單的鏡像,這些鏡像嚴格打包了我們需要在生產中部署的內容(稍後會詳細介紹)。

3 配置

這個因素保持不變,但在確保配置與應用代碼分開時需要考慮一些事項。隨着工具更加成熟,這些選擇正越來越多地轉向諸如 Vault 或服務發現系統之類的工具,這些工具在環境感知系統中管理和存儲配置。

4 後端服務

最初,這個因素主要是圍繞單個系統的組件編寫的,主要集中在數據庫等。儘管它沒有提到本地系統和第三方系統之間的任何區別,但在構建一個其他人將利用 “API 優先” 方法作爲平臺的系統時,這一點已被進一步採用。這種方法非常成功,以至於許多團隊開始採用這種策略便於在負責系統不同區域的團隊之間創建一份清晰的合同。隨着這些系統的發展,這最終會提高靈活性和效率。

5 構建、發佈、運行

對於當今正在開發的任何現代服務而言,這個因素幾乎是相同的。我想指出的是,我認爲不會經常發生的事情是構建和發佈步驟之間的分離,這對於進行合理的部署和回滾流程至關重要。

隨着代碼的合併和測試,每個構建結果鏡像(或二進制文件)都應該通過某種機制存儲,以便後續發佈和部署。這種分離允許更簡單且不易出錯的開發週期。

在更小規模或更早的開發週期中,這可能沒有必要,因爲這些更改與應用及其基礎架構的開發緊密相關。GitOps 是一個進一步討論許多概念的領域。

6 進程

正如所寫的,這個因素在 REST API 的世界中仍然很重要。在 Web 服務的情況下,這意味着我們永遠不應該在請求之間在內存中保留域狀態。相反,這些應用之間的所有通信都應該保持無狀態或存儲在另一個支持系統中。

所有系統面臨的擴展問題都是狀態的管理和存儲。這在 SaaS 模型中進行橫向擴展非常重要。這也與限界上下文的概念相得益彰,它確保每個系統都應該管理其存儲層,如果其他系統需要訪問該數據,它應該通過一個設計良好的 API 來實現。

7 端口綁定

一段時間以來,這個因素一直是標準做法,這裏沒有任何有意義的變化。此外,許多容器化標準、代理和負載均衡器都強制執行了這一因素。

主要思想是每個應用都應該有一個特定的端口映射。

通常,所選端口可以在所述端口上傳遞預期的信息。這隻能通過容器到主機的網絡映射來實現。端口綁定的概念是,使用統一的端口號是向網絡公開進程的最佳方法。例如,在 HTTP 下運行時,端口 80 是 Web 服務器的默認端口。同樣,在 SSH 下運行時,端口 22 是默認的。

8 併發

併發因素是應用應該根據其目的組織每個進程。工程師可以通過將這些進程分成不同的組來實現這一點。這個因素總結了水平擴展,以及領域新加入者,例如 FaaS 等的各種屬性。例如,我們知道對於特定工作負載,大量機器比幾臺大型機器更有能力。

另一個關鍵要點是應用應該圍繞它們的工作負載執行這種併發性,並且具有競爭工作負載的應用應該分開並獨立擴展。

9 可處置性

在系統需要它之前,我經常看到這個因素被忽略了。啓動檢查對於確保系統正常運行至關重要。運行狀況檢查可確保系統繼續處於此狀態或將自身從輪換中移除。

我在關機過程中看到了同樣的疏忽;它相對複雜且很難做正確,再加上古老的觀點 “如果我們乾淨地做有什麼關係?它不會存活這個進程”。好吧,如果在分佈式系統中沒有正確結束,它可能會對依賴它的其他系統產生級聯影響。此外,如果忽視可能會導致系統可靠性下降,並最終影響客戶。

10 開發 / 生產環境等價

正如我所看到的,隨着我們將更多的基礎設施轉移到供應商鎖定的私有云中,這個因素正在變得更糟。當然,從操作的角度來看,像 Docker 和 Kubernetes 這樣的東西讓我們在這兩種環境中運行我們的系統是等效的,但是當我們查看事實真相時,情況幾乎就不是這樣了。

那些不得不調試可在生產環境中重現的問題的人都可以讓你重現這種噩夢般的情況。不幸的是,私有云提供商很少有動力公開他們的技術,事實上(作爲一種服務),它是最好的賣點之一。

此外,Sisyphean 本身也在掙扎着試圖將所有這些系統安裝在所有開發人員都可以使用的機器上。

11 日誌

這個因素已經成爲成爲主業,儘管 Adam 寫這個因素的方式讓它看起來像是別人的問題。這主要已經從應用的輸出(日誌)變成了應用絕對應該關注的事情。

隨着應用的發展,他們將需要跟蹤日誌、指標和路徑,以便在其發展過程中真正瞭解和維護他們的系統。因此,這個因素可能需要更新以反映應用應該是可觀察的,而無需修改所述系統。

12 管理進程

任何改變應用狀態的東西都應該以與應用本身等同的進程進行管理。應該對它們進行測試和審查。當你在槍下時,很難確保這一點,而且非常容易做到。我相信這可以解釋數量驚人的停電和令人不舒服的停工。

具有可用框架的更成熟的語言提供了創建和測試這些管理進程的簡單機制。但是,如果你使用的語言不提供這些,則必須創建它們。這包括遷移進程、依賴關係管理,甚至是用於清理和管理的一次性過程。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6S8co-7dBegsnK-jMzLZDw