Postgresql的三種備份方式
資料庫的備份有多種分類方式。按照備份後的檔案型別,可以分為物理備份(檔案系統級別的備份)和邏輯備份(備份後的檔案是sql檔案或特定格式的匯出檔案);按照備份過程中是否停止資料庫服務,可分為冷備份(備份過程中停止資料庫服務)和熱備份(備份過程中資料庫服務開啟並可供使用者訪問);按照備份是否是完整的資料庫,可分為全量備份(備份是完整的資料庫)和增量備份(備份是上一次全量備份後資料庫改變的內容)。
Postgresql的常見備份方式有以下三種:
1. 檔案系統級別的冷備份。
這種備份方式需要關閉資料庫,然後拷貝資料檔案的完整目錄。恢復資料庫時,只需將資料目錄複製到原來的位置。該方式實際工作中很少使用。
2. SQL轉儲。
這裡我們用到的工具是pg_dump和pg_dumpall。
這種方式可以在資料庫正在使用的時候進行完整一致的備份,並不阻塞其它使用者對資料庫的訪問。它會產生一個指令碼檔案,裡面包含備份開始時,已建立的各種資料庫物件的SQL語句和每個表中的資料。可以使用資料庫提供的工具pg_dumpall和pg_dump來進行備份。pg_dump只備份資料庫叢集中的某個資料庫的資料,它不會匯出角色和表空間相關的資訊,因為這些資訊是整個資料庫叢集共用的,不屬於某個單獨的資料庫。pg_dumpall,對集簇中的每個資料庫呼叫pg_dump
例如,在我的計算機上,可使用如下命令對名為dbname的資料庫進行備份:
pg_dump –h 127.0.0.1 -p 5432 -U postgres -c –f dbname.sql dbname
使用如下命令可對全部pg資料庫進行備份。
pg_dumpall –h 127.0.0.1 –p 5432 -U postgres –c –f db_bak.sql
恢復方式很簡單。執行恢復命令即可:
psql –h 127.0.0.1 -p 5432 -U postgres –f db_bak.sql
3. 連續歸檔
這種方式的策略是把一個檔案系統級別的全量備份和WAL(預寫式日誌)級別的增量備份結合起來。當需要恢復時,我們先恢復檔案系統級別的備份,然後重放備份的WAL檔案,把系統恢復到之前的某個狀態。這種備份有顯著的優點:
- 不需要一個完美的一致的檔案系統備份作為開始點。備份中的任何內部不一致性將通過日誌重放來修正。
- 可以結合一個無窮長的WAL檔案序列用於重放,可以通過簡單地歸檔WAL檔案來達到連續備份。
- 不需要重放WAL項一直到最後。可以在任何點停止重放,並使資料庫恢復到當時的一致狀態。
- 可以連續地將一系列WAL檔案輸送給另一臺已經載入了相同基礎備份檔案的機器,得到一個實時的熱備份系統。
如何進行連續歸檔呢?
下面的例項中,作業系統為windows 10,Postgresql的版本為9.6。
首先,需要修改postgresql.conf檔案的幾個引數修改如下:
wal_level = ‘replica’
archive_mode = ‘on’
archive_command = 'copy /y "%p" "D:\\archive\\%f"'
archive_command執行時,%p會被要被歸檔的檔案路徑所替代,而%f只會被檔名所替代。如果你需要在命令中嵌入一個真正的%字元,可以使用%%。 “D:\\archive\\”替換為歸檔日誌的存放路徑,要確保歸檔的目錄是存在的。
接下來需要製作一個非排他的基礎備份。Postgresql提供了排他備份和非排他備份兩種備份方式,推薦使用非排他的備份方式。
1. 作為一個具有執行 pg_start_backup 權利的使用者連線到伺服器(不在乎是哪個資料庫)並且發出命令:
Select pg_start_backup('backup_label', false, false);
2. 對資料庫進行一次檔案系統級別的備份。即將postgresql的安裝目錄下的data目錄及其內容複製到其他位置。
3. 在同一個連線中,發出命令:
select * from pg_stop_backup(false);
這個命令代表結束一次非排他的備份。
現在來看基於時間點的恢復。
假如你的資料庫出現了故障,需要恢復到之前的某個時刻的一致的狀態,就需要進行基於時間點的恢復。
其過程是:
1. 如果伺服器仍在執行,停止它。
2. 如果你具有足夠的空間,將整個集簇資料目錄和表空間複製到一個臨時位置。注意最好是拷貝而不是移動。如果你沒有足夠的空間,你至少要儲存集簇的pg_xlog子目錄的內容,因為它可能包含在系統垮掉之前還未被歸檔的日誌。
3. 移除data 目錄及其所有子檔案和子目錄。
4. 從檔案系統備份中恢復資料庫檔案。注意它們要使用正確的使用者恢復並且使用正確的許可權。如果你在使用表空間,你應該驗證pg_tblspc/中的符號連結被正確地恢復。
5.現在已經從備份中恢復了整個資料目錄,接下來,你需要部分或全部刪除資料目錄中的下列檔案,如果它們存在:
(1) postmaster.pid;(必須)
(2) pg_xlog中的檔案;(必須)
(3) pgsql_tmp開頭的臨時檔案;(可選)
(4) postgresql.auto.conf.tmp;(可選)
(5) pg_replslot目錄中的檔案;(可選)
(6) pg_stat_tmp目錄中的檔案。(可選)
6. 如果你有在第2步中儲存的未歸檔WAL段檔案,把它們拷貝到pg_xlog/中或WAL日誌的歸檔目錄中。
在集簇資料目錄中建立一個恢復命令檔案recovery.conf。如果你想恢復到最近的一致狀態,在recovery.conf寫入如下兩行:
restore_command = 'copy /y D:\\archive \\%f\\%p'
recovery_target_timeline = 'latest'
其中,restore_command的內容表示將歸檔日誌資料夾中的內容拷貝到pg_xlog,其引數的含義與上文archive_command的引數含義完全相同;recovery_target_timeline = 'latest' 表示恢復到最近的時間點。
7. 如果要阻止普通使用者在成功恢復之前連線,請修改pg_hba.conf。
8. 啟動伺服器。伺服器將會進入到恢復模式並且進而根據需要讀取歸檔WAL檔案。恢復可能因為一個外部錯誤而被終止,可以簡單地重新啟動伺服器,這樣它將繼續恢復。恢復過程結束後,伺服器將把recovery.conf重新命名為recovery.done(為了阻止以後意外地重新進入恢復模式),並且開始正常資料庫操作。
9. 檢查資料庫的內容來確保你已經恢復到了期望的狀態。如果沒有,返回到第1步。如果一切正常,通過恢復pg_hba.conf為正常來允許使用者連線。
這樣就完成了一次檔案系統級別的全量備份,並實現了WAL檔案級別的增量備份。
附:pg_start_backup() 和 pg_stop_backup()做了什麼?
1. pg_start_backup()
pg_start_backup() 的函式原型如下:
pg_start_backup(label text [, fast boolean [, exclusive boolean ]])
其中label是用來唯一標識這次備份操作的任意字串,fast 表示是否立即執行強制的檢查點,exclusive 表示該備份是否是一個排他備份。
使用該函式時,推薦將exclusive設定為false,即非排他方式備份。
執行下面的命令:
Select pg_start_backup('backup_label', false, false);
這條命令會產生三個動作:
1. 在緩衝區中建立兩個變數:label_file和tblspc_map_file。前者包含WAL的起始位置、檢查點的起始位置、備份方法、備份模式、備份開始時間和備份標籤的名稱(本例中,名稱為“backup_label”)等資訊;後者包含 “pg_tblspc/”中表空間符號連結的資訊,如果它們存在。
2. 強制發生一次檢查點。將檢查點開始前提交的事務對資料庫的修改重新整理到磁碟。
3. 置寫日誌標誌為:XLogCtl->Insert.forcePageWrites = true。把這個標誌設定為true後,如果在備份期間時有其他事務修改資料庫,那麼系統會把被修改的資料頁在修改前的完整頁面都記錄到WAL中,而不僅僅是記錄頁面中的變化的部分。
為什麼要將完整的頁面記錄到WAL中呢?
原因是在備份過程中,其他事務修改資料庫,可能會造成備份後的資料存在新舊資料混合的情況,甚至同一資料頁面也會出現這種情況。假如WAL日誌中僅僅記錄變化的那部分的內容,就無法將資料庫恢復到上次備份結束時刻的狀態。所以要將修改後的完整頁面寫入WAL中,以保證資料庫恢復後的一致性。
2. pg_stop_backup()
pg_stop_backup()的函式原型如下:
pg_stop_backup([, exclusive boolean ]);
exclusive 表示該備份是否是一個排他備份。
如果採用非排他方式備份,執行:
Select pg_stop_backup(false);
這條命令會產生如下動作:
1. label_file和tblspc_map_file的內容會包含在該函式返回的結果中,並且應該被寫入到該備份的一些檔案中(這些內容不在資料目錄中)。
2. 在事務日誌歸檔區裡建立一個備份歷史檔案(.hostory)。這個歷史檔案包含 pg_start_backup的標籤、備份的起始與終止事務日誌位置以及備份的起始和終止時間。返回值是備份的終止事務日誌位置(同樣也可以被忽略)。 在記錄結束位置之後,當前事務日誌插入點被自動地推進到下一個事務日誌檔案,這樣結束的事務日誌檔案可以立即被歸檔來結束備份。
參考文獻
[1] PostgreSQL全球開發小組. PostgreSQL 9.6.0 文件. 連續歸檔和時間點恢復(PITR).
[2] 2ndquadrant. What does pg_start_backup() do?. 2017-1-23
[3] Michael Paquire. Postgres 9.6 feature highlight - Non-exclusive base backups. 2016-5-31