最近接獲一個任務,該任務的目標是替一個即將進入正式部署階段的系統,導入一個 database migration tool,以下是此任務整個思考決策的邏輯以及正式進行時技術上比較值得和大家分享的小細節。
系統背景
資料庫的設計方式,目前常見會有兩種方向,code first 以及 database first。
所謂的 code first 模式,是整個系統在發展初期即以程式碼為管理核心,直接在程式碼內撰寫商業邏輯所使用的 data model 然後再透過 migration 工具轉換為資料庫 schema。相反的,database first 模式則是以直接建立、修改資料庫 schema 的方式,來進行整個開發設計工作。
此任務則是使用 database first 模式。
系統的整體架構部分,此系統是由一個以 C# 撰寫的後端、 angularjs 2 撰寫的前端,以及一個以 python 來實作的人工智慧系統,三者架構而成。
人員則是三個次要系統都有專人來處理開發,整體架構如下:
database migration 是什麼
database migration 有兩種含義,第一種是不同資料庫系統間的系統搬移工作,例如將 Oracle Database 上的資料庫移轉到 Postgresql 上;第二種則是將開發中的資料庫部署到正式的環境上,我們今天和大家分析的這個案例的工作內容屬於第二種。而在規劃這類資料庫的移轉工作時,需要注意幾項重點:
- 如何進行資料庫的套用變更
- 資料庫的變更如何做版本控制
- 不同版本的資料庫如何與其系統程式碼的版本相對應
資料庫的套用變更常見有幾種方式可以選擇,一種是透過撰寫變更 db schema 的 sql 原始碼來完成,第二種則是可以透過 ORM 框架來自動將 data model 轉換為資料庫。
使用撰寫 sql 原始碼來進行資料庫的套用變更是一個最原始的方式,但是相對的,使用這個方式我們資料庫的版本控制以及資料庫與系統程式的對應記錄就需要全部人工處理,而使用 ORM 框架及其 migration 工具,則可以更方便的將上述三點以較輕鬆統一的方式,透過程式碼的管理來處理。
所以如果但就技術點來看,透過ORM框架來執行此項任務,通常會較統一簡單些。
migration 工具的選擇
然而在做決策時,也等同於在尋找最佳化解,而所謂的最佳化解,如果我們拉高決策時的高度,通常也不能只思考技術層面,而這份任務其實也算是蠻經典的,需要考慮更多層次因素的案例,下方則是此任務技術之外需考慮的其他層次問題。
人員配置的考慮
依照我們在系統背景段落的簡單介紹可知,這個系統主要有兩大服務(服務系統與智慧系統),三個子系統(智慧系統./服務前端/服務後端),而且由於這兩大服務在系統的比重大致相同,所以我們資料庫移轉工具選擇,可能有下方三種選項:
- 以 C# 開發者為主要資料庫維護者,導入其生態上的 ORM 工具,例如 Entity Framework Core。
- 以 python 開發者為為主要資料庫維護者,導入其生態上的 ORM 工具,例如 SQLAlchemy Migrate。
- 繼續維持以資料庫原生的設計工具並且搭配各類 migration 工具來進行,
然而雖然在導入階段時,C# 開發者為其主要的資料庫維護者,但是顧慮到此系統隨時有可能轉換其資料庫的主要設計者,也就是保留人員調度的彈性,所以此 migration 導入的方向,則偏好維持以 database-first 的設計方式,而且希望能夠找到足夠簡單、低進入門檻、且最好是初期無購買成本的 open source 方案。
最後還有一個最無法改變的現狀是,本系統會部署在完全與 Internet 隔離的封閉環境。
綜合以上因素,最後 migration 工作的整體運作方案如下:
方案的定案
- 使用 Postgresql 資料庫,並且使用 pgAdmin 做為 db frontend 以及 schema 設計工具。
- 版本定版且開始準備移轉部署時,使用 migra(備註一) 來產生升版的 sql script。
- 以制度制度的定訂來進行版本控制,例如原始碼的版號搭配 sql script 的版號記錄。
- 將所有程式碼以及資料庫版本變更的 script 打包為 Docker image 來簡化部署。
- 部署到正式環境後,獨立的 flyway(備註二) container 將自動協助我們套用資料庫的版更 script。
執行細節
以下幾點是 migration 方案在執行時,一些比較值得注意的小細節,完整的工具使用方式請參考最後備註內的連結。
- migra 是一個很像 diff,可以協助我們產生兩個 postgresql schema 不同處分析的小工具。它最簡單的使用方法如下:
migra postgresql:///a postgresql:///b
像我們此次任務目標是要產生新版本 db schema 升版的 sql script,可以使用如下的指令
//# unsafe 是關閉不安全行為的提示
//# 注意 migration 之前一定要確認是否產生的 script 有沒有問題
migra --unsafe postgresql://{帳號}:{密碼}@{舊版資料庫網址}/{資料庫名稱} postgresql://{帳號}:{密碼}@{新版資料庫網址}/{資料庫名稱} migration.sql
2. flyway 是一個可以幫我們自動偵測且套用 migration script 檔的一套工具,最重要的,它內部也會自行記錄變更記錄,來防止 migration script 的重複套用或者自動套用仍為變更的部分。
flyway 的安裝官方有提供多種方式,此案例使用的是 docker 來簡化安裝,最簡單的安裝指令如下:
docker run --rm flyway/flyway
另外官方 flyway docker 也定義了四個特殊意義的 volume:
- /flyway/conf
這目錄內預設存放 flyway.conf 這個設定檔
- /flyway/drivers
存放 jdbc driver 的目錄。(如果你選用的資料庫 flyway 沒有隨機附上的話)
- /flyway/sql
存放你的 db migration sql script 目錄。(如果你和本案例一樣,選擇以 sql script 做 migration 動作時)
- /flyway/jars
你打算讓 flyway 使用的 jar 檔的目錄。(如果你打算使用 java 來做 migration 動作的話)
本案例的其他如 docker 部署以及版本控制的流程說明等已超過本次預設的分享範圍,如果您有什麼想法很歡迎留言討論。
又或者您有任何資訊顧問或者系統開發整合的需求,也歡迎您主動與我聯絡。
我的相關經歷與聯絡方式可以參考這裡:
我的個人履歷
備註
- migra 工具官方程式碼
- flyway 官方 Docker hub image