postgresql数据库的备份与恢复
生活随笔
收集整理的這篇文章主要介紹了
postgresql数据库的备份与恢复
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
和任何包含珍貴數據的東西一樣,PostgreSQL 數據庫也應該經常備份。盡管這個過程相當簡單, 但是我們還是應該理解做這件事所用的一些技巧和假設。 備份 PostgreSQL 數據有三種完全不同的方法: SQL 轉儲 文件系統級別備份 在線備份 每種備份都有自己的優點和缺點。 SQL 轉儲 SQL 轉儲的方法采用的主意是創建一個文本文件,這個文本里面都是 SQL 命令,當把這個文件回饋給服務器時,將重建與轉儲時狀態一樣的數據庫。 PostgreSQL 為這個用途提供了應用工具 pg_dump。這條命令的基本用法是: pg_dump dbname > outfile
正如你所見,pg_dump 把結果輸出到標準輸出。 我們下面就可以看到這樣做有什么好處。 pg_dump 是一個普通的 PostgreSQL 客戶端應用(盡管是個相當聰明的東西。)這就意味著你可以從任何可以訪問該數據庫的遠端主機上面進行備份工作。 但是請記住 pg_dump 不會以任何特殊權限運行。具體說來, 就是它必須要有你想備份的表的讀權限,因此,實際上你幾乎總是要成為數據庫超級用戶。 要聲明 pg_dump 應該以哪個用戶身份進行聯接,使用命令行選項 -h host 和 -p port。 缺省主機是本地主機或你的環境變量PGHOST聲明的值。 類似,缺省端口是環境變量PGPORT或(如果它不存在的話)編譯好了的缺省值。 (服務器通常有相同的缺省,所以還算方便。) 和任何其他 PostgreSQL 客戶端應用一樣, pg_dump 缺省時用與當前操作系統用戶名同名的數據庫用戶名進行聯接。 要覆蓋這個名字,要么聲明 -U 選項, 要么設置環境變量PGUSER。 請注意 pg_dump 的聯接也和普通客戶應用一樣要通過客戶認證機制。 由 pg_dump 創建的備份在內部是一致的, 也就是說,在pg_dump運行的時候對數據庫的更新將不會被轉儲。 pg_dump 工作的時候并不阻塞其他的對數據庫的操作。 (但是會阻塞那些需要排它鎖的操作,比如 VACUUM FULL。) Important: 如果你的數據庫結構依賴于 OID (比如說用做外鍵),那么你必須告訴 pg_dump 把 OID 也倒出來。 要倒 OID,可以使用 -o 命令行選項。 缺省時也不會轉儲"大對象"。如果你使用大對象,請參考 pg_dump 的命令手冊頁。 從轉儲中恢復 pg_dump 生成的文本文件可以由 psql 程序讀取。 從轉儲中恢復的常用命令是 psql dbname < infile
??? 這里的 infile 就是你給pg_dump命令的 outfile參數。這條命令不會創建數據庫 dbname,你必須在執行psql 前自己從template0創建(也就是說,用命令 createdb -T template0 dbname)。 psql 支持類似 pg_dump 的選項用以控制數據庫服務器位置和用戶名。 參閱 psql 的手冊獲取更多信息。 在開始運行恢復之前,目標庫和所有在轉儲出來的庫中擁有對象的用戶, 以及曾經在某些對象上被賦予權限的用戶都必須已經存在。 如果這些不存在,那么恢復將失敗,因為恢復過程無法把這些對象恢復成原有的所有權和/或權限。 (有時候你希望恢復權限,不過通常你不需要這么做。) 一旦完成恢復,在每個數據庫上運行 ANALYZE 是明智的舉動, 這樣優化器就有有用的統計數據了。你總是可以運行 vacuumdb -a -z 來 VACUUM ANALYZE 所有數據庫;這個等效于手工運行 VACUUM ANALYZE。 pg_dump 和 psql 可以通過管道讀寫, 這樣我們就可能從一臺主機上將數據庫目錄轉儲到另一臺主機上,比如 pg_dump -h host1 dbname | psql -h host2 dbname Important: pg_dump生成的轉儲輸出是相對于template0的。這就意味著任何 加入到template1的語言,過程等都會經由 pg_dump 轉儲。結果是,在恢復的時候,如果你使用的是客戶化的template1, 那么你必須從template0中創建空的數據庫,就象我們上面的例子那樣。 有關如何有效地向 PostgreSQL 里裝載大量數據的建議. 使用 pg_dumpall 上面的方法在備份整個數據庫集群的時候比較麻煩而且不方便。因此我們提供了 pg_dumpall 程序。 pg_dumpall 備份一個給出的集群中的每個數據庫,同時還確保保留象用戶和組這樣的全局數據狀態。 這個命令的基本用法是: pg_dumpall > outfile
生成的轉儲可以用 psql 恢復: psql template1 < infile
(實際上,你可以聲明任意現有的數據庫進行連接,但是如果你是向一個空的數據庫裝載,那么 template1 是你唯一的選擇。) 恢復pg_dumpall的轉儲的時候通常需要數據庫超級用戶權限,因為我們需要它來恢復用戶和組信息。 ? 處理大數據庫 因為 PostgreSQL 允許表的大小大于你的系統允許的最大文件大小, 可能把表轉儲到一個文件會有問題,因為生成的文件很可能比你的系統允許的最大文件大。 因為 pg_dump 輸出到標準輸出,你可以用標準的 Unix 工具繞開這個問題: 使用壓縮的轉儲. 使用你熟悉的壓縮程序,比如說 gzip。 pg_dump dbname | gzip > filename.gz
用下面命令恢復: createdb dbname
gunzip -c filename.gz | psql dbname
或者 cat filename.gz | gunzip | psql dbname 使用 split。. split 命令允許你 你用下面的方法把輸出分解成操作系統可以接受的大小。 比如,讓每個塊大小為 1 兆字節: pg_dump dbname | split -b 1m - filename
用下面命令恢復: createdb dbname
cat filename* | psql dbname 使用客戶化轉儲格式. 如果PostgreSQL是在一個安裝了zlib 壓縮庫的系統上制作的, 那么客戶化轉儲格式將在寫入輸出文件的時候壓縮數據。 它會生成和使用 gzip 類似大小的轉儲文件, 但是還附加了一個優點:你可以有選擇地恢復庫中的表。 下面的命令用客戶化轉儲格式轉儲一個數據庫: pg_dump -Fc dbname > filename
客戶化格式的轉儲不是腳本,不能用于 psql, 而是需要使用 pg_restore 轉儲。 請參考 pg_dump 和 pg_restore 的手冊獲取細節。 注意
出于向下兼容的考慮,缺省的時候 pg_dump 并不轉儲大對象。 要轉儲大對象,你必須使用客戶化或者 tar 輸出格式, 并且在 pg_dump 中使用-b選項。 參閱 pg_dump 手冊獲取詳細信息。 在 PostgreSQL 源碼樹的 contrib/pg_dumplo 路徑里也包含一個可以轉儲大對象的程序。 另一個備份的策略是直接拷貝PostgreSQL用于存放數據庫數據的文件。 tar -cf backup.tar /usr/local/pgsql/data 不過,你要受到兩個限制,令這個方法不那么實用,或者至少比 pg_dump 的方法遜色一些: 為了進行有效的備份,數據庫服務器必須被關閉。 象拒絕所有聯接這樣的折衷的方法是不行的,因為總是有一些緩沖區數據存在。 (主要因為 tar 和類似的工具在做備份的時候并不對文件系統的狀態做原子快照)。 如果你曾經深入了解了數據庫在文件系統布局的細節,你可能試圖從對應的文件或目錄里備份幾個表或者數據庫。 這樣做是沒用的,因為包含在這些文件里的信息只是部分信息。還有一半信息在提交日志文件 pg_clog/*里面,它包含所有事務的提交狀態。 只有擁有這些信息,表文件的信息才是可用的。當然,試圖只恢復表和相關的 pg_clog 數據也是徒勞的,因為這樣會把數據庫集群里的所有其他沒有用的表的信息都拿出來。 所以文件系統的備份只適用于一個數據庫集群的完整恢復。
??? 另外一個文件系統備份的方法是給數據目錄做一個"一致的快照", 條件是文件系統支持這個功能(并且你愿意相信它是實現正確的)。 典型的過程是制作一個包含數據庫的卷的"凍結快照", 然后把整個數據庫目錄(不僅僅是部分,見上文)從快照拷貝到備份設備, 然后釋放凍結快照。這樣甚至在數據庫服務器在運行的時候都可以運轉。 不過,這樣創建的備份會把數據庫文件保存在一個沒有恰當關閉數據庫服務器的狀態下; 因此,如果你在這個備份目錄下啟動數據庫服務器, 它就會認為數據庫服務器經歷過崩潰并且重放 WAL 日志。這不是個問題,只要意識到它即可(并且確信在自己的備份中包含 WAL 文件)。 如果你的數據庫分布在多個卷上(比如,數據文件和 WAL 日志在不同的磁盤上),那么可能就沒有任何方法獲取所有卷上準確的同步凍結快照。 在你新聞這樣的情況下的一致性快照的技術之前,仔細閱讀你的文件系統文檔。 最安全的方法是關閉數據庫服務器足夠長的時間,以建立所有凍結快照。 還要說明的是,文件系統備份不會比SQL轉儲小。恰在任何時候,PostgreSQL 都在集群的數據目錄的 pg_xlog/ 子目錄里維護著一套預寫日志(WAL)。 這些日志記錄著每一次對數據庫的數據文件的修改的細節。這些日志存在是為了防止崩潰:如果系統崩潰, 數據庫可以通過"重放"上次檢查點以來的日志記錄以恢復數據庫的完整性。 但是,日志的存在讓它還可以用于第三種備份數據庫的策略:我們可以組合文件系統備份與 WAL 文件的備份。 如果需要恢復,我們就恢復備份,然后重放備份了的WAL文件,把備份恢復到當前的時間。 這個方法對管理員來說,明顯比以前的方法更復雜,但是有非常明顯的優勢: 在開始的時候我們不需要一個非常完美的一致的備份。任何備份內部的不一致都會被日志重放動作修改正確 (這個和崩潰恢復時發生的事情沒什么區別)。因此我們不需要文件系統快照的功能, 只需要 tar 或者類似的歸檔工具。 因為我們可以把無限長的 WAL 文件序列連接起來,所以連續的備份簡化為連續地對 WAL 文件歸檔來實現。 這個功能對大數據庫特別有用,因為大數據庫的全備份可能并不方便。 我們可沒說重放 WAL 記錄的時候我們必須重放到結尾。我們可以在任意點停止重放, 這樣就有一個在任意時間的數據庫一致的快照。因此,這個技術支持即時恢復: 我們可以把數據庫恢復到你開始備份以來的任意時刻的狀態。 如果我們持續把 WAL 文件序列填充給其它裝載了同樣的基礎備份文件的機器, 我們就有了一套"熱備份"系統:在任何點我們都可以啟動第二臺機器, 而它擁有近乎當前的數據庫拷貝。
??? 和簡單的文件系統備份技術一樣,這個方法只能支持整個數據庫集群的恢復,而不是一個子集。 同樣,它還要求大量的歸檔存儲:基礎備份量可能很大,而且忙碌的系統將生成許多兆需要備份的的 WAL 流量。 但是,它仍然時在需要高可靠性的場合下的最好的備份技術。 要想從在線備份中成功恢復,你需要一套連續的 WAL 歸檔文件,它們最遠回朔到你開始備份的時刻。 因此,要想開始備份,你應該在開始第一次基礎備份之前設置并測試你的步驟。 根據我們討論過的歸檔 WAL 文件的機制。 1. 設置 WAL 歸檔 抽象來看,一個運行著的 PostgreSQL 系統生成一個無限長的 WAL 日志序列。 系統物理上把這個序列分隔成 WAL段文件,通常一塊時 16M 字節大 (在制作 PostgreSQL 的時候可以改變其大小)。 這些段文件的名字是數值命名的,這些數值反映他們在抽取出來的 WAL 序列中的位置。 在不適用 WAL 歸檔的時候,系統通常只是創建幾個段文件然后"循環"使用它們, 方法是把不再使用的段文件的名字重命名為更高的段編號。 系統假設那些內容比前一次檢查點更老的段文件是沒用的了,然后就可以循環利用。 在歸檔 WAL 數據的時候,我們希望在每個段文件填充滿之后捕獲之, 并且把這些數據在段文件被循環利用之前保存在某處。根據應用以及可用的硬件的不同, 我們可以有許多不同的方法"把數據保存在某處": 我們可以把段文件拷貝到一個 NFS 裝配的目錄,把它們放到另外一臺機器上, 或者把它們寫入磁帶機里(需要保證你有辦法把文件恢復為原名), 或者把它們打成包,燒錄到 CD 里,或者是其它的什么方法。 為了給數據庫管理員提供最大可能性的靈活性,PostgreSQL 試圖不對如何歸檔做任何假設。取而代之的是,PostgreSQL 讓管理員聲明一個 shell 命令執行來拷貝一個完整的段文件到它需要去的地方。 該命令可以簡單得就是一個 cp,或者它可以調用一個復雜的 shell 腳本 — 所有都由管理員決定。 所使用的 shell 命令由配置參數 archive_command 聲明, 它實際上總是放在 postgresql.conf 文件里的。 在這個字串里,任何 %p 都被要歸檔的文件的絕對路徑代替,而任何 %f 只是被文件名代替。 如果你需要在命令里嵌入一個真正的 %,寫 %%。 最簡單的有用命令是類似下面這樣的 archive_command = 'cp -i %p /mnt/server/archivedir/%f </dev/null'
它將把 WAL 段拷貝到目錄 /mnt/server/archivedir。 這個只是一個例子,并非我們建議的方法,可能不能在所有系統上都正確運行。 歸檔命令將在運行 PostgreSQL 服務器的同一個用戶的權限下執行。 因此被歸檔的 WAL 文件實際上包含你的數據庫里的所有東西,所以你應該確保自己的歸檔數據不會被別人窺探; 比如,歸檔到一個沒有組或者全局讀權限的目錄里。 有一點很重要:當且僅當歸檔命令成功時,它才返回零。在得到一個零值結果之后, PostgreSQL 將假設該 WAL 段文件已經成功歸檔, 因此它稍后將被刪除或者被新的數據覆蓋。但是,一個非零值告訴 PostgreSQL 該文件沒有被歸檔; 因此它會周期性的重試直到成功。 歸檔命令通常應該設計成拒絕覆蓋已經存在的歸檔文件。這是一個非常重要的安全特性, 可以在管理員操作失誤(比如把兩個不同的服務器的輸出發送到同一個歸檔目錄)的時候保持你的歸檔的完整性。 我們建議你首先要測試你準備使用到歸檔命令,以保證它實際上不會覆蓋現有的文件, 并且在這種情況下它返回非零狀態。 我們發現,在這方面, cp -i 在某些平臺上是正確的,而在其它平臺上是不正確的。 如果選定的命令本身并不能正確處理這個問題,你應該增加一個命令預先探測歸檔文件是否存在。 比如,類似下面的東西。 archive_command = 'test ! -f .../%f && cp %p .../%f'
在幾乎所有的 Unix 變種上都工作正確。 在設計你的歸檔環境都時候,請考慮一下如果歸檔命令不停失敗會發生什么情況, 因為有些方面要求操作者的干涉,或者是歸檔空間不夠了。 比如,如果你往磁帶機上寫,但是沒有自動換帶機,那么就有可能發生這種情況; 如果磁帶滿了,那就除非換磁帶,否則啥事也做不了。 你應該確保人和錯誤條件或者人和要求操作員干涉帶錯誤都會正確報告, 這樣才能迅速解決這些問題。否則 pg_xlog/ 目錄會不停地填充 WAL 段文件, 直到問題解決。 歸檔命令的速度并不要緊,只要它能跟上你的服務器生成 WAL 數據的平均速度即可。 即使歸檔進程落在了后面一點,正常的操作也會繼續進行。 如果歸檔進程慢很多,就會增加災難發生的時候丟失的數據量。 同時也意味著 pg_xlog/ 目錄包含大量未歸檔的日志段文件, 并且可能最后超出了磁盤空間。我們建議你監控歸檔進程,確保它是按照你的意識運轉的。 如果你關心能夠恢復到當前即時的狀態,你可能需要采取幾個額外的步驟以確保當前的, 部分填充的 WAL 段也拷貝到了某些地方。這條對于生成很少 WAL 流量的服務器 (或者在運行中有松弛階段的)特別重要,因為在一個 WAL 段文件完全填充滿進而可以歸檔之前, 可能需要很長時間。一個處理這些的可能的方法是設置一個 cron 作業, 周期性(比如每分鐘一次)地標識當前 WAL 段文件然后把它們保存到某個安全的地方。 歸檔的 WAL 段和保存的當前段就足夠保證你可以總是恢復到當前時間的一分鐘之內。 這個行為目前還不是內置于 PostgreSQL 的,因為我們不想把 archive_command 的定義復雜化,因為那樣就要要求它跟蹤成功歸檔但是卻又有不同時刻含義的同一個 WAL 文件。 archive_command 只是用于處理那些不再改變的 WAL 段文件; 除了錯誤重試之外,對于任何給出的文件名他都只被調用一次。 在寫自己的歸檔命令的時候,你應該假設被歸檔的文件最多 64 個字符長并且可以包含 ASCII 字母,數字,以及點的任意組合。 我們不必要記住原始的全路徑(%p),但是有必要記住文件名(%f)。 請注意盡管 WAL 歸檔允許你回復任何對你的 PostgreSQL 數據庫的數據做的修改, 在最初的基礎備份之后,它還是不會回復對配置文件的修改(也就是說,postgresql.conf,pg_hba.conf 和 pg_ident.conf),因為這些文件都是手工編輯的,而不是通過 SQL 操作來編輯的。 所以你可能會需要把你的配置文件放在一個日常文件系統備份過程即可處理到的地方。 2. 進行一次基礎備份
??? 進行基礎備份的過程相當簡單: 確保 WAL 歸檔打開并且可以運轉。 以數據庫超級用戶身份連接到數據庫,發出命令 SELECT pg_start_backup('label');
??? 這里的 label 是任意你想使用的這次備份操作的唯一標識。 (一個好習慣是使用你想把備份轉儲文件放置的目的地的全路徑。) pg_start_backup 用你的備份的信息,在你的集群目錄里,創建一個備份標簽文件, 叫做 backup_label。 至于你連接到集群中的那個數據庫沒什么關系。你可以忽略函數返回的結果; 但是如果它報告錯誤,那么在繼續之前處理它。 執行備份,使用任何方便的文件系統工具,比如 tar 或者 cpio。 這些操作過程中既不需要關閉數據庫,也不希望關閉數據庫的操作。 再次以數據庫超級用戶身份連接數據庫,然后發出命令 SELECT pg_stop_backup();
如果這個返回成功,你的工作就完成了。
??? 我們不需要太關心在 pg_start_backup 和開始實際的備份之間開銷的時間, 也不需要太關心備份結束和 pg_stop_backup 之間的時間; 幾分鐘的延遲不會搞砸事情。不過,你必須確保這些操作是按順序執行的而不是重疊執行的。 要保證你的備份轉儲包括所有數據庫集群目錄里的文件(比如,/usr/local/pgsql/data)。 如果你在使用并未放置在這個目錄里的表空間,也要小心地包含它們 (并且要確保你的備份轉儲歸檔符號連接是符號連接,否則,恢復會把你的表空間搞亂)。 不過,你可以在備份轉儲文件里省略集群目錄里的 pg_xlog/ 子目錄。 這個略微復雜些的動作是值得的,因為它減少了恢復的時候的錯誤。 如果 pg_xlog/ 是一個指向集群目錄之外的一個符號連接,那么這件事情很容易處理, 出于性能考慮的時候經常這么做。 要使用這個備份,你需要保存所有備份開始以及之后的 WAL 段文件。 為了幫助你實現這個任務,pg_stop_backup 函數創建一個備份歷史文件, 它馬上存儲到 WAL 歸檔區域。這個文件的名字是以你在使用備份的時候需要的第一個 WAL 段文件的名字命名的。 比如,如果開始 WAL 文件是 0000000100001234000055CD,那么備份歷史文件將命名為類似 0000000100001234000055CD.007C9330.backup 這樣的東西。 (這個文件名的第二部分表示在該 WAL 文件里面的準確位置,通??梢员缓雎?。) 一旦你安全地把備份轉儲文件歸了檔,那么你就可以刪除所有那些數值名字在這個文件前面的歸檔的 WAL 段。 備份歷史文件只是一個小的文本文件。它包含你給予 pg_start_backup 的標簽字串, 以及備份的起始時間和終止時間。如果你使用這個標簽來表示轉儲文件放在哪里, 如果需要的話,那么歸檔的歷史文件就足夠告訴你轉儲文件存放在哪里了。 因為你必須保留直到你最后一次基礎備份的所有歸檔的 WAL 文件, 那么兩次基礎備份之間的間隔通常是根據你想在歸檔 WAL 文件上花多少存儲空間來定的。 你還應該考慮你準備在恢復上花多少時間,如果需要恢復的話 — 系統將需要重放所有那些段, 而如果最后一次基礎備份以來,時間已經很長了,那么那些動作可能會花掉好些時間。 還有一件事值得一提,那就是 pg_start_backup 函數在數據庫集群目錄里創建了一個叫 backup_label 的文件,它被 pg_stop_backup 刪除。 這個文件當然也會作為你的備份轉儲文件的一部分歸檔。這個備份標簽文件包含你給予 pg_start_backup 的標簽字串, 以及 pg_start_backup 運行的時刻,以及起始 WAL 文件的名字。 如果有混淆,那么我們可以看看備份轉儲文件里面然后判斷轉儲文件來自那個備份會話。 我們還可以在 postmaster 停止的時候制作一個備份轉儲。 在這種條件下,很明顯你不能使用 pg_start_backup 或者 pg_stop_backup, 并且因此你必須靠自己的手段來跟蹤備份轉儲文件都是那些,以及相關的 WAL 文件最遠走到哪里。 通常使用上面的在線備份步驟更好些。 3. 從在線備份中恢復 好,最糟糕的事情發生了,現在你需要從備份中恢復。下面是步驟:
??? 停止 postmaster,如果它還在運行的話。 如果你還有足夠的空間,把整個集群數據目錄和所有表空間拷貝到一個臨時位置, 以防萬一你之后還需要它們。請注意這個預防措施要求你在系統里又足夠的剩余空間來現有庫的保持兩份拷貝。 如果你沒有足夠的空間,那么你至少需要把集群數據目錄的 pg_xlog 子目錄的內容拷貝到安全的地方, 因為它們可能包含系統宕掉的時候還沒有歸檔的日志。 然后清理掉所有在該集群數據目錄里的現存文件, 以及所有你使用的表空間里根目錄下的現存文件。 從你的備份轉儲中恢復數據庫文件。要小心用正確的所有者(數據庫系統用戶,而不是 root!)和權限恢復它們。 如果你使用了表空間,你可能需要核實在 pg_tblspc/ 里的符號連接都得到正確恢復。 刪除任何目前還在 pg_xlog/ 里的文件;這些文件來自備份轉儲,因此它們可能比目前的老。 如果你就根本沒有歸檔 pg_xlog/,那么重建之,要注意也要重建子目錄 pg_xlog/archive_status/。 如果你有在步驟 2 里面保存的 WAL 段文件,那么把它們拷貝到 pg_xlog/。 (最好是拷貝它們,而不是把它們移動回來,這樣即使發生了糟糕的事情,你需要重啟的時候, 你也依然擁有未修改的文件。) 在集群數據目錄里創建一個恢復命令文件 recovery.conf(參閱 Recovery Settings)。 你可能還需要臨時修改 pg_hba.conf 以避免普通用戶連接,直到你確信恢復已經正常了為止。 啟動 postmaster。postmaster 將進入恢復模式并且繼續讀取它需要的歸檔的 WAL 文件。 在恢復過程完成后,postmaster 將把 recovery.conf 改名為 recovery.done (以避免不小心因后面的崩潰再次進入恢復模式)然后開始正常的數據庫操作。 檢查數據庫的內容以確保你已經恢復到你期望的位置。 如果還沒有,回到步驟 1。如果全部正常,則恢復 pg_hba.conf 成正常狀態,允許你的用戶登錄。
???? 所有這些操作的關鍵部分時設置一個恢復命令文件, 這個文件描述你希望如何恢復以及恢復應該走到哪里。 你可以使用 recovery.conf.sample(通常安裝在安裝目錄的 share/ 子目錄里)作為原型。 你必須在 recovery.conf 里面聲明的一個東西是 restore_command, 它告訴系統如何拿回歸檔的 WAL 文件段。類似 archive_command, 這個是一個腳本命令字串。它可以包含 %f,這個變量會被需要的日志文件名替換, 以及 %p,它會被要拷貝去的日志文件的絕對路徑代替。 如果需要在命令里替換真正的 %,寫 %%。 最簡單的有用命令是類似下面的東西 restore_command = 'cp /mnt/server/archivedir/%f %p'
這個命令將把以前歸檔的 WAL 段從目錄 /mnt/server/archivedir 拷貝過來。 你當然可以使用某些更復雜的東西,甚至是一個要求操作者裝配合適的磁帶的 shell 腳本。 重要的一點是:該命令在失敗的時候返回非零值。如果日志文件沒有出現在規檔中,那么該系統將詢問該命令; 在問到的時候,它必須返回非零。這個不是錯誤條件。還要注意 %p 路徑的基礎名將和 %f 不一樣; 不要認為它們是可以互換的。 在歸檔中找不到的 WAL 段將被認為在 pg_xlog/ 里;這樣就允許使用最近沒有歸檔的段。 但是在歸檔中的段將比 pg_xlog/ 中的優先。在檢索歸檔的文件的時候,系統將不會覆蓋現有的 pg_xlog/ 內容。 通常,恢復將處理所有可用的 WAL 段,因此把數據庫恢復到當前時間(或者是在所給出的可用 WAL 段數目的情況下, 我們能走到的最近的地方)。但是如果你想恢復到某些以前的時刻點(比如,就在菜鳥 DBA 刪除你的主要事務表之前), 那么只需要在 recovery.conf 里聲明要求的停止點。你可以通過日期/時間來聲明, 也可以通過特定事務 ID 的結束來聲明這個停止點,我們叫做"恢復目標"。 在我們寫到這些的時候,只有日期/時間選項比較有用, 因為我們沒有工具來幫助你精確地標識應該使用哪個事務 ID。 注意: 請注意停止點必須在備份的終止時間之后(也就是,pg_stop_backup 的時間)。 你無法使用一個基礎備份恢復到備份正在進行中的某個時刻。 (要想恢復到該時刻,你必須回到你以前的基礎備份,然后從那個位置向前滾動。) 3.1. 恢復設置 這些設置只能在 recovery.conf 里面使用,并且只是在恢復的過程中起作用。 在任何之后的恢復中,你必須重新設置他們?;謴瓦^程開始后,它們的值無法改變。 restore_command (string)
??? 執行檢索歸檔 WAL 文件段序列的 shell 命令。這個參數是必須的。 字串中的任何 %f 都被從歸檔中檢索出來的文件名替換, 而任何 %p 都被替換為拷貝過去的服務器上的絕對路徑。 需要在命令里嵌入真正的 % 字符時,寫 %%。 有一點很重要,那就是這個命令只有在成功的時候才返回零。 系統會向這條命令詢問沒有在歸檔里出現的文件名; 在這種情況下,它必須返回非零。比如: restore_command = 'cp /mnt/server/archivedir/%f "%p"'
restore_command = 'copy /mnt/server/archivedir/%f "%p"'? # Windows recovery_target_time (timestamp)
這個參數聲明恢復執行到達的時間戳。最多可以聲明一個 recovery_target_time 或 recovery_target_xid。缺省是恢復到 WAL 日志的結尾。 精確的停止點也受 recovery_target_inclusive 影響。 recovery_target_xid (string)
這個參數聲明恢復將到達的事務 ID。要注意的是,盡管事務 ID 在事務開始的時候是認為順序的, 但是事務可以以不同的數值順序完成。將要恢復的事務是那些在聲明的這個事務之前(可以選擇包括它提交的時候的)提交的。 最多可以聲明一個 recovery_target_xid 或 recovery_target_time。 缺省是恢復到 WAL 日志的結尾。精確的停止點也受 recovery_target_inclusive 影響。 recovery_target_inclusive (boolean)
聲明我們是否在恢復目標之后(true),還是正好在其之前(false)停止。 適用于 recovery_target_time 和 recovery_target_xid, 不管聲明的是哪個。它分別表示具有準確的提交時間或者 ID 的那些(個)事務,是否將包含在恢復之中。 缺省是 true。 recovery_target_timeline (string)
聲明恢復到一個特定的時間線。缺省是恢復到進行基礎備份時的當時的當前時間線上。 只是在復雜的重新恢復的情況下,你才需要設置這個參數,也就是在你需要恢復到一個本身是在即時恢復之后到達的狀態下, 才需要這么做。 參閱 Section 22.3.4 進行討論。 4. 時間線
?
??? 能夠把數據庫恢復到以前的某個時間點的能力導致了一些類似科幻小說里的時間跟蹤和并行宇宙這樣的復雜情況。 在數據庫的最初的歷史里,可能你在周二下午 5:15 刪除掉了一個非常關鍵的表。 然后有條不紊地拿出備份,恢復到周二晚上 5:14 即時備份。在這個數據庫宇宙的歷史里, 你從來沒有刪除過那個表。但是假如你后來認識到這么干并非絕好的主意,并且想回到最初的歷史中的稍后的點。 你沒法這么干,因為在數據庫運行的時候,它覆蓋了一些 WAL 段文件的序列,這些序列就是在你希望回去的區間里的。 因此你的確需要區分在你從那些原始數據庫歷史生成的 WAL 中完成即時恢復之后生成的 WAL 序列。 為了處理這些問題,PostgreSQL 有個叫時間線的概念。 每次你即時恢復到一個比 WAL 序列的結尾要早的時刻,那么就創建一個新的時間線, 以表示在該次恢復之后生成的 WAL 記錄。(不過,如果恢復動作一尺處理到 WAL 的結尾, 我們就不會開始一個新的時間線:我們只是擴展現有個那個。)時間線 ID 號是 WAL 段文件名的一部分, 因此新的時間線并不會覆蓋以前的時間線生成的 WAL 數據。實際上我們可以歸檔許多不同的時間線。 雖然這些看起來像沒用的特性,但它卻可能常常是救命稻草。考慮一下你并不很確信應該恢復到那個時刻的情況, 這個時候你不得不做好幾次試驗性即時恢復然后從中找到舊歷史中最好的分支。 如果沒有時間線,那么這個過程可能很快就會導致無法管理的混亂。 有了時間線,你可以恢復到任意以前的狀態, 包括恢復到你后來放棄的時間線分支的狀態。 每當創建一個新的時間線的時候,PostgreSQL 都創建一個"時間線歷史"文件, 它顯示自己從那個時間線分出來,以及何時分出來的。這些歷史文件是在從包含多個時間線的規黨中進行恢復時, 允許系統選取正確的 WAL 段文件的必要文件。因此,它們像 WAL 段文件一樣歸檔到 WAL 歸檔里。 歷史文件只是很小的文本文件(不想段文件很大),所以獨立地保存他們代價很小,也值得做。 如果你喜歡,你可以在歷史文件里加入注釋,錄自己為什么設置一個時間線以及如何設置的等信息。 這樣的注釋會在你有厚厚一堆不同的時間線需要選擇和分析的時候特別有價值。 恢復的缺省的行為時沿著與備份基礎備份的同一個時間線恢復。 如果你像恢復到某些子時間線(也就是,你想回到某些本身就是在開始恢復企圖之后發生的狀態), 你需要在 recovery.conf 里聲明目標時間線 ID。你無法恢復到比基礎備份更早的時間線分支。 5. 注意
??? 在我們寫到這些的時候,在線備份技術還有幾個局限。它們可能在將來的版本中修補: 在非 B-tree 索引上的操作(散列,R-tree,和 GiST 索引)目前沒有用 WAL 記錄日志, 所以重放就不會更新這些索引類型。我們建議的繞開方法是在完成恢復操作之后手工 REINDEX 每個這樣的索引。
??? 還要注意,目前的 WAL 格式占地非常大,因為它包含許多磁盤影像。 這么做對于崩潰恢復用途是合適的,因為我們可能需要修補部分寫入的磁盤頁。 但是對 PITR 操作卻沒必要存儲如此多頁面。將來開發的一個方面就是通過刪除無用的頁拷貝來壓縮歸檔的 WAL 數據。恰相反,大多數情況下它要大。 (比如pg_dump 不用倒出索引,只是創建它們的命令。)
正如你所見,pg_dump 把結果輸出到標準輸出。 我們下面就可以看到這樣做有什么好處。 pg_dump 是一個普通的 PostgreSQL 客戶端應用(盡管是個相當聰明的東西。)這就意味著你可以從任何可以訪問該數據庫的遠端主機上面進行備份工作。 但是請記住 pg_dump 不會以任何特殊權限運行。具體說來, 就是它必須要有你想備份的表的讀權限,因此,實際上你幾乎總是要成為數據庫超級用戶。 要聲明 pg_dump 應該以哪個用戶身份進行聯接,使用命令行選項 -h host 和 -p port。 缺省主機是本地主機或你的環境變量PGHOST聲明的值。 類似,缺省端口是環境變量PGPORT或(如果它不存在的話)編譯好了的缺省值。 (服務器通常有相同的缺省,所以還算方便。) 和任何其他 PostgreSQL 客戶端應用一樣, pg_dump 缺省時用與當前操作系統用戶名同名的數據庫用戶名進行聯接。 要覆蓋這個名字,要么聲明 -U 選項, 要么設置環境變量PGUSER。 請注意 pg_dump 的聯接也和普通客戶應用一樣要通過客戶認證機制。 由 pg_dump 創建的備份在內部是一致的, 也就是說,在pg_dump運行的時候對數據庫的更新將不會被轉儲。 pg_dump 工作的時候并不阻塞其他的對數據庫的操作。 (但是會阻塞那些需要排它鎖的操作,比如 VACUUM FULL。) Important: 如果你的數據庫結構依賴于 OID (比如說用做外鍵),那么你必須告訴 pg_dump 把 OID 也倒出來。 要倒 OID,可以使用 -o 命令行選項。 缺省時也不會轉儲"大對象"。如果你使用大對象,請參考 pg_dump 的命令手冊頁。 從轉儲中恢復 pg_dump 生成的文本文件可以由 psql 程序讀取。 從轉儲中恢復的常用命令是 psql dbname < infile
??? 這里的 infile 就是你給pg_dump命令的 outfile參數。這條命令不會創建數據庫 dbname,你必須在執行psql 前自己從template0創建(也就是說,用命令 createdb -T template0 dbname)。 psql 支持類似 pg_dump 的選項用以控制數據庫服務器位置和用戶名。 參閱 psql 的手冊獲取更多信息。 在開始運行恢復之前,目標庫和所有在轉儲出來的庫中擁有對象的用戶, 以及曾經在某些對象上被賦予權限的用戶都必須已經存在。 如果這些不存在,那么恢復將失敗,因為恢復過程無法把這些對象恢復成原有的所有權和/或權限。 (有時候你希望恢復權限,不過通常你不需要這么做。) 一旦完成恢復,在每個數據庫上運行 ANALYZE 是明智的舉動, 這樣優化器就有有用的統計數據了。你總是可以運行 vacuumdb -a -z 來 VACUUM ANALYZE 所有數據庫;這個等效于手工運行 VACUUM ANALYZE。 pg_dump 和 psql 可以通過管道讀寫, 這樣我們就可能從一臺主機上將數據庫目錄轉儲到另一臺主機上,比如 pg_dump -h host1 dbname | psql -h host2 dbname Important: pg_dump生成的轉儲輸出是相對于template0的。這就意味著任何 加入到template1的語言,過程等都會經由 pg_dump 轉儲。結果是,在恢復的時候,如果你使用的是客戶化的template1, 那么你必須從template0中創建空的數據庫,就象我們上面的例子那樣。 有關如何有效地向 PostgreSQL 里裝載大量數據的建議. 使用 pg_dumpall 上面的方法在備份整個數據庫集群的時候比較麻煩而且不方便。因此我們提供了 pg_dumpall 程序。 pg_dumpall 備份一個給出的集群中的每個數據庫,同時還確保保留象用戶和組這樣的全局數據狀態。 這個命令的基本用法是: pg_dumpall > outfile
生成的轉儲可以用 psql 恢復: psql template1 < infile
(實際上,你可以聲明任意現有的數據庫進行連接,但是如果你是向一個空的數據庫裝載,那么 template1 是你唯一的選擇。) 恢復pg_dumpall的轉儲的時候通常需要數據庫超級用戶權限,因為我們需要它來恢復用戶和組信息。 ? 處理大數據庫 因為 PostgreSQL 允許表的大小大于你的系統允許的最大文件大小, 可能把表轉儲到一個文件會有問題,因為生成的文件很可能比你的系統允許的最大文件大。 因為 pg_dump 輸出到標準輸出,你可以用標準的 Unix 工具繞開這個問題: 使用壓縮的轉儲. 使用你熟悉的壓縮程序,比如說 gzip。 pg_dump dbname | gzip > filename.gz
用下面命令恢復: createdb dbname
gunzip -c filename.gz | psql dbname
或者 cat filename.gz | gunzip | psql dbname 使用 split。. split 命令允許你 你用下面的方法把輸出分解成操作系統可以接受的大小。 比如,讓每個塊大小為 1 兆字節: pg_dump dbname | split -b 1m - filename
用下面命令恢復: createdb dbname
cat filename* | psql dbname 使用客戶化轉儲格式. 如果PostgreSQL是在一個安裝了zlib 壓縮庫的系統上制作的, 那么客戶化轉儲格式將在寫入輸出文件的時候壓縮數據。 它會生成和使用 gzip 類似大小的轉儲文件, 但是還附加了一個優點:你可以有選擇地恢復庫中的表。 下面的命令用客戶化轉儲格式轉儲一個數據庫: pg_dump -Fc dbname > filename
客戶化格式的轉儲不是腳本,不能用于 psql, 而是需要使用 pg_restore 轉儲。 請參考 pg_dump 和 pg_restore 的手冊獲取細節。 注意
出于向下兼容的考慮,缺省的時候 pg_dump 并不轉儲大對象。 要轉儲大對象,你必須使用客戶化或者 tar 輸出格式, 并且在 pg_dump 中使用-b選項。 參閱 pg_dump 手冊獲取詳細信息。 在 PostgreSQL 源碼樹的 contrib/pg_dumplo 路徑里也包含一個可以轉儲大對象的程序。 另一個備份的策略是直接拷貝PostgreSQL用于存放數據庫數據的文件。 tar -cf backup.tar /usr/local/pgsql/data 不過,你要受到兩個限制,令這個方法不那么實用,或者至少比 pg_dump 的方法遜色一些: 為了進行有效的備份,數據庫服務器必須被關閉。 象拒絕所有聯接這樣的折衷的方法是不行的,因為總是有一些緩沖區數據存在。 (主要因為 tar 和類似的工具在做備份的時候并不對文件系統的狀態做原子快照)。 如果你曾經深入了解了數據庫在文件系統布局的細節,你可能試圖從對應的文件或目錄里備份幾個表或者數據庫。 這樣做是沒用的,因為包含在這些文件里的信息只是部分信息。還有一半信息在提交日志文件 pg_clog/*里面,它包含所有事務的提交狀態。 只有擁有這些信息,表文件的信息才是可用的。當然,試圖只恢復表和相關的 pg_clog 數據也是徒勞的,因為這樣會把數據庫集群里的所有其他沒有用的表的信息都拿出來。 所以文件系統的備份只適用于一個數據庫集群的完整恢復。
??? 另外一個文件系統備份的方法是給數據目錄做一個"一致的快照", 條件是文件系統支持這個功能(并且你愿意相信它是實現正確的)。 典型的過程是制作一個包含數據庫的卷的"凍結快照", 然后把整個數據庫目錄(不僅僅是部分,見上文)從快照拷貝到備份設備, 然后釋放凍結快照。這樣甚至在數據庫服務器在運行的時候都可以運轉。 不過,這樣創建的備份會把數據庫文件保存在一個沒有恰當關閉數據庫服務器的狀態下; 因此,如果你在這個備份目錄下啟動數據庫服務器, 它就會認為數據庫服務器經歷過崩潰并且重放 WAL 日志。這不是個問題,只要意識到它即可(并且確信在自己的備份中包含 WAL 文件)。 如果你的數據庫分布在多個卷上(比如,數據文件和 WAL 日志在不同的磁盤上),那么可能就沒有任何方法獲取所有卷上準確的同步凍結快照。 在你新聞這樣的情況下的一致性快照的技術之前,仔細閱讀你的文件系統文檔。 最安全的方法是關閉數據庫服務器足夠長的時間,以建立所有凍結快照。 還要說明的是,文件系統備份不會比SQL轉儲小。恰在任何時候,PostgreSQL 都在集群的數據目錄的 pg_xlog/ 子目錄里維護著一套預寫日志(WAL)。 這些日志記錄著每一次對數據庫的數據文件的修改的細節。這些日志存在是為了防止崩潰:如果系統崩潰, 數據庫可以通過"重放"上次檢查點以來的日志記錄以恢復數據庫的完整性。 但是,日志的存在讓它還可以用于第三種備份數據庫的策略:我們可以組合文件系統備份與 WAL 文件的備份。 如果需要恢復,我們就恢復備份,然后重放備份了的WAL文件,把備份恢復到當前的時間。 這個方法對管理員來說,明顯比以前的方法更復雜,但是有非常明顯的優勢: 在開始的時候我們不需要一個非常完美的一致的備份。任何備份內部的不一致都會被日志重放動作修改正確 (這個和崩潰恢復時發生的事情沒什么區別)。因此我們不需要文件系統快照的功能, 只需要 tar 或者類似的歸檔工具。 因為我們可以把無限長的 WAL 文件序列連接起來,所以連續的備份簡化為連續地對 WAL 文件歸檔來實現。 這個功能對大數據庫特別有用,因為大數據庫的全備份可能并不方便。 我們可沒說重放 WAL 記錄的時候我們必須重放到結尾。我們可以在任意點停止重放, 這樣就有一個在任意時間的數據庫一致的快照。因此,這個技術支持即時恢復: 我們可以把數據庫恢復到你開始備份以來的任意時刻的狀態。 如果我們持續把 WAL 文件序列填充給其它裝載了同樣的基礎備份文件的機器, 我們就有了一套"熱備份"系統:在任何點我們都可以啟動第二臺機器, 而它擁有近乎當前的數據庫拷貝。
??? 和簡單的文件系統備份技術一樣,這個方法只能支持整個數據庫集群的恢復,而不是一個子集。 同樣,它還要求大量的歸檔存儲:基礎備份量可能很大,而且忙碌的系統將生成許多兆需要備份的的 WAL 流量。 但是,它仍然時在需要高可靠性的場合下的最好的備份技術。 要想從在線備份中成功恢復,你需要一套連續的 WAL 歸檔文件,它們最遠回朔到你開始備份的時刻。 因此,要想開始備份,你應該在開始第一次基礎備份之前設置并測試你的步驟。 根據我們討論過的歸檔 WAL 文件的機制。 1. 設置 WAL 歸檔 抽象來看,一個運行著的 PostgreSQL 系統生成一個無限長的 WAL 日志序列。 系統物理上把這個序列分隔成 WAL段文件,通常一塊時 16M 字節大 (在制作 PostgreSQL 的時候可以改變其大小)。 這些段文件的名字是數值命名的,這些數值反映他們在抽取出來的 WAL 序列中的位置。 在不適用 WAL 歸檔的時候,系統通常只是創建幾個段文件然后"循環"使用它們, 方法是把不再使用的段文件的名字重命名為更高的段編號。 系統假設那些內容比前一次檢查點更老的段文件是沒用的了,然后就可以循環利用。 在歸檔 WAL 數據的時候,我們希望在每個段文件填充滿之后捕獲之, 并且把這些數據在段文件被循環利用之前保存在某處。根據應用以及可用的硬件的不同, 我們可以有許多不同的方法"把數據保存在某處": 我們可以把段文件拷貝到一個 NFS 裝配的目錄,把它們放到另外一臺機器上, 或者把它們寫入磁帶機里(需要保證你有辦法把文件恢復為原名), 或者把它們打成包,燒錄到 CD 里,或者是其它的什么方法。 為了給數據庫管理員提供最大可能性的靈活性,PostgreSQL 試圖不對如何歸檔做任何假設。取而代之的是,PostgreSQL 讓管理員聲明一個 shell 命令執行來拷貝一個完整的段文件到它需要去的地方。 該命令可以簡單得就是一個 cp,或者它可以調用一個復雜的 shell 腳本 — 所有都由管理員決定。 所使用的 shell 命令由配置參數 archive_command 聲明, 它實際上總是放在 postgresql.conf 文件里的。 在這個字串里,任何 %p 都被要歸檔的文件的絕對路徑代替,而任何 %f 只是被文件名代替。 如果你需要在命令里嵌入一個真正的 %,寫 %%。 最簡單的有用命令是類似下面這樣的 archive_command = 'cp -i %p /mnt/server/archivedir/%f </dev/null'
它將把 WAL 段拷貝到目錄 /mnt/server/archivedir。 這個只是一個例子,并非我們建議的方法,可能不能在所有系統上都正確運行。 歸檔命令將在運行 PostgreSQL 服務器的同一個用戶的權限下執行。 因此被歸檔的 WAL 文件實際上包含你的數據庫里的所有東西,所以你應該確保自己的歸檔數據不會被別人窺探; 比如,歸檔到一個沒有組或者全局讀權限的目錄里。 有一點很重要:當且僅當歸檔命令成功時,它才返回零。在得到一個零值結果之后, PostgreSQL 將假設該 WAL 段文件已經成功歸檔, 因此它稍后將被刪除或者被新的數據覆蓋。但是,一個非零值告訴 PostgreSQL 該文件沒有被歸檔; 因此它會周期性的重試直到成功。 歸檔命令通常應該設計成拒絕覆蓋已經存在的歸檔文件。這是一個非常重要的安全特性, 可以在管理員操作失誤(比如把兩個不同的服務器的輸出發送到同一個歸檔目錄)的時候保持你的歸檔的完整性。 我們建議你首先要測試你準備使用到歸檔命令,以保證它實際上不會覆蓋現有的文件, 并且在這種情況下它返回非零狀態。 我們發現,在這方面, cp -i 在某些平臺上是正確的,而在其它平臺上是不正確的。 如果選定的命令本身并不能正確處理這個問題,你應該增加一個命令預先探測歸檔文件是否存在。 比如,類似下面的東西。 archive_command = 'test ! -f .../%f && cp %p .../%f'
在幾乎所有的 Unix 變種上都工作正確。 在設計你的歸檔環境都時候,請考慮一下如果歸檔命令不停失敗會發生什么情況, 因為有些方面要求操作者的干涉,或者是歸檔空間不夠了。 比如,如果你往磁帶機上寫,但是沒有自動換帶機,那么就有可能發生這種情況; 如果磁帶滿了,那就除非換磁帶,否則啥事也做不了。 你應該確保人和錯誤條件或者人和要求操作員干涉帶錯誤都會正確報告, 這樣才能迅速解決這些問題。否則 pg_xlog/ 目錄會不停地填充 WAL 段文件, 直到問題解決。 歸檔命令的速度并不要緊,只要它能跟上你的服務器生成 WAL 數據的平均速度即可。 即使歸檔進程落在了后面一點,正常的操作也會繼續進行。 如果歸檔進程慢很多,就會增加災難發生的時候丟失的數據量。 同時也意味著 pg_xlog/ 目錄包含大量未歸檔的日志段文件, 并且可能最后超出了磁盤空間。我們建議你監控歸檔進程,確保它是按照你的意識運轉的。 如果你關心能夠恢復到當前即時的狀態,你可能需要采取幾個額外的步驟以確保當前的, 部分填充的 WAL 段也拷貝到了某些地方。這條對于生成很少 WAL 流量的服務器 (或者在運行中有松弛階段的)特別重要,因為在一個 WAL 段文件完全填充滿進而可以歸檔之前, 可能需要很長時間。一個處理這些的可能的方法是設置一個 cron 作業, 周期性(比如每分鐘一次)地標識當前 WAL 段文件然后把它們保存到某個安全的地方。 歸檔的 WAL 段和保存的當前段就足夠保證你可以總是恢復到當前時間的一分鐘之內。 這個行為目前還不是內置于 PostgreSQL 的,因為我們不想把 archive_command 的定義復雜化,因為那樣就要要求它跟蹤成功歸檔但是卻又有不同時刻含義的同一個 WAL 文件。 archive_command 只是用于處理那些不再改變的 WAL 段文件; 除了錯誤重試之外,對于任何給出的文件名他都只被調用一次。 在寫自己的歸檔命令的時候,你應該假設被歸檔的文件最多 64 個字符長并且可以包含 ASCII 字母,數字,以及點的任意組合。 我們不必要記住原始的全路徑(%p),但是有必要記住文件名(%f)。 請注意盡管 WAL 歸檔允許你回復任何對你的 PostgreSQL 數據庫的數據做的修改, 在最初的基礎備份之后,它還是不會回復對配置文件的修改(也就是說,postgresql.conf,pg_hba.conf 和 pg_ident.conf),因為這些文件都是手工編輯的,而不是通過 SQL 操作來編輯的。 所以你可能會需要把你的配置文件放在一個日常文件系統備份過程即可處理到的地方。 2. 進行一次基礎備份
??? 進行基礎備份的過程相當簡單: 確保 WAL 歸檔打開并且可以運轉。 以數據庫超級用戶身份連接到數據庫,發出命令 SELECT pg_start_backup('label');
??? 這里的 label 是任意你想使用的這次備份操作的唯一標識。 (一個好習慣是使用你想把備份轉儲文件放置的目的地的全路徑。) pg_start_backup 用你的備份的信息,在你的集群目錄里,創建一個備份標簽文件, 叫做 backup_label。 至于你連接到集群中的那個數據庫沒什么關系。你可以忽略函數返回的結果; 但是如果它報告錯誤,那么在繼續之前處理它。 執行備份,使用任何方便的文件系統工具,比如 tar 或者 cpio。 這些操作過程中既不需要關閉數據庫,也不希望關閉數據庫的操作。 再次以數據庫超級用戶身份連接數據庫,然后發出命令 SELECT pg_stop_backup();
如果這個返回成功,你的工作就完成了。
??? 我們不需要太關心在 pg_start_backup 和開始實際的備份之間開銷的時間, 也不需要太關心備份結束和 pg_stop_backup 之間的時間; 幾分鐘的延遲不會搞砸事情。不過,你必須確保這些操作是按順序執行的而不是重疊執行的。 要保證你的備份轉儲包括所有數據庫集群目錄里的文件(比如,/usr/local/pgsql/data)。 如果你在使用并未放置在這個目錄里的表空間,也要小心地包含它們 (并且要確保你的備份轉儲歸檔符號連接是符號連接,否則,恢復會把你的表空間搞亂)。 不過,你可以在備份轉儲文件里省略集群目錄里的 pg_xlog/ 子目錄。 這個略微復雜些的動作是值得的,因為它減少了恢復的時候的錯誤。 如果 pg_xlog/ 是一個指向集群目錄之外的一個符號連接,那么這件事情很容易處理, 出于性能考慮的時候經常這么做。 要使用這個備份,你需要保存所有備份開始以及之后的 WAL 段文件。 為了幫助你實現這個任務,pg_stop_backup 函數創建一個備份歷史文件, 它馬上存儲到 WAL 歸檔區域。這個文件的名字是以你在使用備份的時候需要的第一個 WAL 段文件的名字命名的。 比如,如果開始 WAL 文件是 0000000100001234000055CD,那么備份歷史文件將命名為類似 0000000100001234000055CD.007C9330.backup 這樣的東西。 (這個文件名的第二部分表示在該 WAL 文件里面的準確位置,通??梢员缓雎?。) 一旦你安全地把備份轉儲文件歸了檔,那么你就可以刪除所有那些數值名字在這個文件前面的歸檔的 WAL 段。 備份歷史文件只是一個小的文本文件。它包含你給予 pg_start_backup 的標簽字串, 以及備份的起始時間和終止時間。如果你使用這個標簽來表示轉儲文件放在哪里, 如果需要的話,那么歸檔的歷史文件就足夠告訴你轉儲文件存放在哪里了。 因為你必須保留直到你最后一次基礎備份的所有歸檔的 WAL 文件, 那么兩次基礎備份之間的間隔通常是根據你想在歸檔 WAL 文件上花多少存儲空間來定的。 你還應該考慮你準備在恢復上花多少時間,如果需要恢復的話 — 系統將需要重放所有那些段, 而如果最后一次基礎備份以來,時間已經很長了,那么那些動作可能會花掉好些時間。 還有一件事值得一提,那就是 pg_start_backup 函數在數據庫集群目錄里創建了一個叫 backup_label 的文件,它被 pg_stop_backup 刪除。 這個文件當然也會作為你的備份轉儲文件的一部分歸檔。這個備份標簽文件包含你給予 pg_start_backup 的標簽字串, 以及 pg_start_backup 運行的時刻,以及起始 WAL 文件的名字。 如果有混淆,那么我們可以看看備份轉儲文件里面然后判斷轉儲文件來自那個備份會話。 我們還可以在 postmaster 停止的時候制作一個備份轉儲。 在這種條件下,很明顯你不能使用 pg_start_backup 或者 pg_stop_backup, 并且因此你必須靠自己的手段來跟蹤備份轉儲文件都是那些,以及相關的 WAL 文件最遠走到哪里。 通常使用上面的在線備份步驟更好些。 3. 從在線備份中恢復 好,最糟糕的事情發生了,現在你需要從備份中恢復。下面是步驟:
??? 停止 postmaster,如果它還在運行的話。 如果你還有足夠的空間,把整個集群數據目錄和所有表空間拷貝到一個臨時位置, 以防萬一你之后還需要它們。請注意這個預防措施要求你在系統里又足夠的剩余空間來現有庫的保持兩份拷貝。 如果你沒有足夠的空間,那么你至少需要把集群數據目錄的 pg_xlog 子目錄的內容拷貝到安全的地方, 因為它們可能包含系統宕掉的時候還沒有歸檔的日志。 然后清理掉所有在該集群數據目錄里的現存文件, 以及所有你使用的表空間里根目錄下的現存文件。 從你的備份轉儲中恢復數據庫文件。要小心用正確的所有者(數據庫系統用戶,而不是 root!)和權限恢復它們。 如果你使用了表空間,你可能需要核實在 pg_tblspc/ 里的符號連接都得到正確恢復。 刪除任何目前還在 pg_xlog/ 里的文件;這些文件來自備份轉儲,因此它們可能比目前的老。 如果你就根本沒有歸檔 pg_xlog/,那么重建之,要注意也要重建子目錄 pg_xlog/archive_status/。 如果你有在步驟 2 里面保存的 WAL 段文件,那么把它們拷貝到 pg_xlog/。 (最好是拷貝它們,而不是把它們移動回來,這樣即使發生了糟糕的事情,你需要重啟的時候, 你也依然擁有未修改的文件。) 在集群數據目錄里創建一個恢復命令文件 recovery.conf(參閱 Recovery Settings)。 你可能還需要臨時修改 pg_hba.conf 以避免普通用戶連接,直到你確信恢復已經正常了為止。 啟動 postmaster。postmaster 將進入恢復模式并且繼續讀取它需要的歸檔的 WAL 文件。 在恢復過程完成后,postmaster 將把 recovery.conf 改名為 recovery.done (以避免不小心因后面的崩潰再次進入恢復模式)然后開始正常的數據庫操作。 檢查數據庫的內容以確保你已經恢復到你期望的位置。 如果還沒有,回到步驟 1。如果全部正常,則恢復 pg_hba.conf 成正常狀態,允許你的用戶登錄。
???? 所有這些操作的關鍵部分時設置一個恢復命令文件, 這個文件描述你希望如何恢復以及恢復應該走到哪里。 你可以使用 recovery.conf.sample(通常安裝在安裝目錄的 share/ 子目錄里)作為原型。 你必須在 recovery.conf 里面聲明的一個東西是 restore_command, 它告訴系統如何拿回歸檔的 WAL 文件段。類似 archive_command, 這個是一個腳本命令字串。它可以包含 %f,這個變量會被需要的日志文件名替換, 以及 %p,它會被要拷貝去的日志文件的絕對路徑代替。 如果需要在命令里替換真正的 %,寫 %%。 最簡單的有用命令是類似下面的東西 restore_command = 'cp /mnt/server/archivedir/%f %p'
這個命令將把以前歸檔的 WAL 段從目錄 /mnt/server/archivedir 拷貝過來。 你當然可以使用某些更復雜的東西,甚至是一個要求操作者裝配合適的磁帶的 shell 腳本。 重要的一點是:該命令在失敗的時候返回非零值。如果日志文件沒有出現在規檔中,那么該系統將詢問該命令; 在問到的時候,它必須返回非零。這個不是錯誤條件。還要注意 %p 路徑的基礎名將和 %f 不一樣; 不要認為它們是可以互換的。 在歸檔中找不到的 WAL 段將被認為在 pg_xlog/ 里;這樣就允許使用最近沒有歸檔的段。 但是在歸檔中的段將比 pg_xlog/ 中的優先。在檢索歸檔的文件的時候,系統將不會覆蓋現有的 pg_xlog/ 內容。 通常,恢復將處理所有可用的 WAL 段,因此把數據庫恢復到當前時間(或者是在所給出的可用 WAL 段數目的情況下, 我們能走到的最近的地方)。但是如果你想恢復到某些以前的時刻點(比如,就在菜鳥 DBA 刪除你的主要事務表之前), 那么只需要在 recovery.conf 里聲明要求的停止點。你可以通過日期/時間來聲明, 也可以通過特定事務 ID 的結束來聲明這個停止點,我們叫做"恢復目標"。 在我們寫到這些的時候,只有日期/時間選項比較有用, 因為我們沒有工具來幫助你精確地標識應該使用哪個事務 ID。 注意: 請注意停止點必須在備份的終止時間之后(也就是,pg_stop_backup 的時間)。 你無法使用一個基礎備份恢復到備份正在進行中的某個時刻。 (要想恢復到該時刻,你必須回到你以前的基礎備份,然后從那個位置向前滾動。) 3.1. 恢復設置 這些設置只能在 recovery.conf 里面使用,并且只是在恢復的過程中起作用。 在任何之后的恢復中,你必須重新設置他們?;謴瓦^程開始后,它們的值無法改變。 restore_command (string)
??? 執行檢索歸檔 WAL 文件段序列的 shell 命令。這個參數是必須的。 字串中的任何 %f 都被從歸檔中檢索出來的文件名替換, 而任何 %p 都被替換為拷貝過去的服務器上的絕對路徑。 需要在命令里嵌入真正的 % 字符時,寫 %%。 有一點很重要,那就是這個命令只有在成功的時候才返回零。 系統會向這條命令詢問沒有在歸檔里出現的文件名; 在這種情況下,它必須返回非零。比如: restore_command = 'cp /mnt/server/archivedir/%f "%p"'
restore_command = 'copy /mnt/server/archivedir/%f "%p"'? # Windows recovery_target_time (timestamp)
這個參數聲明恢復執行到達的時間戳。最多可以聲明一個 recovery_target_time 或 recovery_target_xid。缺省是恢復到 WAL 日志的結尾。 精確的停止點也受 recovery_target_inclusive 影響。 recovery_target_xid (string)
這個參數聲明恢復將到達的事務 ID。要注意的是,盡管事務 ID 在事務開始的時候是認為順序的, 但是事務可以以不同的數值順序完成。將要恢復的事務是那些在聲明的這個事務之前(可以選擇包括它提交的時候的)提交的。 最多可以聲明一個 recovery_target_xid 或 recovery_target_time。 缺省是恢復到 WAL 日志的結尾。精確的停止點也受 recovery_target_inclusive 影響。 recovery_target_inclusive (boolean)
聲明我們是否在恢復目標之后(true),還是正好在其之前(false)停止。 適用于 recovery_target_time 和 recovery_target_xid, 不管聲明的是哪個。它分別表示具有準確的提交時間或者 ID 的那些(個)事務,是否將包含在恢復之中。 缺省是 true。 recovery_target_timeline (string)
聲明恢復到一個特定的時間線。缺省是恢復到進行基礎備份時的當時的當前時間線上。 只是在復雜的重新恢復的情況下,你才需要設置這個參數,也就是在你需要恢復到一個本身是在即時恢復之后到達的狀態下, 才需要這么做。 參閱 Section 22.3.4 進行討論。 4. 時間線
?
??? 能夠把數據庫恢復到以前的某個時間點的能力導致了一些類似科幻小說里的時間跟蹤和并行宇宙這樣的復雜情況。 在數據庫的最初的歷史里,可能你在周二下午 5:15 刪除掉了一個非常關鍵的表。 然后有條不紊地拿出備份,恢復到周二晚上 5:14 即時備份。在這個數據庫宇宙的歷史里, 你從來沒有刪除過那個表。但是假如你后來認識到這么干并非絕好的主意,并且想回到最初的歷史中的稍后的點。 你沒法這么干,因為在數據庫運行的時候,它覆蓋了一些 WAL 段文件的序列,這些序列就是在你希望回去的區間里的。 因此你的確需要區分在你從那些原始數據庫歷史生成的 WAL 中完成即時恢復之后生成的 WAL 序列。 為了處理這些問題,PostgreSQL 有個叫時間線的概念。 每次你即時恢復到一個比 WAL 序列的結尾要早的時刻,那么就創建一個新的時間線, 以表示在該次恢復之后生成的 WAL 記錄。(不過,如果恢復動作一尺處理到 WAL 的結尾, 我們就不會開始一個新的時間線:我們只是擴展現有個那個。)時間線 ID 號是 WAL 段文件名的一部分, 因此新的時間線并不會覆蓋以前的時間線生成的 WAL 數據。實際上我們可以歸檔許多不同的時間線。 雖然這些看起來像沒用的特性,但它卻可能常常是救命稻草。考慮一下你并不很確信應該恢復到那個時刻的情況, 這個時候你不得不做好幾次試驗性即時恢復然后從中找到舊歷史中最好的分支。 如果沒有時間線,那么這個過程可能很快就會導致無法管理的混亂。 有了時間線,你可以恢復到任意以前的狀態, 包括恢復到你后來放棄的時間線分支的狀態。 每當創建一個新的時間線的時候,PostgreSQL 都創建一個"時間線歷史"文件, 它顯示自己從那個時間線分出來,以及何時分出來的。這些歷史文件是在從包含多個時間線的規黨中進行恢復時, 允許系統選取正確的 WAL 段文件的必要文件。因此,它們像 WAL 段文件一樣歸檔到 WAL 歸檔里。 歷史文件只是很小的文本文件(不想段文件很大),所以獨立地保存他們代價很小,也值得做。 如果你喜歡,你可以在歷史文件里加入注釋,錄自己為什么設置一個時間線以及如何設置的等信息。 這樣的注釋會在你有厚厚一堆不同的時間線需要選擇和分析的時候特別有價值。 恢復的缺省的行為時沿著與備份基礎備份的同一個時間線恢復。 如果你像恢復到某些子時間線(也就是,你想回到某些本身就是在開始恢復企圖之后發生的狀態), 你需要在 recovery.conf 里聲明目標時間線 ID。你無法恢復到比基礎備份更早的時間線分支。 5. 注意
??? 在我們寫到這些的時候,在線備份技術還有幾個局限。它們可能在將來的版本中修補: 在非 B-tree 索引上的操作(散列,R-tree,和 GiST 索引)目前沒有用 WAL 記錄日志, 所以重放就不會更新這些索引類型。我們建議的繞開方法是在完成恢復操作之后手工 REINDEX 每個這樣的索引。
??? 還要注意,目前的 WAL 格式占地非常大,因為它包含許多磁盤影像。 這么做對于崩潰恢復用途是合適的,因為我們可能需要修補部分寫入的磁盤頁。 但是對 PITR 操作卻沒必要存儲如此多頁面。將來開發的一個方面就是通過刪除無用的頁拷貝來壓縮歸檔的 WAL 數據。恰相反,大多數情況下它要大。 (比如pg_dump 不用倒出索引,只是創建它們的命令。)
轉載于:https://blog.51cto.com/infosec/112032
總結
以上是生活随笔為你收集整理的postgresql数据库的备份与恢复的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 桌面图标去掉阴影
- 下一篇: 年底了,游戏大作连连