Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

PostgreSQL 線上備份
post by tommy @ 11 八月, 2007 13:05

我們大約是由 2003 年初開始使用 PostgreSQL 當做是公司內的資料庫系統. 當初在 ORACLE (9i), MySQL (3.x) 與 PostgreSQL (7.2) 之間選擇時, 先把當時還算很簡陋的 MySQL (那時應該還沒有支援 stored procedure, sub-query, transaction 等等的功能, 實在不適合商業使用,  不過因為快又小, 我們有些中介的資料庫, 還是使用 MySQL 來處理) 給排除掉. 在 ORACLE 與 PostgreSQL 的比較上, 在我們需要的功能上頭, 兩者都能提供, 當然, PostgreSQL 有絕對的價格優勢 (不過, 當初我們並沒有預算上的壓力, 雖然 ORALCE 不算便宜, 但我們決定要用時, 也不會說花不起這筆錢), 但是在複製, 備份與災難復原方面, 就遠遠比不上 ORACLE 了. 最後與老闆討論的結果, 是決定先用 PostgreSQL 試看看, 如果一年內有發生重大的當機或災難時, 我們就轉用 ORACLE. 結果... 當然 4 年多過去了... 我們還是在用 PostgreSQL.

在這段期間, 我們對於 PostgreSQL 的備份, 就只能使用  SQL dump (pg_dump) 的方式來處理, 也就是每天我們會把資料庫 dump 下來, 存在  RAID 上頭保留一個月, 然後每天會把這些備份 tar 到磁帶櫃裡頭的不同磁帶, 也就是至少可以有七天的磁帶來循環使用. 這樣子的方式, 可以確保我們在發生問題時, 應該最差只會損失一天的交易資料 (當然, 有些公司一天的交易資料算很嚴重的事, 不過我們對於收入有關的資料, 是由交換機上產生的資料再匯入的, 如果真的發生問題, 還是可以做重新匯入的動作, 真的發生問題時, 還不至於造成收入上的損害). 四年多下來, 還沒碰過需要還原的時候.

雖然 PostgreSQL 7.x 的版本, 就有了 WAL (Write-Ahead Logging) 的功能, 可以把交易記錄存下來, 不過, 對於備份與還原來說, 一點幫助也沒有, 仍然只有 SQL dump 的方式可以處理. 在 2005 年初的時候, PostgreSQL  8.0 發表了, 除了支援 windows 外, 利用 WAL 這個功能, 終於有了除了 SQL dump 之外的備份方式了. 而且是 on-line 的備份方式. 也就是我們可以線上做一份基本的備份, 然後把之後的 WAL 交易記錄檔也存起來, 就可以還原到你保存的最後一個 WAL 交易檔的時間點. 在這之後, 備份與還原, 就不是一件困難的事情了. 與一般市售的資料庫比較起來, 一點也不遜色. 原本用 SQL dump 的方式, 雖然備份的時間算快, 但是還原的時間, 當資料一多時, 就要花很多的時間了, 且... 就只能還原到備份的那個時間點. 現在... 利用這個新的備份方式, 還原的時間就可以大幅的縮減, 也可以儘可能的還原到出問題前的那個時間點.

參考 8.0 有關 PITR (point-in-time recovery) 的說明, 很容易就可以使用這樣的備份方式.

首先, 在你的 postgresql.conf 設定中, 設定 archive_command 這個參數, 如:

archive_command='cp -i %p /backup/archivelog/%f < /dev/null' 

這樣子, PostgreSQL 就會在產生 WAL 之後, 利用這個指令, 把檔案 copy 到 /backup/archivelog/ 這個目錄中.

在有了 WAL 的 archive 之後, 我們可以在 psql 中, 使用這個指令告訴 PostgreSQL 我們要開始一個備份:

SELECT pg_start_backup('label');

在這個指令之後, 我們就可以利用 tar 或 cpio 之類的軟體, 把 PostgreSQL 的 data 目錄備份下來 (tar 可能因為在備份的時後, 檔案有更動產生錯誤訊息, 可以忽略).  在把檔案備份之後, 再用 psql 執行下面這個指令, 告訴 PostgreSQL 我們結束備份了:

SELECT pg_stop_backup();

在這個指令後, 再把備份的檔案, 以及備份這段時間在 pg_xlog 產生的 WAL 交易檔案保存起來, 再把之後的 WAL 交易檔也都存下來. 在發生問題時, 就可以利用這些備份的資料與 WAL 交易檔, 來還原整個資料庫了.

上頭的備份動作, 我們可以整合一下, 寫成一個 script 來跑:

#!/bin/sh
 
if [ "$1" == "" ]; then
$0 backupname
exit 1
fi
 
psql << START_BACKUP_END
select pg_start_backup('$1');
\q
START_BACKUP_END
 
find . -print | cpio -o -H crc | gzip -v > /backup/base/$1.cpio.gz
 
psql << STOP_BACKUP_END
select pg_stop_backup();
\q
STOP_BACKUP_END

利用上頭的 script, 我們只要讓 PostgreSQL 的使用者, 執行這個指令, 加上日期當參數, 就可以產生一個以該日期參數為檔名的基本備份檔了.

有了上頭的備份資料後, 要怎麼還原呢?

首先, 先安裝出一個有 PostgreSQL 的環境, 然後把上頭 tar 或 cpio 得到的基本備份檔案, 還原到 PostgreSQL 的 data 目錄中.  如果你用上頭的 script 備份, 可以用到下頭的指令還原:

#!/bin/sh
 
cat /backup/base/20070810.cpio.gz | gzip -cd | cpio -idvm

還原之後, 把 pg_xlog 的目錄內的檔案清除掉. 然後做一個 recovery.conf 的設定檔如下:

restore_command = 'cp /backup/archivelog/%f "%p"'

把這個檔案放在 PostgreSQL 的目錄中, 然後把在上一個基本備份之後的 WAL 交易檔放到 /backup/archivelog/ 目錄中. 接著只要啟動 PostgreSQL, 就會進入到  recovery 的模式, 會把這些 WAL 交易記錄執行一次, 直到最後一個交易記錄檔為止, 接著 PostgreSQL 會把 recovery.conf 改名為 recovery.done, 然後把正常的資料庫帶起來. 這樣子, 你就可以還原出你的資料庫了.

在 recovery.conf 上頭, 還可以利用其它的參數, 讓 recovery 的動作做到某個時間點或某個交易為止, 可以防止某些不正常的交易被再執行到. 如果沒有設定, 就是做到沒有下一個 WAL 交易檔為止. 如有需要, 請自行參考官方的文件有關這部份的參數設定.

PS:

  • 在 8.2 版之後, 如果你把 full_page_writes 設為 off, 來增加效能的話, 在備份期間, 效能與平時有明顯的差異.
  • 在 Debian 的 PostgreSQL 版本中, 如果你的 recovery.conf 放在 data 的目錄下沒有作用時, 請在 /etc/postgresql/8.2/main 下頭同樣放上一份 recovery.conf (不過, 在執行 recovery 時, 並不是讀取這個檔案裡頭的設定值?), 在我之前的測試中, 似乎這樣子才會在一開始進入 recovery 的模式去還原之後的 WAL 交易檔.

 

Del.icio.us Furl HEMiDEMi Technorati MyShare
迴響
暱稱:
標題:
個人網頁:
電子郵件:
authimage

迴響

  

Bad Behavior 已經阻擋了 136 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS