1 關於備份
1.1 為什么要備份
- 災難恢復,數據庫在運行過程中,終會遇到各種各樣的問題: 硬件故障、Bug 導致數據損壞、由於服務器宕機或者其他原因造成的數據庫不可用。除此以外還有人為操作:
DELETE
語句忘加條件、ALTER TABLE
執行錯表、DROP TABLE
執行錯表、黑客攻擊,即使這些問題你都還沒遇到,但是根據墨菲定律,總會有遇上的時候。 - 回滾,由於某種Bug或系統被黑造成大量的損失,這個時候就需要回滾到某個狀態。常見的有區塊鏈交易所被黑然后回滾,游戲漏洞被利用然后整體回滾。
- 審計,有時候有這樣的需求:需要知道某一個時間點的數據是怎么樣的,可能是年末審計,也可能是因為官司。
- 測試,一個基本的測試需求是,定時拉取線上數據到測試環境,如果有備份,就可以非常方便地拉取數據。
1.2 有哪些備份方式
1.2.1 邏輯備份
邏輯備份是最常見的方式,在數據量比較少的時候很常用。
邏輯備份的優勢:
- 備份恢復比較簡單,例如
mysqldump
就是 MySQL 自帶的備份工作,無需額外安裝。恢復的時候可以直接使用mysql
命令進行恢復。 - 可以遠程備份和恢復,也就是說,可以在其他機器執行備份命令。
- 備份出來的數據非常直觀,備份出來后,可以使用
sed
grep
等工具進行數據提取或者修改。 - 與存儲引擎無關,因為備份文件是直接從 MySQL 里面提取出來的數據,所以在直觀上,備份數據數據不對引擎做區分,可以很方便地從
MyISAM
引擎改到InnoDB
引擎。 - 避免受到文件損壞的影響,如果直接復制原始文件,可能會受到某個文件損壞的影響而得到一個損壞的備份。使用邏輯備份,只要 MySQL 還能執行 SELECT 語句,就可以得到一份可以信賴的邏輯備份,在文件損壞的時候很有用。
邏輯備份缺點:
- 因為必須使用 MySQL 服務進行數據操作,所以備份的時候會占用更多 CPU,且備份時間可能會更長。
- 邏輯備份在某些場景下比數據庫文件更大,文本存儲的數據不總是比存儲引擎更高效。當然,使用壓縮的話會得到一個更小的備份,但是要占用 CPU 資源。(如果索引較多,邏輯備份會比物理備份小。)
- 恢復時間更長,使用邏輯備份的數據恢復,需要占用更多資源去進行鎖分配、索引構建、沖突檢查、日志刷新。
邏輯備份常用方法:
mysqldump
是MySQL
自帶的備份工具,通用性強,非常常見。使用的使用通常要加上一些參數,后面繼續介紹。select into outfile
,以符號分割數據創建邏輯備份,對於要導入到CSV
等表格會比較實用。mydumper
,允許使用多線程進行備份,備份文件會進行表結構和數據分離,在恢復某些表或數據的時候會非常有效。
1.2.2 物理備份
物理備份在數據量較大的時候非常常見。
物理備份的優勢:
- 備份速度快,因為物理備份是基於復制進行備份,意味者復制有多快,備份就能有多快。
- 恢復速度快,只需要把文件復制到數據庫目錄就可以完成恢復,不需要檢查鎖、構建索引。
- 恢復簡單,對於 MySIAM 引擎的表,不需要停庫,只需要簡單地復制進數據目錄就可以。對於 InnoDB,如果是每個表一個表空間,也可以不停庫操作,使用卸載加載表空間的方式便可導入(不太安全)。
物理備份缺點:
- 沒有官方物理熱備份工具的支持。沒有官方工具的支持,意味着出問題的概率較大,使用的時候就要謹慎了
- InnoDB 的原始文件通常比邏輯備份要大。InnoDB 表空間往往包含很多未被使用的空間,InnoDB 表在刪除數據后不會釋放空間,所以即使數據量不大,文件有可能很大。除此以外,文件中除了數據還包含了索引、日志等信息。
- 物理備份不總可以跨平台跨版本。MySQL 文件和操作系統、MySQL 版本息息相關,如果環境與原來不一致,很有可能會出現問題。
物理備份常用方法:
xtrabackup
是最常用的物理備份工具,由percona
開源,能夠實現對 InnoDB 存儲引擎和 XtraDB 存儲引擎非阻塞地備份(對於 MyISAM 還是要加鎖),得到一份一致性備份。直接復制文件/文件系統快照
,這種方式對於MySIAM
引擎是非常高效的,只需要執行FLUSH TABLE WITH READ LOCK
就可以復制得到一份備份文件。但是對於InnoDB
引擎就比較困難,因為InnoDB
引擎使用了大量的異步技術,即使執行了FLUSH TABLE WITH READ LOCK
,它還是會繼續合並日志、緩存數據。所以要用這種方法備份InnoDB
,需要確保checkpoint
已經最新。
1.2 為什么要備份 binlog
如果有 DBA 告訴你,這個數據庫能夠恢復到兩個個月內任何狀態,這說明了,這個數據庫的 binlog 日志至少保留了兩個月。備份 binlog 的好處:
- 可以實現基於任意時間點的恢復
- 可以用於誤操作數據閃回
- 可以用於審計
當你要進行數據恢復的時候,就會非常慶幸有做 binlog
備份。當然,使用 binlog
恢復數據的前提是 binlog
格式要設為 row
,不要擔心空間問題,當前最不缺的資源就是硬盤空間。對於 binlog
,我們推薦的配置是
# 記錄每一行數據的變化
binlog_format = row
# 備庫在重做數據的時候,記錄一條 binlog
log_slave_updates = 1
1.3 復制和備份
主從復制等於多了一個數據副本,但是復制並不等於備份,也不能代替備份。假設在主庫執行了 drop table
操作,會立刻同步到備庫,並執行相同的操作,沒有辦法在出現意外的時候使用備庫進行數據恢復。
延遲復制也不能代替備份,但是能加快恢復的速度,是一種非常有用的策略。
在實際使用中,為了不影響主庫的使用,我們往往會在備庫進行備份,同時記錄同步點,以方便進行新備庫搭建。在備庫備份需要注意的是,主從復制並不能保證主備間數據是一致的。實際上,基於復制的 MySQL
集群並不能保證集群內部一致性,當前也沒有非常好的辦法,常用的是使用 pt-table-checksum
進行一致性檢查。
2. 全量備份
全量備份介紹最常用的邏輯備份工具 mysqldump
和物理備份工具 xtrabackup
。如果對 mysqldump
不太滿意 可以使用 mydumper
來替代 mysqldump
。
2.1 mysqldump
mysqldump
是用得最多的工具,但是要用好的話,需要增加一些額外的參數。mysqldump
有很多可用參數,這里不展開,建議直接訪問官網 mysqldump。使用 mysqldump
某些參數需要 select,reload,lock tables
權限。
2.1.1 常見例子
2.1.1.1 InnoDB 全庫備份
mysqldump --opt --single-transaction --master-data=2 --default-character-set=utf8 -h<host> -u<user> -p<password> -A > backup.sql
--opt
如果有這個參數表示同時激活了mysqldump命令的quick,add-drop-table,add-locks,extended-insert,lock-tables參數,它可以給出很快的轉儲操作並產生一個可以很快裝入MySQL服務器的轉儲文件。當備份大表時,這個參數可以防止占用過多內存--single-transaction
設置事務的隔離級別為可重復讀,然后備份的時候開啟事務,這樣能保證在一個事務中所有相同的查詢讀取到同樣的數據。注意,這個參數只對支持事務的引擎有效,如果有MyISAM
的數據表,並不能保證數據一致性-A
導出全部數據庫–-default-character-set=charset
指定導出數據時采用何種字符集--master-data=2
表示在備份過程中記錄主庫的binlog
和pos
點,並在dump文件中注釋掉這一行,在使用備份文件做新備庫時會用到
2.1.1.2 MyISAM 全庫備份
mysqldump --opt --lock-all-tables --master-data=2 --default-character-set=utf8 -h<host> -u<user> -p<password> -A > backup.sql
--lock-all-tables
鎖表備份。由於MyISAM
不能提供一致性讀,如果要得到一份一致性備份,只能進行全表鎖定。
2.1.1.3 備份帶上壓縮
mysqldump -h<host> -u<user> -p<password> -A | gzip >> backup.sql.gz
2.1.1.4 備份多個庫
mysqldump -h<host> -u<user> -p<password> --databases <dbname1> <dbname2> > backup.sql
2.1.2 恢復
恢復方式比較簡單,直接執行 sql 語句就可以了
mysql -h<host> -u<user> -p<password> < backup.sql
2.1.3 mysqldump執行流程
打開 general_log
可以查看 mysqldump
的執行流程,這里以 --single-transaction --opt -A
參數為例
FLUSH /*!40101 LOCAL */ TABLES
FLUSH TABLES WITH READ LOCK
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
START TRANSACTION
SHOW VARIABLES LIKE 'gtid\_mode'
SHOW MASTER STATUS
UNLOCK TABLES
...
SHOW CREATE DATABASE IF NOT EXISTS `employees`
SAVEPOINT sp
...
SELECT /*!40001 SQL_NO_CACHE */ * FROM `departments`
....
2.2 xtrabackup
2.2.1 安裝方式
更多安裝方式參考官網 xtrabackup
這里我們使用 rpm
安裝的方式
yum install http://www.percona.com/downloads/percona-release/redhat/0.1-6/percona-release-0.1-6.noarch.rpm
yum update percona-release
# qpress 用作壓縮解壓
yum install percona-xtrabackup-24 qpress
2.2.2 使用方法
2.2.2.1 增加備份賬號並授權
CREATE USER 'backup'@'localhost' IDENTIFIED BY 'backup';
GRANT PROCESS,RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;
2.2.2.2 全備
innobackupex --defaults-file=/etc/my.cnf --user=<user> --password=<pwd> <要備份到哪個目錄> --no-timestamp --compress --compress-threads=4 --parallel=4
--no-timestamp
不使用當前時間建立文件夾。默認情況下會在備份目錄以當前時間創建文件夾--compress
壓縮--compress-threads=N
壓縮線程--parallel=N
備份線程
2.2.2.3 恢復
# 步驟一:解壓
innobackupex --decompress <備份文件所在目錄> --parallel=4
# 步驟二:應用日志
innobackupex --apply-log <備份文件所在目錄> --parallel=4
# 步驟三:復制備份文件到數據目錄
innobackupex --datadir=<MySQL數據目錄> --copy-back <備份文件所在目錄> --parallel=4
3. 增量備份
當數據了變得龐大時,一個常見策略就是做定期的增量備份。例如:周一做了一次全量備份,然后周二到日做增量備份。
增量備份只包含變化的數據集,一般情況不會比原始數據量大,所以可以減少服務器的開銷、備份時間、備份空間。
當然,使用增量備份也會有風險,增量備份每一次迭代都是基於上一次的備份實現,意味着只要其中一份備份出現問題,那么就有可能導致所有備份不可用。
下面介紹一些增量備份方法:
3.1 使用 xtrabackup 做增量備份
xtrabackup 允許進行增量備份,命令如下:
innobackupex --defaults-file=/etc/my.cnf --user=<user> --password=<pwd> --no-timestamp --compress --incremental --incremental-basedir=<全量備份的目錄> <要增量備份到什么目錄>
恢復:
# 步驟一:對全備解壓
innobackupex --decompress <全量備份文件所在目錄>
# 步驟二:對全備應用日志
innobackupex --apply-log --redo-only <全量備份文件所在目錄>
# 步驟三:對增量備份進行解壓
innobackupex --decompress <增量文件所在目錄>
# 步驟四:合並增量數據
innobackupex --apply-log --redo-only --incremental <全量備份文件所在目錄> --incremental-dir=<增量文件所在目錄>
# 步驟五:對合並后的數據應用日志
innobackupex --apply-log <全量備份文件所在目錄>
# 步驟六:復制備份文件到數據目錄
innobackupex --datadir=<MySQL數據目錄> --copy-back <全量備份文件所在目錄>
3.2 使用 binlog 做增量備份
使用 binlog
做增量備份比較簡單,備份的時候執行 FLUSH LOGS
輪轉日志,然后把舊的 binlog
復制到備份目錄就可以了。
恢復的時候使用 mysqlbinlog --start-position=<備份集的pos點> binlog日志 | mysql -u<user> -p
就可以了
4. 延遲同步
延遲同步是常見的使用主從復制使用模式,在遇到誤操作的時候,無論是用於恢復數據,還是使用跳過的方式跳過錯誤都是非常有用。
例如在主庫做了 drop
的誤操作,在主庫找到命令所在 binlog 日志和 pos 位置,Delay庫停止同步,然后使用 start slave until master_log_file='<對應file>',master_log_pos=<誤操作命令前一個SQL的pos>;
等待同步到這個位置,執行跳過一條 SQL 的命令再開啟同步。
常見的延遲同步復制模式有:
一主帶三從
有時候為了減少主庫壓力,會把延遲庫放在備節點之后
延遲同步開啟方式如下:
stop slave;
CHANGE MASTER TO MASTER_DELAY = N秒;
start slave;
5. 數據校驗
除了備份,非常重要的一件事情就是驗證備份數據的可用性。想象一下,當你需要進行數據恢復的時候,忽然發現過去的備份數據都是無效的,那得有多難受。很多朋友在寫好備份腳本加到定時任務后,只要檢查到定時任務有執行,備份目錄有文件就不再關注了,往往到了需要使用備份文件的時候才發現備份數據有問題。
目前對於備份文件的數據校驗沒有非常方便的辦法,用的比較多的還是定時把備份文件拉出來做備份恢復演練,例如一個月做一次備份恢復演練就可以有效提高備份文件可用性,心里也踏實。
數據校驗部分,如果是邏輯備份,往往會抽查某個表的數據,檢查是否符合預期。如果是物理備份,首先要使用 mysqlcheck
等命令檢查是否有表損壞,沒有損壞再抽查表數據。
6. 總結
- 邏輯備份和物理備份可以一起使用,不同的備份周期使用不同的工具,全備周期不應該太長,至少一周一次全備
- 如果數據量較大,可以使用增量備份的方式減少數據量,要注意的是,增量備份風險更大
- binlog功能要開啟,設為
row
模式,設置log_slave_updates = 1
,且最好定時備份 binlog - 有條件的話可以增加一個 Delay 庫,在做緊急恢復的時候有奇效
- 數據校驗要定時去做,否則當需要備份恢復的時候而備份文件又失效,后悔都來不及