Skip to content

變更回滾與資料復原

核心原則:Argus 不提供「按一個按鈕就把 prod DB 倒帶」功能。

所有「回滾」都走新開一份 Plan:原始變更通過審批,回滾也必須通過審批。這條設計守住「所有變更走 Plan」核心承諾,避免 audit 軌跡被繞道。

但 Argus 提供兩個機制讓你寫倒帶 Plan 時不用憑記憶猜:DML 變更前自動備份影響的 row(PriorBackup)、DDL 變更前後自動拍 schema snapshot(sync_history)。

DML 變更:PriorBackup(執行前抓 row)

怎麼啟用

Plan 設定時開 enablePriorBackup(Plan 詳細頁右側設定 → Prior backup)。

預設 關閉 — 你必須主動勾選才會備份。

怎麼運作

備份去哪了

Argus 在你的 instance 內自動建立一個 sidecar database 叫 bbdataarchive(Oracle 是大寫 BBDATAARCHIVE),所有 PriorBackup 都寫在這。

每張被影響的原表,會在 backup DB 內生成一張 _<random>_<source_table>_<timestamp> 對應表,只放這次 UPDATE/DELETE 影響的 row(不是整表複製)。

怎麼知道備份了什麼

進 issue 詳細頁 → Task Run → 看 TaskRunLog,有兩條:

  • PRIOR_BACKUP_START — 備份開始時間
  • PRIOR_BACKUP_END — 備份結束時間 + PriorBackupDetail,列出每張 source table 對應的 target table 名稱

也可以直接 SQL Editor 連 bbdataarchive database,看裡面的表清單。

支援的 engine

