知識閱讀 - 如何沒有 Downtime 的更新資料庫樣式

在更新資料庫樣式的時候,會不會影響系統造成 Downtime,最重要的就是你的操作是否可以向下相容。 所以區分成兩個:向下相容、不向下相容

Backward-Compatible Operations

  • Add a table or a view:新加上 Table 和 View 對於舊的系統並不會有影響,所以不需要做額外的操作。但是要注意,不要在操作還沒完成就部署上新系統,那就會造成問題了。
  • Add a column:添加欄位,也沒有舊系統沒有影響。但是要注意是否有 NOT NULL constraint,因為 NOT NULL constraint,因為過去的資料就都會是空值,如果有預設值的話就還好處理。如果沒有預設值的話,就建議用以下三種方式來添加 constraint
    1. 新增沒有 constraint 的欄位
    2. 執行 database script 將其初始值填入欄位
    3. 加上 NOT NULL constraint
  • Remove a column that’s not used by the old and the new version of your application:此操作因為系統都不在使用該欄位,所以也是可以直接處理(當然前提是確定真的不需要了)
  • Remove constraints:不影響系統服務的操作

Backward-Incompatible Operations

針對這些操作,通常就是造成無法順利無 Downtime 的更新。會建議使用一些熱門的工具:Flyway 和 Liquibase。

  • Rename a column, a table or a view:今天欄位、資料表和視圖的改名,看起來很簡單。但是卻是最常見造成無法向下相容的問題,主要發生在 Rolling update 的時候。因為同時舊系統還在使用舊的地方,新系統又上線,怎麼在更新過程中兩邊的資料可以是同步的。
    • Option 1: Sync with database triggers:如果你的資料庫支援 trigger 的話,那這個操作就比較好處理了。
      1. 新增新欄位並且將舊資料複製過去,新增 Trigger 將新進入的資料同步到新欄位
      2. 執行 Rolling update
      3. 刪除舊資料(Column、Table、View)和 Trigger
    • Option 2: Sync programmatically:如果你的資料庫不支援 Trigger 的話,那就會建議將系統進入 Read-only 模式,不然可能會在更新過程丟失一些資料。
      1. 新增新欄位並且將舊資料複製過去
      2. 確定新系統會從舊欄位讀取和同時寫入到舊欄位和新欄位 - 先稱其為 new1。因為此時舊系統依舊可以寫入新資料或更新舊資料,所以要確定 new1 要可以處理新舊欄位之後就執行 Rolling update
      3. 確保 new1 都更新後,就可以在更新一版只有處理新欄位的系統 new2
      4. 刪除舊資料欄位
  • Change the data type of a column:基本上的操作跟 Rename 一樣,唯一的差別是需要更改資料型態
  • Remove a column or table or view that’s still used by the old version of your application:需要更新系統才有辦法操作刪除

Reference