閱讀261 返回首頁    go 技術社區[雲棲]


如何用好PostgreSQL的備份與恢複?

如何用好PostgreSQL的備份與恢複?

作者

趙成

日期

2017-10-22

標簽

PostgreSQL , 數據庫高可用 , 備份與恢複


高可用性是數據庫的關鍵指標,簡單說就是要做到故障時間短,數據不丟失,能夠回退到指定位置(時間/事務)。實現高可用的基礎是數據庫的備份與恢複技術。

PostgreSQL備份與恢複操作涉及的參數和相關文件較多,內部邏輯關係較複雜,恢複分類方式容易混淆,這些都會影響到PostgreSQL高可用方案的實現。

本文首先介紹通常的數據庫故障場景與處理方案,然後通過梳理PostgreSQL數據庫備份與恢複的相關文件、參數配置與主要流程,對PostgreSQL恢複方式進行了清晰分類,最後給出了應對典型故障,PostgreSQL備份與恢複的配置方案。

一、故障場景和處理方案

數據庫采用數據文件加日誌文件,兩份數據的存儲方式。為提高性能,數據庫運行時操作的數據位於內存緩衝區,緩衝區的數據延遲寫入數據文件,因此數據文件會處於不一致的狀態。數據的變更記錄稱為日誌記錄,日誌記錄以日誌文件方式存儲在磁盤上。日誌記錄也是先寫入日誌緩衝區,再寫入日誌文件。通過兩個簡單的規則Write-ahead log(將數據寫入數據文件前,先將對應的日誌記錄寫入日誌文件)和Force log at commit(事務提交時,將其所有日誌記錄寫入日誌文件),可以保證通過日誌文件完整的恢複數據文件。

傳統的故障類型包括事務內部故障、係統故障、介質(磁盤)故障。對於事務內部故障和係統故障,數據庫使用日誌文件自動恢複,不需要人工幹預。為應對介質故障,DBA需事先備份數據,發生故障後,使用備份數據恢複數據庫。

可靠的磁盤設備可以大幅降低介質故障概率,但不能減少數據備份工作。一個常見的故障是數據誤操作,即修改了不應該修改的數據。從數據庫的角度看,誤操作是正常的操作,不會進行自動恢複,隻有使用備份數據才能恢複。同時,提供一段時間內曆史數據的訪問,也是一個常見的需求。

數據的備份與恢複可以分為邏輯與物理兩種方式。

  • 邏輯備份與恢複:備份時,使用工具將數據全量導出為外部文件,恢複時,使用工具,將備份文件導入新建的數據庫

  • 物理備份與恢複:備份時,配置實例處於歸檔模式,將生成的日誌文件保持到指定位置。使用熱備工具直接拷貝數據的數據目錄,作為基線數據。恢複時,使用基線數據和日誌文件將數據恢複到一致的狀態。
    邏輯方式不支持增量方式,適用於數據較小情況下的備份與恢複。物理方式支持增量備份,適合大數據量的備份與恢複。本文隻討論物理備份與恢複,下圖為物理備份與恢複的基本流程。

物理備份與恢複

在高可用需求中,當單台實例發生故障,需要快速提供備用實例。備份基線數據+日誌文件的方式無法滿足時間要求。通常采用主備(master/slave)方案,master與slave通過日誌流複製進行同步,slave可以提供隻讀數據訪問,當master發送故障後,直接將應用請求轉發到slave。

流複製與日誌切換

在高可用方案中,需要支持介質故障恢複,實時故障切換,誤操作數據恢複,查看曆史數據等功能。流複製技術和物理備份與恢複的結合,可以滿足數據庫高可用的基本要求。

流複製 物理備份與恢複
介質故障恢複 支持 支持
實時故障切換 支持 不支持
誤操作數據恢複 不支持 支持
查看曆史數據 不支持 支持

PostgreSQL備份與恢複相關文件、參數配置與主要流程

PostgreSQL日誌文件的命名

日誌序號 (lsn:log sequence number) 標識日誌記錄在日誌文件中的位置。lsn是一個64位的整數。PostgreSQL運行時生成的日誌文件存放在數據目錄下的pg_xlog目錄,每個日誌文件稱為一個segment,日誌文件大小固定,由wal_segment_size參數指定,日誌文件內部劃分為多個wal page,每個page的大小由wal_block_size參數指定。

對於一個64位的lsn,可以計算出其所在的xlog文件名。lsn可以劃分segment序號高位,segment序號低位和塊內序號三個部分。對於segment大小為64M和16M的情況如下:

16M:segment序號高位(32比特)+segment序號低位(8比特)+塊內序號(24比特)

64M:segment序號高位(32比特)+segment序號低位(6比特)+塊內序號(26比特)

Xlog文件名由三部分組成,格式為:時間線+segment序號高位+segment序號低位,每個部分都表示為一個8位16進製數字。取出lsn中的segment高位和segment低位數值,就可以確定其所在的xlog文件。

使用pg_current_xlog_location()查詢當前lsn為0/1C000090(16進製高32位/16進製低32位),當前時間線為1,wal segment大小為64M,

根據64M大小日誌文件名格式,可計算出lsn的segment序號高32位為0x0,segment序號低位為0x7, 塊內序號為0x90,xlog文件名為000000010000000000000007
使用pg_xlogfile_name_offset()可以查詢lsn對應的文件名文件內偏移,與上述計算一致。

pg_current_xlog_location

checkpoint與control文件

PostgreSQL的數據文件和日誌文件互為冗餘。當某lsn之前的操作已經全部寫入了數據文件後,則該lsn號之前的日誌文件可以丟棄。checkpoint機製實現此功能。

checkpoint操作在以下場景執行:管理員手工執行check命令、數據庫啟動完成恢複、數據庫正常關閉,以及後台Checkpoint進程的定期執行。

checkpoint流程可以簡單描述為,首先構造checkpoint記錄(redo字段為當前已寫入日誌文件的lsn),然後將數據緩衝區中的髒數據寫入磁盤,最後寫入checkepoint日誌記錄(包含checkpoint記錄),並將checkpoint記錄寫入control文件。

512字節的control文件是PostgreSQL的關鍵數據,用於數據庫啟動時,判斷數據庫狀態和恢複位置。controlfile文件中記錄了數據庫的狀態,最近checkpoint記錄,最小恢複lsn信息和基本的參數配置。數據庫的狀態包括:

  • DB_SHUTDOWNED(數據庫正常關閉)
  • DB_SHUTDOWNED_IN_RECOVERY(數據庫在恢複時關閉)
  • DB_SHUTDOWNING(數據庫啟動到正常關閉過程中崩潰)
  • DB_IN_CRASH_RECOVERY(數據庫在恢複過程中崩潰),
  • DB_IN_ARCHIVE_RECOVERY(數據庫處於歸檔恢複)
  • DB_IN_PRODUCTION(數據庫處於正常工作狀態,等待接受事務處理)

日誌文件的生成與歸檔

PostgreSQL日誌文件的segment序號從1開始,一個日誌文件寫完後,會寫入下一個序號的日誌文件。checkpoint之後,最近一次checkpoint.redo lsn之前的日誌文件可以丟棄。PostgreSQL會循環使用日誌文件。checkpoint操作中,會將可丟棄的日誌文件改名為未來的日誌文件名,並該日誌文件重新初始化。PostgreSQL在寫新的日誌文件時,如果該文件已存在,則使用該文件,否則才會創建新的文件。因此不能從pg_xlog目錄中的文件名直接判斷當前的日誌文件,需要使用pg_current_xlog_location和pg_xlogfile_name_offset函數進行判斷。

為持久保存日誌文件,需要開啟日誌歸檔模式。在該模式下,可丟棄日誌文件被刪除前,被拷貝到指定目錄。在postgres.conf配置文件中設置三個參數:

wal_level=replica 或更高
archive_mode = on
archive_command = 'cp %p /mnt/server/archivedir/%f'
%p表示pg_xlog目錄路徑和日誌文件名,%f表示日誌文件名。 日誌被拷貝到/mnt/server/archivedir目錄

日誌的歸檔過程如下:

  • checkpoint操作中,當一個日誌文件X可丟棄時,在pg_xlog的archive_status目中生成X.ready文件。
  • 後台archive進程負責日誌文件的拷貝。該進程監控archive_status目錄,當發現有X.ready文件名後,使用archive_command拷貝文件,並將X.ready命名為X.done
  • 下一次checkpoint操作中,將archive_status目中X.done對應的X日誌文件改名。

crash recovery

