數據庫作為一個系統中唯一或者主要的持久化組件,對服務的可用性和數據的可靠性要求極高。 作為能夠有效應對因為系統軟硬件故障、人工誤操作導致數據丟失的預防手段,備份是目前最為常見的數據庫運維操作。 考慮到備份操作對數據庫可用性的影響, MySQL官方將備份方式划主要划分為以下三類:
-
熱備:備份過程中,MySQL實例始終是運行的,所有用戶的讀寫請求都不會受到影響。
-
冷備:備份前首先需要停止MySQL實例的運行,整個備份過程中,用戶均無法訪問數據庫。
-
溫備:備份過程中,雖然MySQL實例是運行的,但是為了保證數據的一致性,允許用戶通過加鎖的方式來防止可能的更新或者修改操作。備份過程中,數據是只讀的,所有的寫請求會被阻塞。
-
--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公司一款開源的數據庫備份軟件,相對於mysqldump,它是直接通過拷貝物理文件實現數據庫備份的,所以速度相比要快很多。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是需要保存的,用於在恢復時進行回放或者回滾。
從前面我們對數據庫備份過程上鎖的必要性的分析可知,除了解決數據文件的一致性外,還需要解決DDL和獲取Binlog的問題。而該問題就需要依賴innobackupex來完成,首先在xtrabackup拷貝完數據文件后,innobackupex在MySQL上執行flush table with read lock,該操作會鎖定整個實例的所有帶X鎖的讀,更新、插入、刪除和DDL語句,相當於凍結了LSN。此時MySQL 當前LSN不會再推進,然后記錄LSN,此為最終一致的LSN;然后記錄當前Binlog的文件名和位置;接着開始拷貝MySQL的表定義文件(.frm),myisam表文件;最后unlock tables釋放鎖,這樣就完成了一次完整的備份過程。