MySQL · 物理備份 · Percona XtraBackup 備份原理

weixin_34292959發表於2016-07-17

 http://mysql.taobao.org/monthly/2016/03/07/

前言

Percona XtraBackup(簡稱PXB)是 Percona 公司開發的一個用於 MySQL 資料庫物理熱備的備份工具,支援 MySQl(Oracle)、Percona Server 和 MariaDB,並且全部開源,真可謂是業界良心。我們 RDS MySQL 的物理備份就是基於這個工具做的。

專案的 blueprint 和 bug 討論放在 Launchpad,程式碼之前也放在 Launchpad,現在已經遷移到 Github 啦,專案更新發布非常快,感興趣的可以關注 :-)

本文會介紹下備份工具的工作原理,希望對大家有所幫助。

工具集

軟體包安裝完後一共有4個可執行檔案,如下:

usr
├── bin
│   ├── innobackupex
│   ├── xbcrypt
│   ├── xbstream
│   └── xtrabackup

其中最主要的是 innobackupex 和 xtrabackup,前者是一個 perl 指令碼,後者是 C/C++ 編譯的二進位制。

xtrabackup 是用來備份 InnoDB 表的,不能備份非 InnoDB 表,和 mysqld server 沒有互動;innobackupex 指令碼用來備份非 InnoDB 表,同時會呼叫 xtrabackup 命令來備份 InnoDB 表,還會和 mysqld server 傳送命令進行互動,如加讀鎖(FTWRL)、獲取位點(SHOW SLAVE STATUS)等。簡單來說,innobackupex 在 xtrabackup 之上做了一層封裝。

一般情況下,我們是希望能備份 MyISAM 表的,雖然我們可能自己不用 MyISAM 表,但是 mysql 庫下的系統表是 MyISAM 的,因此備份基本都通過 innobackupex 命令進行;另外一個原因是我們可能需要儲存位點資訊。

另外2個工具相對小眾些,xbcrypt 是加解密用的;xbstream 類似於tar,是 Percona 自己實現的一種支援併發寫的流檔案格式。兩都在備份和解壓時都會用到(如果備份用了加密和併發)。

本文的介紹的主角是 innobackupex 和 xtrabackup

原理

通訊方式

2個工具之間的互動和協調是通過控制檔案的建立和刪除來實現的,主要檔案有:

  • xtrabackup_suspended_1
  • xtrabackup_suspended_2
  • xtrabackup_log_copied

舉個例子,我們來看備份時 xtrabackup_suspended_2 是怎麼來協調2個工具程式的

  1. innobackupex 在啟動 xtrabackup 程式後,會一直等 xtrabackup 備份完 InnoDB 檔案,方式就是等待 xtrabackup_suspended_2 這個檔案被建立出來;
  2. xtrabackup 在備完 InnoDB 資料後,就在指定目錄下建立出這個檔案,然後等這個檔案被 innobackupex 刪除;
  3. innobackupex 檢測到檔案 xtrabackup_suspended_2 被建立出來後,就繼續往下走;
  4. innobackupex 在備份完非 InnoDB 表後,刪除 xtrabackup_suspended_2 這個檔案,這樣就通知 xtrabackup可以繼續了,然後等 xtrabackup_log_copied 被建立;
  5. xtrabackup 檢測到 xtrabackup_suspended_2 檔案刪除後,就可以繼續往下了。

是不是感覺有點不可思議,通過檔案是否存在來控制程式,這種方式非常的不靠譜,因為非常容易被外部干擾,比如檔案被別人誤刪掉,或者2個正在跑的備份控制檔案誤放在同一個目錄下,就等著備份亂掉吧,但是 Percona 就是這麼幹的。

之所以這麼搞,估計主要是因為 perl 和 C 二進位制2個程式,沒有既好用又方便的通訊方式,搞個協議啥的太麻煩了。但是官方也覺得這種方式不靠譜,11年就搞了個 blueprint 要用C重寫 innobackupex,終於在2.3 版本實現了,innobackupex 功能全部整合到 xtrabackup 裡面,只有一個 binary,另外為了使用上的相容考慮,innobackupex作為 xtrabackup 的一個軟鏈。對於二次開發來說,2.3 擺脫了之前2個程式協作的負擔,架構上明顯要好於之前版本。考慮到 perl + C 這種架構的長期存在,大多數讀者朋友也基本用的2.3之前版本,本文的介紹也是基於老的架構(2.2版本),但是原理和2.3是一樣的,只是實現上的差別。

備份過程

整個備份過程如下圖:

 