PostgreSQL正常運行中,直接kill主進程,重啟PostgreSQL,將進入crash recovery處理流程,從control文件中checkpoint的redo lsn位置開始,
使用pg_xlog目錄中的日誌文件進行恢複。PostgreSQL能進行上述處理,是因為將其狀態和最近的checkpoint記錄在在control文件中。

初始化數據庫後,control文件DB狀態初始值為shutdown。pg啟動時,當control文件DB狀態為shutdown,則將狀態設置為production,退出恢複過程。在正常關閉服務時,執行checkpoint,並將control文件DB狀態設置shutdown。pg啟動時,當control文件DB狀態為production,則說明發生了crash,會從control文件讀取最近checkpoint,從redo lsn開始進行恢複,恢複完成後,將狀態設置為production。

熱備

備份分為冷備和熱備。冷備是正常關閉服務後拷貝文件。熱備是服務正常運行中拷貝文件。由於采用數據緩衝區機製,拷貝的文件數據會不一致。根據數據庫恢複基本原理,隻要確定某lsn之前的日誌已經全部寫入了數據文件,則在拷貝後的數據文件上,應用該lsn號之後的日誌文件,可將數據恢複到一致的狀態。

熱備包括以下步驟

  • 執行pg_start_backup函數:該函數執行checkpoint,將checkpont信息寫入數據目錄下的backup_label文件。
  • 拷貝數據目錄到指定位置
  • 執行pg_stop_backup函數:該命令刪除backup_label文件,寫XLOG_BACKUP_END日誌,並在pg_xlog目錄中寫入backup文件,該文件記錄了熱備開始和結束的lsn信息。

backup文件格式為:熱備開始lsn對應的日誌文件名.開始lsn的塊內偏移.backup

使用歸檔日誌恢複

Crash recovery隻能使用pg_log目錄中的日誌文件進行恢複,啟用archive recovery模式後,可以使用其它目錄的日誌文件(歸檔日誌文件)進行恢複。

在數據目錄存創建recover.conf文件,PostgreSQL啟動時,讀取到該文件,會進入archive recovery流程。在recover.conf中設置日誌拷貝命令restore_command,pg恢複過程中,使用該命令將歸檔日誌拷貝到pg_xlog目錄後進行恢複。

restore_command = 'cp /mnt/server/archivedir/%f "%p"'
%f表示日誌文件名 %p表示目標路徑和文件名

使用流複製恢複

流複製可以視為archive recovery的一種情況。使用歸檔日誌文件進行恢複時,備機需要獲取主機一個完整xlog文件,才可進行恢複。在流複製中,主機產生日誌記錄後,會及時發送到備機。

在slave節點數據目錄的recover.conf中,配置到主機的連接信息primary_conninfo並設置standby_mode為on。

standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'

master節點的postgres.conf文件中指定wal_level和發送日誌進程的數目max_wal_senders。

wal_level=replica 或更高
max_wal_senders=5

在master的pg_hba.conf文件中允許複製連接建立

host    replication     postgres        192.168.10.0/24            trust

slave啟動後會啟動wal reciver進程,根據primary_conninfo向master發送連接請求。master收到請求後,啟動wal sender進程,wal sender與reciver建立連接。 wal reciver將起始的lsn信息發送給wal sender,wal sender從該lsn開始,將日誌記錄持續發送給wal reciver,wal reciver將日誌寫入pg_xlog目錄中的日誌文件,並通知恢複進程讀取文件進行恢複處理。

恢複的退出與時間線

Crash recovery模式下,應用完pg_xlog目錄中的所有可用日誌文件後,自動退出恢複,進入運行狀態。Archive recovery模式下,recovery.conf文件中參數standby_mode為off時,應用完所有日誌後,自動退出恢複,進入運行狀態。standby_mode為on時,應用完所有日誌後,恢複流程不會退出,持續讀取可用日誌(來自於歸檔日誌文件或流複製),當收到pg_ctl工具發出的promote命令後,才退出恢複流程,進入運行狀態。

可以通過設置Recovery Target,使得archive recovery在指定的位置(時間或事務號)停止恢複。在recovery.conf文件配置如下參數,表示恢複流程在恢複完123947事務後結束。

recovery_target_xid = '123947'

時間線(Timeline)是PostgreSQL中的特有的概念。其初始值為1,退出archive recovery時,timeline增1,退出crash recovery時,timeline不變。Timeline反映在日誌的文件名中,日誌文件的命名格式為:時間線號+segment序號高位+segment序號低位。

