只有累積,沒有奇蹟

2020年9月9日 星期三

[Architecture] The 12 factor App 筆記

前言
最近在與同事一起規劃新系統的架構,在整理相關文件時想起參加前公司 Techday 由新加坡同事提起的 The Twelve-Factor App 方法論,提出此方法論的作者參與了超過一百個專案開發與部署,並透過 Heroku 平台見證了數十萬個應用程式的開發運作以及擴展的過程,整理了在 SaaS (Software as a Service) 開發時需要理想的實踐標準,方法論主要內容如下

Use declarative formats for setup automation, to minimize time and cost for new developers joining the project;
Have a clean contract with the underlying operating system, offering maximum portability between execution environments;
Are suitable for deployment on modern cloud platforms, obviating the need for servers and systems administration;
Minimize divergence between development and production, enabling continuous deployment for maximum agility;
And can scale up without significant changes to tooling, architecture, or development practices.
其中提到此方法論是不限定語言與後端服務開發的應用程式,因此這篇文章就來介紹關於 12 個方法論的一些重點項目,若有理解錯誤或是異常的地方歡迎隨時提出討論。

介紹
【文不如圖,圖不如表】再多的文字都比不上一張清晰的圖讓人容易了解,因此在一開始先 PO 出在網路上找到有關 12 factors 的小抄表,讓有興趣的朋友對於整個方法論有更清楚的 overview
接著,再來逐一介紹每個方法論的內容 備註 : Puppeteer 是 Playwright 的前身,其 API 與核心概念都很相似。

Codebase
一份基准代码(Codebase),多份部署(Deploy)
  • 使用版本控制系統來控管代碼,像是 Git、Subversion 等常見的版本控管工具
  • 一份用來追蹤代碼所有異動版本的數據庫被稱為 代碼庫 (code repository, code repo, repo)
  • 基準代碼指的就是這一份代碼庫,如果是 Git 分布式版本控制系統,基準代碼就是最上游的代碼庫。
  • 基準代碼與應用(Aplication) 是保持一對一的關係。
  • 在不同的環境會對應到同一份代碼庫,每個部署可能會使用到不同的版本

Dependencies
清楚的定義依賴關係(Dependency)
  • 應用程序不會隱式依賴系統級的類別庫,透過依賴清單清楚定義所有依賴項目
  • 透過依賴隔離工具來確保不會調用不存在的項目,此做法在 Production 與測試環境皆是如此
  • 為新的開發者簡化環境配置的流程,只需要透過建構指令 (build command) 即可安裝其依賴項目,即可開始工作
  • 舉例來說,在 Ruby/Bundler 就是透過 bundle install

Config
將 Config 定義在環境變數中
  • 代碼(Code)與配置(Config)嚴格分離
  • Config 在不同環境分別各自定義,代碼是一致的
  • 推薦將應用程式的配置定義在環境變數中 (Env vars, env)
  • 環境變數可以很方便的在不同環境修改,不用異動到代碼 (Code)與語言也無關
  • 舉例來說,與第三方介接時所需要的 Token,在與 DB 建立連線時需要的連線字串 Connection string

Backing Service
將後端服務(Backing Service)視為附加資源

  • 應用程式(Application)不會區別本地或是第三方服務
  • 對它來說兩者都是附加的資源,透過某個 url 或配置的服務定位 (locator/credentials) 來取得數據
  • 也可以在不用異動代碼的情況下,將本地 MySql 資料庫換成第三方服務(ex:Amaxon RDS)
  • 每個不同的後端服務都是一份資源(resource),這些資源與其附屬的部署保持鬆耦合(loose coupling)的關係

Build, release, run
嚴格分離建構與運行

  • 嚴格區分構建,發布,運行這三個步驟
  • 直接修改運行中的代碼是非常不可取的行為
  • 每次發布都要對應到唯一個發布ID,例如可以使用發布時的時間戳記 2020-09-10 22:33:44
  • 發布的版本一但發布就不能修改,任何代碼的變動都應該產新的版本
  • 備註 : 小弟公司是使用 Git commit 的 hash 值,方便盤查

Processes
使用一個或多個無狀態的 Process 運行
  • Application 的 Process 應該是無狀態且不能共享的(share-nothing),
  • 任何像是需要持久化的數據都要存在後端服務中,像是數據庫
  • 一些互聯網系統過度依賴於 session (sticky sessions),這在 12-Factor 是極力反對的,
  • Session 數據應該保持在像是 Memcached 或是 Redis 有帶過期時間的緩存中

Port binding
通過端口綁定( Port binding )來提供服務
  • 通過端口綁定(Port binding)來提供服務,並監聽發送至該 Port 的請求
  • 不僅限於 HTTP 服務

Concurrency
使用 Process Model 進行 Scale Out

  • Processes are a first class citizen
  • 開發人員可以運用 Unix process model for running servuce daemons,將不同的工作分配給不同的類型 (Process Type)
  • 舉例來說,HTTP 請求可以交給 Web 進城來處理;常駐的後台則交由 worker 來負責
  • Process 應該 stateless 和無分享的,方便進行擴充

Disposability
通過快速啟動和優雅關機,實現穩健性最大化
  • Processes 是可以瞬間開啟或是停止,易處理的 (disposable)
  • 追求最小啟動時間,理想狀態當輸入啟動指令到等待請求應該只需要很短的時間
  • 更快的啟動時間提供敏捷的發布與擴展,容易將 Process 容易的搬移到新的物理機器上
  • 收到終止信號(SIGTERM)就會優雅的終止,也就是停止監聽服務的 Port 拒絕所有的請求然後退出

Dev/prod parity
盡可能保持開發/測試/正式環境相同
  • 想做到持續部署應該縮小本地與線上的差異
  • 縮小時間差異:開發人員可以幾小時,甚至幾分鐘就部署代碼。
  • 縮小人員差異:開發人員不只要編寫代碼,更應該密切參與部署過程以及代碼在線上的表現。
  • 縮小工具差異:盡量保證開發環境以及線上環境的一致性。
  • 開發人員應該反對在不同環境使用不同的後端服務,降低使用上的差異以及突然出現的不相容問題

Logs
把日志當作事件流
  • 應用程式不應該煩惱 logs 存放位置,統一使用 stdout 直接輸出
  • 這些事件流可以輸出至文件,或是在終端實現觀察的
  • 輸出流可以發送到 Splunk 諸如此類的日誌索引及分析系統

Admin processes
後台管理任務當作一次性運行
  • 開發人員有可能會執行一次性的管理或是維護的一次性任務
  • 執行資料轉換
  • 執行控制台(REPL Shell)
  • 一次性管理程序應該使用相同的環境,並使用相同的程式碼跟配置


感想
以上針對 The 12 Factor 做了基本簡單的介紹,但在實務上某些部份可能實現的難度較高,舉例來說像是 Dev/Prod 環境要一致的要求,現實上可能會遇的問題是開發環境的 Server 已經包含 feature A,但在未驗證完全的情況下可能會也不會更新到正式環境;每一個原則都是開發與運維同仁在開發時需要注意的部分,日後有機會設計新架構或是既有系統調整時可以做為參考的準則之一,以上如果有不清楚的地方歡迎一起討論,謝謝 !

參考
12 factor

0 意見:

張貼留言

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com