備份與恢復
文件系統快照
先決條件和配置
創建一個快照的消耗幾乎微不足道,但還是需要確保系統配置可以讓你獲取在備份瞬間的所有需要的文件的一致性副本。首先,確保系統滿足下面這些條件。
- 1.所有的InnoDB文件(InnoDB的表空間文件和InnoDB的事務日志)必須時在單個邏輯卷(分區)。你需要絕對的時間點一致性,LVM不能為多于一個卷做某個時間點一致的快照。(這是LVM的一個限制;其他一些系統沒有這個問題)
- 2.如果需要備份表定義,MySQL數據目錄必須在相同的邏輯卷中。如果使用另外一種方法來備份表的帝國一,例如只備份Schema到版本控制系統中,就不需要擔心這個問題
- 3.必須在卷組中有足夠的空閑空間來創建快照。需要多少取決于負載。當配置系統時,應該留一些未分配的空間以便后面做快照。
LVM有卷組的概念,它包含一個或多個邏輯卷。可以按照如下的方式查看系統中的卷組:
vgs
VG:vg
#PV:1
#LV:4
#SN:0
Attr:wz--n-
VSize:534.18G
VFree:249.18G
輸出顯示了一個分布在一個物理卷上的卷組,它有四個邏輯卷,大概有250GB空間空閑。入股哦需要,可用vgdisplay命令產生更詳細的輸出。現在讓我們看下系統上的邏輯卷
lvs
LV:home
VG:vg
Attr:-wi-ao
LSize:40.00G
Origin Snap%:
Move Log Copy%:LV:mysql
VG:vg
Attr:-wi-ao
LSize:225.00G
Origin Snap%:
Move Log Copy%:LV:tmp
VG:vg
Attr:-wi-ao
LSize:10.00G
Origin Snap%:
Move Log Copy%:LV:var
VG:vg
Attr:-wi-ao
LSize:10.00G
Origin Snap%:
Move Log Copy%:
創建、掛載和刪除LVM快照
一條命令就能創建快照。只需要決定快照存放的未知和分配給寫時復制的空間大小即可。不要糾結于是否適用比想象中的需求更多的空間。LVM不會馬上使用完所有指定的空格鍵,只是為后續適用預留而已。因此多預留一點空間并沒有壞處,除非你必須同時為其他快照預留空間。讓我們來練習創建一個快照。我們給它16GB的寫時復制空間,名字為backup_mysql.
lvcreate --size 16G --snapshot --name backup_mysql /dev/vg/mysq
這里特意命名為backup_mysql卷而不是mysql_backup,是為了避免Tab鍵自動補全造成誤會。這有助于避免因為Tab鍵自動補全導致突然誤刪除mysql卷組的可能。我們可以適用lvs看看新創建的卷的狀態。快照的屬性與原設備不同,而且該輸出還顯示了一點額外的信息:原始卷組和分配了16GB的寫時復制空間目前已經使用了多少。備份對此進行監控是個非常好的主意,可以知道是否會因為設備寫滿而備份失敗。可以交互地監控設備的狀態,或使用諸如Nagios這樣的監控系統。
wathc 'lvs | grep backup'
從前面mount的輸出可以看到,mysql卷包含一個文件系統。這意味著快照也同樣如此,可以像其他文件系統一樣掛載。
mkdir /tmp/backup
mount /dev/mapper/vg-backup_mysql /tmp/backup
ls -l /tmp/backup/mysql
這里只是為了聯系,因此我們卸載這個快照并用lvremove命令將其刪除
umount /tmp/backup
rmdir /tmp/backup
lvremove --force /dev/vg/backup_mysql
用于在線備份的LVM快照
現在已經知道如何創建、加載和刪除快照,可以使用它們來進行備份了。首先看一下如何在不停止MySQL服務的情況下備份InnoDB數據庫,這里需要使用一個全局的讀鎖。連接MySQL服務器并使用一個全局讀鎖將表刷到磁盤上,然后獲取二進制日志的位置:
mysql>FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS;
記錄SHOW MASTER STATUS的輸出,確保到MySQL的連接處于打開狀態,以使讀鎖不被釋放。然后獲取LVM的快照并立刻釋放該讀鎖,可以使用UNLOCK TABLES或直接關閉連接來釋放鎖。最后,加載快照并賦值文件到備份位置。這種方法最主要的問題是,獲取讀鎖可能需要一點時間,特別時當有許多長時間運行的查詢時。當連接等待全局讀鎖時,所有的查詢都將被阻塞,并且不可預測這會持續多久。
文件系統快照和InnoDB
即使鎖住所有的表,InnoDB的后臺線程仍會繼續工作,因此,即使在創建快照時,仍然可以往文件中寫入。并且,由于InnoDB沒有執行關閉操作。如果服務器意外斷電,快照中InnoDB的文件會和服務器意外掉電后文件的遭遇一樣。這不是什么問題,因為InnoDB是個ACID系統。任何時刻(例如快照時),每隔提交的事務要么在InnoDB數據文件中要么在日志文件中。在還原快照后啟動MySQL時,InnoDB將運行恢復進程,就像服務器斷過電一樣。它會查找事務日志中任何提交但沒有應用到數據文件中的事務然后應用,因此不會丟失任何事務。這正是要強制InnoDB數據文件和日志文件在一起快照的原因。這也是在備份后需要測試的原因。啟動一個MySQL實例,把它指向一個新備份,讓InnoDB執行崩潰恢復過程,然后檢測所有的表。通過這種方法,就不會備份損壞了卻還不知道(文件可能由于任何原因損壞)。這么做的另外一個好處是,維拉i需要從備份中還原時會更快,因為已經在備份上運行過一遍恢復程序了。甚至還可以在將快照復制到備份目的地之前,直接在快照上做上面的操作,但增加一點點額外開銷。所以需要確保這是計劃內的操作
使用LVM快照無所InnoDB備份
無鎖備份只有一點不同。區別是不需要執行FLUSH TABLES WITH READ LOCK.這意味著不能保證MyISAM文件在磁盤上一致,如果只使用InnoDB,這就不是問題。mysql系統數據庫中依然有部分MyISAM表,但如果是典型的工作負載,在快照時這些表不太可能發生改變。如果你認為mysql系統表可能會變更,那么可以鎖住并刷新這些表。一般不會對這些表有長時間運行的查詢,所以通常會很快:
mysql> LOCK TABLES mysql.user READ, mysql.db READ;
mysql> FLUSH TABLES mysql.user, mysql.db;
由于沒有用全局讀鎖,因此不會從SHOW MASTER STATUS 中獲取到任何有用的信息。盡管如此,基于快照啟動MySQL(來驗證備份的完整性)時,也將會在日志文件中看到像下面的內容:
InnoDB: Doing recovery: scanned up to log sequence number 0 40817239
InnoDB: Starting an apply batch of log records to the database...
InnoDB:Progress in percents: 3 4 5 6 .. [omitted] ... 97 98 99
InnoDB:Apply batch completed
InnoDB:Last MySQL binlog file position 0 3304937,file name /var/log/mysql/mysql-bin.000001
070928 14:08:42 InnoDB:Started; log sequence number 0 40817239
InnoDB記錄了MySQL已經恢復得時間點對應的二進制日志位置,這個二進制日志位置可以用來做基于時間點的恢復。使用快照進行無鎖備份的方法在MySQL5.0或更新版本中有變動。這些MySQL版本使用XA來協調InnoDB和二進制日志。如果還原到一個與備份時server_id不同的服務器,服務器在準備事務階段可能發現這是從另外一個與自己不同ID的服務器來的。在這種情況下,服務器會變得困惑,恢復事務時可能會卡在PREPARED狀態。這種情況很少發生,但是存在可能性。這也是只有經過驗證才可以說備份成功的原因。有些備份也許是不能恢復的。如果時在備庫上獲取快照,InnoDB恢復時還會打印如下幾行日志:
InnoDB:In a MySQL replica the last master binlog file
InnoDB:position 0 115, file name mysql-bin.001717
輸出顯示了InnoDB已經恢復了基于主庫的二進制位置(相對于備庫二進制日志位置),這對基于備庫備份或基于其他備庫克隆備庫來說非常有用