標籤:style http 使用 strong 檔案 資料 io width
資料庫作為一個系統中唯一或者主要的持久化組件,對服務的可用性和資料的可靠性要求極高。 作為能夠有效應對因為系統軟硬體故障、人工誤操作導致資料丟失的預防手段,備份是目前最為常見的資料庫營運操作。 考慮到備份操作對資料庫可用性的影響, MySQL官方將備份方式劃主要劃分為以下三類:
熱備:備份過程中,MySQL執行個體始終是啟動並執行,所有使用者的讀寫請求都不會受到影響。
冷備:備份前首先需要停止MySQL執行個體的運行,整個備份過程中,使用者均無法訪問資料庫。
溫備:備份過程中,雖然MySQL執行個體是啟動並執行,但是為了保證資料的一致性,允許使用者通過加鎖的方式來防止可能的更新或者修改操作。備份過程中,資料是唯讀,所有的寫請求會被阻塞。
針對MySQL資料庫,目前主流的備份軟體主要有mysqldump和XtraBackup兩種。
mysqldump mysqldump是MySQL內建的備份工具,通過create table、drop table和insert into 等SQL語句,將資料庫中的資料匯出成.sql檔案。由於該檔案是可讀的,所以稱之為邏輯備份。為了保證備份資料的一致性,mysqldump為使用者提供了以下參數:
--add-locks 為了保證一張表的資料一致性,對該表執行lock table xxx read,無論是innodb表還是myisam表,插入、刪除、更新、帶X鎖的讀(select for update)和DDL(alter)請求均會被阻塞,不影響快照讀和S鎖讀(select lock in share mode)請求。該參數不保證表之間的資料一致性,如果涉及到跨表的查詢,備份不能保證表之間資料是一致的。
--lock-tables 鎖定某一個資料庫的所有的表,能夠保證某一個庫中的所有表的資料一致性,但是不保證庫之間的資料一致,相當於在一個資料庫的所有表上執行了--add-locks參數,此外該庫的DDL語句均會給阻塞。
--lock-all-tables 鎖定某個執行個體的所有表,可以保證所有庫的資料一致性,相當於所有的庫同時指定lock tables參數,此外,執行個體的所有DDL語句(create database)均會阻塞。除非指定--single-transaction選項,如果指定,則mysqldump僅在備份開始時,加一個flush tables with read lock的全域鎖,防止所有的DDL和寫操作,在開啟事務後,釋放該鎖,備份過程中,如果是innodb表則不受影響。
--single-transaction 針對支援MVCC(多版本)事務的儲存引擎,例如innodb,mysqldump提供了在匯出資料之前,開啟一個事務,由資料庫保證單次匯出資料的一致性,此時針對Innodb表的所有讀寫操作,均不會被阻塞。
--master-data 擷取備份資料的Binlog位置和Binlog檔案名稱,用於通過備份恢複的執行個體之間建立複製關係時使用,該參數會預設開啟。
從對mysqldump參數的分析我們可以看出,之所以備份過程中要上鎖,主要基於以下幾個原因:
備份的資料庫中包含不支援事務的表,需要通過鎖來保證單個表、一個庫中的表之間、同一個執行個體的不同庫的表之間的資料一致性。該鎖可以表鎖、庫層級的鎖甚至執行個體層級的鎖,應根據實際業務對一致性的需求選擇不同粒度的鎖,最大程度的減少鎖對使用者讀寫請求的影響。
為了保證備份時,表結構的一致性,需要通過鎖來阻止對錶、庫和執行個體的DDL操作。
為了保證擷取正確的Binlog位置和檔案名稱,需要短暫的鎖定整個執行個體的所有庫,因為Binlog是執行個體層級的,一個執行個體的所有庫是共用Binlog檔案和位置的。同時值得注意的是,無論是innodb表還是myisam表,此都為必須步驟,只是innodb表可以在開啟事務後即釋放該鎖,而myisam需要在整個備份過程中,一直持有該鎖,對使用者訪問的影響時間長短區別。
mysqldump由於依賴資料庫層的轉換,所以並不關心底層的儲存引擎,既適用於支援事務的,也適用於不支援事務的,並且可以同時在不同MySQL版本之間進行轉換,由於是邏輯備份,使用者可以在備份的過程中,同時對資料進行修改。但是也正是因為需要經過資料庫層的轉換,mysqldump產生的備份檔案往往很大,而且速度較慢,備份過程對資料庫的訪問有較大的影響,對於資料量大、業務壓力高的執行個體並不適用。
XtraBackup
XtraBackup是Percona公司一款開源的Database Backup軟體,相對於mysqldump,它是直接通過拷貝物理檔案實現Database Backup的,所以速度相比要快很多。XtraBackup包含兩部分:xtrabackup的c程式和innobackupex perl指令碼;前者主要用於處理innodb表的備份;後者是前者的封裝,主要包括一些與MySQL伺服器的通訊和mysiam表的備份。
首先我們先來簡單的瞭解一下xtrabackup備份的基本原理。xtrabackup能夠實現針對innodb表的無鎖備份,即所有的讀寫請求、DDL語句在整個備份過程中都是不受影響的。它的實現是基於innodb對事務的支援,利用其崩潰恢複的功能來實現的。MySQL所有的更新操作都是在記憶體中完成的,然後非同步刷入磁碟進行持久化。支援事務的儲存引擎,為了保證MySQL宕機後記憶體中還未刷出的更新不會丟失,設計了事務引擎日誌(redo log)。通過將該部分的更新記錄到日誌中,然後記錄日誌序號(LSN),非同步線程在將髒頁重新整理到磁碟的同時,維護一個檢查點LSN,兩個LSN之間的差異就是資料宕機後丟失的更新。在資料庫啟動時,只要交易記錄儲存完好,就可以根據redo log和undo log將資料庫恢複到崩潰前的一致性狀態。
通過在MySQL執行show engine innodb status,我們可以清楚的看到:
Log sequence number:表明當前redo log的最新LSN。
Log flushed up to:表明當前已經重新整理到磁碟上redo log的LSN。
Last checkpoint at :redo log記錄的更新已經重新整理到磁碟上的檢查點LSN,該LSN之前的redo log上記錄的更新已全部重新整理到磁碟上,可以被覆蓋重複使用。
xtrabackup備份時,首先會記錄一個當前redo log最新的LSN,該點是備份資料一致最後一個矯正點,在利用該備份進行恢複時,即從該LSN作為起點,之後的所有redo log記錄的更新都需要重做或者復原。記錄了LSN之後,xtrabackup就找到了一個資料一致點,然後直接拷貝資料檔案。
Innodb儲存引擎的表檔案主要包括以下幾類:
ibdata1:預設資料表空間檔案,如果沒有設定innodb_file_per_table,則所有的表都是共用同一個檔案的。如果啟動了innodb_file_per_table,每張表的索引、資料和插入緩衝BITMAP資訊是按照表分別獨立存放在不同的檔案中,但是undo log等其他資訊還是存放在預設資料表空間中。
table_name.bid:表檔案,存放每張表的資料、索引和插入緩衝。
ib_logfile0: 重做記錄檔,備份前記錄的LSN和備份結束時的LSN之間的redo log xtrabackup是需要儲存的,用於在恢複時進行回放或者復原。
MySQL的redo log是重用的,即檢查點之間的redo log存在被覆蓋的風險,而備份前和備份結束後之間的redo log是需要完整儲存的,不允許被覆蓋,如果備份時間比較長,redo log比較小的情況下,存在備份還沒結束,原先記錄的LSN之後的redo log即被覆蓋,導致更新丟失的問題。為瞭解決該問題,xtrabackup額外啟動了一個線程,不斷的掃描redo log日誌,一旦發現LSN有推進,則立即將該部分redo log拷貝出來,避免被覆蓋。之後xtrabackup就開始拷貝包括預設資料表空間檔案在內的所有表檔案,直到拷貝結束,然後記錄LSN,這樣就完成了innodb表的備份。
從前面我們對Database Backup過程上鎖的必要性的分析可知,除瞭解決資料檔案的一致性外,還需要解決DDL和擷取Binlog的問題。而該問題就需要依賴innobackupex來完成,首先在xtrabackup拷貝完資料檔案後,innobackupex在MySQL上執行flush table with read lock,該操作會鎖定整個執行個體的所有帶X鎖的讀,更新、插入、刪除和DDL語句,相當於凍結了LSN。此時MySQL 當前LSN不會再推進,然後記錄LSN,此為最終一致的LSN;然後記錄當前Binlog的檔案名稱和位置;接著開始拷貝MySQL的表定義檔案(.frm),myisam表檔案;最後unlock tables釋放鎖,這樣就完成了一次完整的備份過程。