引入時間線概念後,日誌位置的唯一標識從lsn變為時間線+lsn,checkpoint的結構中記錄了當前的timeline。

發生時間線切換時,在pg_xlog目錄寫入時間線history文件,文件名為"當前timelime.history",文件內記錄了時間線切換的曆史紀錄,每一行記錄一條時間線信息,格式為。

parentTLI為時間線id,為切換發生後的lsn,為發生切換的原因。

從時間線history文件中,可以計算出每條時間線的開始和結束lsn。

時間線文件00000003.history,內容為 
1   0/14000060  no recovery target specified
2   0/140420D0  no recovery target specified

該文件含義為當前時間線為3,時間線1的lsn範圍[0/0,0/14000060),
時間線2的lsn範圍[0/14000060,0/140420D0),時間線3從0/140420D0開始。

使用timeline有以下優點:

  • 切換邏輯顯得清晰。從時間線history文件,可以計算出每條時間線的開始和結束lsn。
  • 避免歸檔日誌的覆蓋。當備機與主機的歸檔目錄相同時,備機升級為主機後,生成的日誌文件名與原主機不同(時間線不同),拷貝到歸檔目錄後,不會覆蓋之前的日誌文件。

pg_basebackup、pg_rman工具

pg_basebackup和pg_rman為備份與恢複提供良好的操作管理界麵,避免手工管理配置文件。

pg_basebackup是PostgreSQL自帶的一個遠程熱備工具,可以將遠程PostgreSQL熱備到本地目錄。其工作流程為,連接到一個遠程PostgreSQL,執行pg_start_backup,將整個數據目錄傳輸到本地,執行pg_stop_backup命令。

將地址為192.168.0.1的PostgreSQL,備份到本地usr/local/pgsql/data目錄
pg_basebackup -h 192.168.0.1 -U test -D /usr/local/pgsql/data

pg_basebackup支持在目標數據目錄生成用於流複製的recovery.conf文件。

pg_basebackup -h 192.168.0.1 -U test -R -D /usr/local/pgsql/data

會在/usr/local/pgsql/data目錄生成流複製所用的postgresql.conf文件,內容如下

standby_mode = 'on'
primary_conninfo = 'host=192.168.0.1 user=test'

pg_rman是PostgreSQL的備份與恢複工具,支持全量、增量、歸檔三種備方式,支持數據壓縮與備份集管理。pg_rman適用於大數據量數據庫的增量備份。pg_rman必須與被備份數據庫安裝在同一台機器。其備份流程為,連接到本地PostgreSQL,執行pg_start_backup,全量備份文件或者通過比較數據文件塊的lsn號進行增量備份,執行pg_stop_backup命令,備份歸檔日誌。

pg_rman 恢複支持將數據恢複到指定時間、事務號和時間線參數,流程為其將對應的全量數據和歸檔日誌拷貝到相應目錄,並配置recovery.conf文件的restore_command參數,standby_mode為off。
pg_rman支持的命令包括

  • 初始化 pg_rman init
  • 全量備份 pg_rman backup -b full
  • 增量備份 pg_rman backup -b incremental
  • 恢複 pg_rman restore

PostgreSQL數據庫恢複分類

根據配置文件和參數的不同,PostgreSQL恢複可以做以下分類。

恢複分類

Crash recovery是PostgreSQL發生故障後自動進行的恢複處理,archive recovery是DBA通過配置recovery.conf文件,PostgreSQL啟動後進入的恢複流程。

配置recovery.conf文件的standby_mode參數為on或off,可以控製進入standb模式還是非standby模式。非standby模式下,PostgreSQL恢複到指定位置或者發現沒有可用日誌記錄時,停止恢複流程。standby模式下,在沒有可用日誌的情況下,會持續檢查並應用可用日誌,直到DBA發出promote命令。

配置postgresql.conf文件的hot_standby參數為on或off,可以控製是否開啟hot standby模式。hot standby開啟情況下,恢複結束前,數據庫可對外提供隻讀訪問。hot standby關閉情況下,恢複結束前,數據庫不提供對外訪問。