EnginePriorBackup
MySQL
TiDB
MSSQL
PostgreSQL
Oracle✅(backup DB 命名為 BBDATAARCHIVE
Snowflake
Cassandra
SQLite
MongoDB
Spanner

不支援的 engine 上勾 enablePriorBackup 會被略過(看 TaskRunLog 不會有 PRIOR_BACKUP_END)。

怎麼用備份倒帶

不是按一個按鈕。你開一份新 Plan,SQL 內容是「從 bbdataarchive 把 row 倒回 source」:

sql
-- 倒帶範本(PostgreSQL):
-- 假設 PriorBackupDetail 顯示 source=public.users / target=_a1b2c3_users_20260615
INSERT INTO public.users (id, email, ...)
SELECT id, email, ... FROM bbdataarchive._a1b2c3_users_20260615
ON CONFLICT (id) DO UPDATE SET
  email = EXCLUDED.email;

這份 Plan:

  • 走 advisor + 審批,跟原始 Plan 同等待遇
  • 自動再做一次 PriorBackup(如果你想要的話)
  • 進 Revision 帳本,跟原 Plan 串成完整時序

為什麼不一鍵倒帶? 一鍵 = 沒審批 = 任何能跑 rollback 的人都能改 prod 資料 = 違反「所有變更走 Plan」核心承諾。Argus 的設計是 rollback 也是變更,rollback 也要審批

限制

限制說明
只備份 DML 影響的 row,不備份整表例:UPDATE WHERE id=42 只備這一筆,不備整張 users
不備份 SELECT 結果、不備份 view、不備份 sequence純 DML 變更感知
bbdataarchive 內表沒 retention 政策長期累積會佔空間,需要 DBA 定期清 — SOP 見 bbdataarchive 保留政策
不能跨 instance / 跨 DB enginebackup 跟 source 必須同 instance
不取代 PITR / DB 內建備份是「逐次變更的 row 級備份」不是「整 DB 時間點還原」

DDL 變更:sync_history + Revision(schema 歷史追蹤)

DDL 沒有等同 PriorBackup 的機制 — schema 變更(CREATE TABLE / ALTER COLUMN / DROP COLUMN)很多動作沒有乾淨的反向 SQL

DDL反向可行嗎
ADD COLUMN x INT NULL✅ 簡單:DROP COLUMN x
ADD COLUMN x INT NOT NULL DEFAULT 0⚠️ 反向後,原本沒值的 row 應該怎樣?
DROP COLUMN x資料已 gone,反向只能拿到空欄位
DROP TABLE users❌ 整表資料 gone
ALTER COLUMN type TEXT → VARCHAR(50)⚠️ 截斷風險,反向不安全

所以 Argus 對 DDL 走「追蹤 + 手動寫反向 SQL」路徑,不嘗試自動生成。

Argus 為你存了什麼

每次 Plan-driven 變更後:

角色
revision每筆 schema 變更寫一筆,含 version + 完整 SQL(你可以反查上次跑了什麼)
sync_history每次 sync schema 拍一張 metadata snapshot(含 raw_dump)
changelog把 task_run 連到 sync_history,知道「哪次跑了什麼 → 跑完後 schema 是什麼樣」

怎麼寫反向 Plan

  1. 找變更時間點:上 audit log 查 bb.databases.adminExecute 或對應 issue 的 TaskRun 時間
  2. 撈變更前 snapshot
    sql
    SELECT raw_dump FROM sync_history
    WHERE instance = '<instance>' AND db_name = '<db>'
    AND created_at < '<變更時間>'
    ORDER BY created_at DESC LIMIT 1;
  3. diff 出反向 SQL:用 Atlas / pg_dump --schema-only / 手寫,比對「現在 schema」vs「snapshot schema」
  4. 開新 Plan 跑反向 SQL — 一樣走 advisor + 審批

跟 Schema Drift Detection 的銜接

DDL 反向 Plan 跑完後:

  • TaskRun 結束會自動祝福新 baseline(backend/runner/taskrun/blessing_hook.go
  • 下次 Schema Drift runner tick 不再出現該 db 的 drift event
  • 如果有殘餘 drift event 未 resolve,Auditor 在列表手動 Resolve 標 retroactive_plan

DML + DDL 混合變更怎麼算

很常見:一個 Plan 內既有 DDL 又有 DML(例:先 ADD COLUMN,再 UPDATE 新欄位)。

混合場景PriorBackup 行為
ALTER TABLE ADD COLUMN; UPDATE ...TransformDMLToSelect 自動過濾掉 DDL,只備份 UPDATE 影響的 row
純 DDL不會生成 backup(但 sync_history 仍會拍 snapshot)
純 DML完整 PriorBackup

反模式 — 看到立刻喊停

行為為什麼不該
直接 connect prod 跑反向 SQL(不開 Plan)違反「所有變更走 Plan」;觸發 Schema Drift event
把 bbdataarchive 當長期備份倉它不是 — 只是逐次 PriorBackup 的累積;定期清
用 PriorBackup 取代 DB 內建 backup / PITR兩個維度不同 — PriorBackup 是「逐次變更追溯」,PITR 是「整 DB 時間點還原」。兩者並存
Snowflake / MongoDB 上勾 enablePriorBackup 期待會備份不支援的 engine 會 silently skip
寫反向 Plan 不勾 enablePriorBackup反向也是變更,也該備 — 萬一倒帶倒錯方向再想倒帶

常見錯誤

訊息 / 現象含意處理
PRIOR_BACKUP_END 含 error備份失敗(通常 sidecar DB 權限不夠 / 空間不足)看 error 訊息;通常 DBA 在 instance 內手動建好 bbdataarchive 並 grant 權限
TaskRunLog 沒有 PRIOR_BACKUP_END沒勾 enablePriorBackup 或不支援的 engine確認 Plan 設定 + engine
bbdataarchive 內找不到對應 backup tableTaskRun 還在跑或備份失敗中斷看 TaskRunLog;正常完成的 PRIOR_BACKUP_END 一定有 PriorBackupDetail
Plan 勾了 enablePriorBackup 但 PriorBackupDetail 是 empty ItemsDML 影響 0 row(WHERE 沒匹配任何 row)跑前先 SELECT COUNT 確認

相關

Argus — 公司內部資料庫變更審計平台