Categories
Database Backup

> Discover why standard VM snapshots cause data corruption in transactional databases like PostgreSQL and SQL Server. Learn DBA best practices for application-consistent backups, avoiding VM stun, and ensuring data integrity with CloudSave.

對於 DevOps 工程師和系統管理員而言,虛擬機器 (VM) 快照是一項基礎工具。它們提供了一種快速、便捷的方式,可以在執行高風險修補程式、重大配置變更或應用程式部署之前,擷取伺服器的狀態。如果發生問題,只需幾秒鐘即可完成還原。

然而,當同樣的方法應用於交易型資料庫(例如 PostgreSQL、MySQL、Oracle 或 Microsoft SQL Server)時,VM 快照就會從安全網變成一顆定時炸彈。

依賴標準虛擬化平台 (Hypervisor) 快照進行資料庫備份,是導致資料損毀、頁面損壞 (torn pages) 和無法復原的生產環境中斷的最常見原因之一。在本文中,我們將探討虛擬化平台與資料庫引擎之間的架構衝突、快照期間資料損毀的機制,以及安全備份虛擬化資料庫所需的工程最佳實踐。

架構衝突:虛擬化平台 vs. 資料庫引擎

要了解為什麼 VM 快照會危及資料庫,我們必須先檢視這兩個系統如何管理狀態和 I/O 操作。

虛擬化平台如何執行快照

當虛擬化平台(例如 VMware ESXi、Microsoft Hyper-V 或 KVM)執行快照時,它並不會複製磁碟。相反地,它會將目前的虛擬磁碟檔案(例如 .vmdk.vhdx)凍結為唯讀狀態,並建立一個新的差異磁碟 (delta disk)。所有後續的寫入操作都會導向至此差異磁碟。

當刪除快照時,虛擬化平台必須將差異磁碟中的資料提交(合併)回基礎磁碟。標準快照完全不了解客體作業系統內執行的應用程式。它們只是在該微秒瞬間精確地擷取磁碟狀態。

交易型資料庫如何管理狀態

交易型資料庫是圍繞 ACID 特性(原子性、一致性、隔離性、持久性)設計的。為了在保持 ACID 合規性的同時實現高效能,資料庫不會立即將每筆交易直接寫入磁碟上的主要資料檔案。相反地,它們使用複雜的多層架構:

  1. 緩衝池 / 共享緩衝區 (Buffer Pool / Shared Buffers): 資料被讀取並在系統記憶體中進行修改。
  2. 預寫式記錄 (WAL) / 重做記錄 (Redo Logs): 變更會依序寫入磁碟上高度最佳化的記錄檔,以確保持久性。
  3. 檢查點 / 延遲寫入 (Checkpoints / Lazy Writers): 資料庫會定期將記憶體中修改過的(髒)頁面刷新到磁碟上的實際資料檔案中。

由於這種架構,磁碟上的實體資料檔案幾乎總是與資料庫的實際狀態不同步。資料庫的真實狀態僅存在於磁碟上的資料檔案、WAL/重做記錄以及目前駐留在記憶體中的資料的組合中。

危險地帶:VM 快照期間會發生什麼

當您對資料庫伺服器執行標準 VM 快照時,您擷取的是一個崩潰一致性 (crash-consistent) 的狀態。

崩潰一致性 vs. 應用程式一致性

崩潰一致性快照等同於拔掉實體伺服器的電源線。磁碟狀態被擷取了,但記憶體中的內容會遺失,而傳輸到儲存控制器的中途資料也會突然中斷。

雖然現代資料庫設計為透過重播預寫式記錄來從意外斷電中復原,但將崩潰復原作為主要的備份策略是非常危險的。如果您的資料庫跨越多個虛擬磁碟(例如資料檔案在 D 槽,WAL 在 E 槽),虛擬化平台可能無法在完全相同的微秒內對兩個磁碟進行快照。如果 WAL 磁碟快照是在資料磁碟快照之後才擷取的(即使只差幾分之一秒),資料庫在還原時就無法協調序列號,從而導致致命的損毀。