PXB 備份過程

  1. innobackupex 在啟動後,會先 fork 一個程式,啟動 xtrabackup程式,然後就等待 xtrabackup 備份完 ibd 資料檔案;
  2. xtrabackup 在備份 InnoDB 相關資料時,是有2種執行緒的,1種是 redo 拷貝執行緒,負責拷貝 redo 檔案,1種是 ibd 拷貝執行緒,負責拷貝 ibd 檔案;redo 拷貝執行緒只有一個,在 ibd 拷貝執行緒之前啟動,在 ibd 執行緒結束後結束。xtrabackup 程式開始執行後,先啟動 redo 拷貝執行緒,從最新的 checkpoint 點開始順序拷貝 redo 日誌;然後再啟動 ibd 資料拷貝執行緒,在 xtrabackup 拷貝 ibd 過程中,innobackupex 程式一直處於等待狀態(等待檔案被建立)。
  3. xtrabackup 拷貝完成idb後,通知 innobackupex(通過建立檔案),同時自己進入等待(redo 執行緒仍然繼續拷貝);
  4. innobackupex 收到 xtrabackup 通知後,執行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位點,然後開始備份非 InnoDB 檔案(包括 frm、MYD、MYI、CSV、opt、par等)。拷貝非 InnoDB 檔案過程中,因為資料庫處於全域性只讀狀態,如果在業務的主庫備份的話,要特別小心,非 InnoDB 表(主要是MyISAM)比較多的話整庫只讀時間就會比較長,這個影響一定要評估到。
  5. 當 innobackupex 拷貝完所有非 InnoDB 表檔案後,通知 xtrabackup(通過刪檔案) ,同時自己進入等待(等待另一個檔案被建立);
  6. xtrabackup 收到 innobackupex 備份完非 InnoDB 通知後,就停止 redo 拷貝執行緒,然後通知 innobackupexredo log 拷貝完成(通過建立檔案);
  7. innobackupex 收到 redo 備份完成通知後,就開始解鎖,執行 UNLOCK TABLES
  8. 最後 innobackupex 和 xtrabackup 程式各自完成收尾工作,如資源的釋放、寫備份後設資料資訊等,innobackupex 等待 xtrabackup 子程式結束後退出。

在上面描述的檔案拷貝,都是備份程式直接通過作業系統讀取資料檔案的,只在執行 SQL 命令時和資料庫有互動,基本不影響資料庫的執行,在備份非 InnoDB 時會有一段時間只讀(如果沒有MyISAM表的話,只讀時間在幾秒左右),在備份 InnoDB 資料檔案時,對資料庫完全沒有影響,是真正的熱備。

InnoDB 和非 InnoDB 檔案的備份都是通過拷貝檔案來做的,但是實現的方式不同,前者是以page為粒度做的(xtrabackup),後者是 cp 或者 tar 命令(innobackupex),xtrabackup 在讀取每個page時會校驗 checksum 值,保證資料塊是一致的,而 innobackupex 在 cp MyISAM 檔案時已經做了flush(FTWRL),磁碟上的檔案也是完整的,所以最終備份集裡的資料檔案都是寫入完整的。

增量備份

PXB 是支援增量備份的,但是隻能對 InnoDB 做增量,InnoDB 每個 page 有個 LSN 號,LSN 是全域性遞增的,page 被更改時會記錄當前的 LSN 號,page中的 LSN 越大,說明當前page越新(最近被更新)。每次備份會記錄當前備份到的LSN(xtrabackup_checkpoints 檔案中),增量備份就是隻拷貝LSN大於上次備份的page,比上次備份小的跳過,每個 ibd 檔案最終備份出來的是增量 delta 檔案。

MyISAM 是沒有增量的機制的,每次增量備份都是全部拷貝的。

增量備份過程和全量備份一樣,只是在 ibd 檔案拷貝上有不同。

恢復過程

如果看恢復備份集的日誌,會發現和 mysqld 啟動時非常相似,其實備份集的恢復就是類似 mysqld crash後,做一次 crash recover。

恢復的目的是把備份集中的資料恢復到一個一致性位點,所謂一致就是指原資料庫某一時間點各引擎資料的狀態,比如 MyISAM 中的資料對應的是 15:00 時間點的,InnoDB 中的資料對應的是 15:20 的,這種狀態的資料就是不一致的。PXB 備份集對應的一致點,就是備份時FTWRL的時間點,恢復出來的資料,就對應原資料庫FTWRL時的狀態。

因為備份時 FTWRL 後,資料庫是處於只讀的,非 InnoDB 資料是在持有全域性讀鎖情況下拷貝的,所以非 InnoDB 資料本身就對應 FTWRL 時間點;InnoDB 的 ibd 檔案拷貝是在 FTWRL 前做的,拷貝出來的不同 ibd 檔案最後更新時間點是不一樣的,這種狀態的 ibd 檔案是不能直接用的,但是 redo log 是從備份開始一直持續拷貝的,最後的 redo 日誌點是在持有 FTWRL 後取得的,所以最終通過 redo 應用後的 ibd 資料時間點也是和 FTWRL 一致的。

所以恢復過程只涉及 InnoDB 檔案的恢復,非 InnoDB 資料是不動的。備份恢復完成後,就可以把資料檔案拷貝到對應的目錄,然後通過mysqld來啟動了。

相關文章