數據庫的備份有多種分類方式。按照備份后的文件類型,可以分為物理備份(文件系統級別的備份)和邏輯備份(備份后的文件是sql文件或特定格式的導出文件);按照備份過程中是否停止數據庫服務,可分為冷備份(備份過程中停止數據庫服務)和熱備份(備份過程中數據庫服務開啟並可供用戶訪問);按照備份是否是完整的數據庫,可分為全量備份(備份是完整的數據庫)和增量備份(備份是上一次全量備份后數據庫改變的內容)。
Postgresql的常見備份方式有以下三種:
1. 文件系統級別的冷備份。
這種備份方式需要關閉數據庫,然后拷貝數據文件的完整目錄。恢復數據庫時,只需將數據目錄復制到原來的位置。該方式實際工作中很少使用。
2. SQL轉儲。
這里我們用到的工具是pg_dump和pg_dumpall。
這種方式可以在數據庫正在使用的時候進行完整一致的備份,並不阻塞其它用戶對數據庫的訪問。它會產生一個腳本文件,里面包含備份開始時,已創建的各種數據庫對象的SQL語句和每個表中的數據。可以使用數據庫提供的工具pg_dumpall和pg_dump來進行備份。pg_dump只備份數據庫集群中的某個數據庫的數據,它不會導出角色和表空間相關的信息,因為這些信息是整個數據庫集群共用的,不屬於某個單獨的數據庫。pg_dumpall,對集簇中的每個數據庫調用pg_dump來完成該工作,還會還轉儲對所有數據庫公用的全局對象(pg_dump不保存這些對象)。 目前這包括適數據庫用戶和組、表空間以及適合所有數據庫的訪問權限等屬性。
例如,在我的計算機上,可使用如下命令對名為dbname的數據庫進行備份:
pg_dump –h 127.0.0.1 -p 5432 -U postgres -c -C –f dbname.sql dbname
使用如下命令可對全部pg數據庫進行備份。
pg_dumpall –h 127.0.0.1 –p 5432 -U postgres –c -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的標簽、備份的起始與終止事務日志位置以及備份的起始和終止時間。返回值是備份的終止事務日志位置(同樣也可以被忽略)。 在記錄結束位置之后,當前事務日志插入點被自動地推進到下一個事務日志文件,這樣結束的事務日志文件可以立即被歸檔來結束備份。