對高交易系統的「VM 停頓」(VM Stun) 效應

快照建立過程——更重要的是快照合併過程——會導致一種稱為「VM 停頓」的現象。

為了安全地將 I/O 從基礎磁碟切換到差異磁碟,虛擬化平台必須短暫地暫停 (stun) 虛擬機器。對於負載較輕的網頁伺服器,這種停頓可能持續 10-50 毫秒且不易察覺。然而,對於具有大量 I/O 的高吞吐量資料庫,合併大型差異磁碟可能會導致 VM 停頓數秒之久。

在 VM 停頓期間:
* 網路連線中斷,導致應用程式逾時。
* 高可用性叢集(如 SQL Server Always On、PostgreSQL Patroni 或 MySQL Galera)會錯過心跳檢查。
* 叢集可能會認為停頓的節點已死,從而觸發不必要且具破壞性的容錯移轉(腦裂情境)。

頁面損壞 (Torn Pages) 與 I/O 不對齊

資料庫引擎通常以特定的頁面大小寫入資料(例如 PostgreSQL 和 SQL Server 為 8KB,InnoDB 為 16KB)。然而,底層作業系統和儲存陣列處理 I/O 的區塊較小(例如 4KB 或 512 位元組)。

如果虛擬化平台恰好在資料庫寫入 8KB 頁面時進行快照,快照可能會擷取新資料的前 4KB 和舊資料的後 4KB。這會產生一個頁面損壞 (torn page)。當您嘗試還原快照時,資料庫讀取該頁面會導致校驗和驗證失敗,並將資料庫標記為損毀。

特定資料庫引擎的現實後果

不同的資料庫引擎對崩潰一致性快照的反應各不相同,但在生產環境中,沒有一個能優雅地處理這種情況。

  • PostgreSQL: PostgreSQL 極度依賴 pg_wal 目錄。如果快照擷取的資料目錄 ($PGDATA) 與 WAL 不同步,PostgreSQL 將無法啟動,並拋出 PANIC: could not locate a valid checkpoint record 錯誤。
  • MySQL/InnoDB: InnoDB 使用雙寫緩衝區 (doublewrite buffer) 來防止頁面損壞,這對崩潰一致性狀態提供了一些保護。然而,如果 ibdata1 檔案和 ib_logfile 不同步被擷取,InnoDB 引擎在復原時仍會崩潰。
  • Microsoft SQL Server: SQL Server 對 I/O 凍結非常敏感。如果沒有適當的 VSS (磁碟區陰影複製服務) 整合,從標準 VM 快照還原 SQL Server 通常會導致資料庫處於「可疑」(suspect) 狀態並破壞記錄鏈,從而摧毀您的時間點復原 (PITR) 能力。

安全備份虛擬化資料庫的最佳實踐

為了保護交易型資料庫,您必須從崩潰一致性備份轉向應用程式一致性 (application-consistent) 備份。這要求備份機制必須與資料庫引擎進行通訊,強制其在進行快照時將記憶體刷新到磁碟並暫時暫停 I/O 操作。

1. 利用應用程式感知靜止 (VSS 和 fsfreeze)

針對 Windows (SQL Server):
請務必確保您的備份解決方案使用 Microsoft 磁碟區陰影複製服務 (VSS)。當觸發 VSS 感知備份時,SQL Server VSS Writer 會凍結資料庫 I/O,將待處理的交易刷新到磁碟,並確保快照達到完美的應用程式一致性。

針對 Linux (PostgreSQL / MySQL):
Linux 沒有 VSS 的原生對應功能。為了達到應用程式一致性,您必須結合虛擬化平台的客體工具(例如 VMware Tools)使用凍結前 (pre-freeze) 和解凍後 (post-thaw) 指令碼。

以下是一個適用於 PostgreSQL 15+ 的 VMware pre-freeze-script 範例,可安全地為快照準備資料庫:

#!/bin/bash
# /usr/sbin/pre-freeze-script
# 確保此指令碼具有執行權限 (chmod +x)