5種情況下配置文件與參數的不同:

  • crash recovery:無recovery.conf文件
  • archive recovery:有recovery.conf文件,lable文件(可選)
    • standby-hot standby:standby_mode為on,hot_standby為on
    • standby-非hot standby:standby_mode為on,hot_standby為off
    • 非standby-hot standby:standby_mode為off,hot_standby為on
    • 非standby-非hot standby:standby_mode為off,hot_standby為off

對於流複製建議采用archive recovery-standby-hot standby配置,對於基線數據+歸檔日誌恢複的配置,建議采用archive recovery-非standby-hot standby配置。

Recovery過程簡單說就是從一個checkpoint的redo lsn位置開始,通過應用日誌記錄,使數據文件達到一致的狀態。對於每一種恢複配置,要明確三個問題,從哪裏找到開始的lsn與時間線,日誌記錄的來源是哪裏,恢複狀態如何退出。

Crash recovery模式下,從control文件讀取checkpoint記錄,其中包含redo lsn和時間線,從該位置開始恢複,日誌記錄隻來自pg_xlog目錄中的日誌文件,當沒有日誌可以應用時,退出恢複。

Archive recovery模式下,當數據目錄下不存在backup_label文件時,與crash recovery相同的方式從control文件讀取redo lsn和時間線。當數據目錄下存在backup_label文件時,redo lsn從該文件讀取,根據timeline history文件,獲取該redo lsn對應的時間線。

Archive recovery模式的非standby配置下,必須配置recovery.conf的restore_command命令,該模式下隻能使用歸檔日誌文件進行恢複。應用完所有的規定日誌,或者指定位置時,恢複處理結束。

Archive recovery模式的standby配置下,至少配置recovery.conf的restore_command命令和primary_conninfo中的一個。該模式下可以使用歸檔日誌文件或者流複製。當沒有可用的日誌記錄時,會持續檢查並應用可用日誌,直到DBA發出promote命令。

在recovery.conf文件中,可以配置Recovery Target,使得archive recovery在指定的位置(時間、事務號或時間線)停止恢複。

PostgreSQL高可用方案中的備份與恢複

PostgreSQL高可用方案應能夠滿足介質故障恢複、實時故障切換、誤操作數據恢複和查看曆史數據的需求。

高可用環境的建立,包括以下工作:

配置主機啟動日誌歸檔和流複製主節點信息

postgres.conf(異步流複製)

wal_level=replica

archive_mode = on

archive_command = 'cp %p /mnt/server/archivedir/%f'

max_wal_senders=5 #發送wal進程數據

hot_standby=on

pg_hba.conf

host    replication     postgres        192.168.10.0/24            trust

建立備機並啟動流複製

使用basebackup工具熱備:

pg_basebackup -h 192.168.0.1 -U test -R -D /usr/local/pgsql/data

修改postgres.conf中的port和archive_command為備機端口和歸檔路徑。啟動備機,建立流複製。

以上配置下,備機恢複模式為archive recovery,開啟standby,開啟hot standby。

使用pg_rman工具為主機建立基線數據備份,並定期進行增量數據備份

  • 初始化 pg_rman init -B 備份文件保存目錄 -D 數據庫數據目錄

  • 全量備份 pg_rman backup -B 備份文件保存目錄 -D 數據庫數據目錄 -b full

  • 增量備份 pg_rman backup -B 備份文件保存目錄 -D 數據庫數據目錄 -b incremental

故障處理流程:

(1)在環境中配置狀態監控工具,實時監控主機狀態,主機不可用時,自動promte備機,並將數據庫訪問路由到備機。

(2)恢複曆史數據

pg_rman restore命令支持將數據恢複到指定時間、事務號和時間線參數,該命令將對應的全量數據和歸檔日誌拷貝到相應目錄,並配置recovery.conf文件。
pg_rman restore執行完成後,啟動PostgresSQL,進行恢複。

以上配置下,備機恢複模式為archive recovery,關閉standby,開啟hot standby。

結尾

通過梳理PostgreSQL數據庫備份與恢複流程的相關文件、參數配置與主要流程,對恢複方式進行了分類,給出高可用方案中備份與恢複的基本配置。完整的可用性方案中,還需要考慮主機狀態監控,數據訪問路由切換和故障主機複用等問題。


版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)

最後更新:2017-10-23 09:33:42

  上一篇:go  CentOS7安裝與配置Zabbix
  下一篇:go  [C#][MySql]統計數據表總行數函數--C#和MySQL開發