# 1. 通知 PostgreSQL 準備備份
su - postgres -c "psql -c "SELECT pg_backup_start('vm_snapshot', true);""

# 2. 將檔案系統緩衝區刷新到磁碟
sync

# 3. 凍結檔案系統 (假設資料位於 /var/lib/pgsql)
fsfreeze -f /var/lib/pgsql

以及對應的 post-thaw-script 以恢復操作:

#!/bin/bash
# /usr/sbin/post-thaw-script

# 1. 解凍檔案系統
fsfreeze -u /var/lib/pgsql

# 2. 通知 PostgreSQL 備份完成
su - postgres -c "psql -c "SELECT pg_backup_stop();""

2. 使用原生資料庫備份工具

雖然應用程式一致性快照優於標準快照,但它們仍然存在 VM 停頓的風險。資料庫備份最安全的方法是使用獨立於虛擬化平台運作的原生串流備份工具。

PostgreSQL (pg_basebackup):

pg_basebackup -h localhost -U replication_user -D /mnt/backups/pg_backup -Ft -z -P

MySQL/MariaDB (Percona XtraBackup / Mariabackup):
這些工具透過複製資料檔案並同時追蹤重做記錄中的變更,來執行熱備份且不阻塞操作。

mariabackup --backup --target-dir=/mnt/backups/mysql_backup --user=root --password=SecurePass

SQL Server (T-SQL):

BACKUP DATABASE [ProductionDB] 
TO DISK = N'Z:BackupsProductionDB.bak' 
WITH NOFORMAT, NOINIT, NAME = N'ProductionDB-Full Backup', 
SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 10;
GO

3. 透過記錄封存實現時間點復原 (PITR)

每日快照或完整備份只能保護您到備份完成的那一刻。如果您的資料庫在下午 4:00 崩潰,而您最後一次快照是在凌晨 2:00,您將遺失 14 小時的交易資料。

為了實現真正的企業級韌性,您必須將完整的應用程式一致性備份與持續的記錄封存(每隔幾分鐘備份 WAL、重做記錄或交易記錄)結合起來。這使資料庫管理員能夠將資料庫還原到災難發生前的特定分鐘,甚至是特定的交易 ID。

使用 CloudSave 的企業備份策略

對於 DevOps 團隊來說,管理數十台資料庫伺服器上的自訂凍結前指令碼、原生傾印 (dump) 的 cron 工作以及記錄傳輸是一場營運惡夢。這正是像 CloudSave 這樣的企業級平台變得至關重要的原因。

CloudSave 架起了虛擬化與資料庫架構之間的橋樑。CloudSave 不依賴盲目的虛擬化平台快照,而是利用與 SQL Server、PostgreSQL、MySQL 和 Oracle 原生整合的應用程式感知代理程式。

當 CloudSave 啟動備份時:
1. 它透過原生 API(如 Windows 的 VSS 或 Linux 的原生 WAL 串流)直接與資料庫引擎通訊。
2. 它協調記憶體緩衝區到磁碟的刷新,而不會導致破壞性的 VM 停頓。
3. 它安全地擷取資料檔案並自動管理交易記錄截斷。
4. 它持續備份交易記錄,只需點擊幾下即可實現細粒度的時間點復原 (PITR)。

透過將應用程式一致性的複雜性卸載給 CloudSave,資料庫管理員和系統管理員可以在不犧牲生產叢集效能或可用性的情況下,確保資料完整性。

結論

虛擬機器快照是基礎架構管理的絕佳工具,但它們從根本上與交易型資料庫的 ACID 要求不相容。依賴崩潰一致性的虛擬化平台快照會使您的組織面臨頁面損壞、複製鏈斷裂和災難性資料遺失的風險。

為了保護您的關鍵任務資料,您必須實施應用程式感知靜止、利用原生資料庫備份方法,並維護持續的交易記錄封存。透過採用專用的企業備份解決方案,您可以確保資料庫保持高可用性、完全可復原且絕對安全。