備份應用的場景包括:系統崩潰、硬件故障、用戶錯誤、升級MySQL Installation、傳輸MySQL Installation到另一台機器、設置復制等。
Slave Server備份
在備份Slave 數據庫時,應該備份Master info 和 Relay log info repository,如果在備份時,Slave 正在復制 LOAD DATA語句應該備份slave_load_tmpdir 系統變量指定目下的SQL_LOAD*文件。
備份和恢復策略的例子
假設數據存儲在InnoDB存儲引擎上,支持事務和自動崩潰恢復。也假設在崩潰時,MySQL有負載。如果沒有負載,可能恢復是不需要的。
一種情況:操作系統崩潰或電源故障,MySQL Server磁盤上的數據在數據庫重啟后可用。InnoDB上的數據文件可能由於崩潰而不一致。InnoDB讀它的日志發現還未刷新到磁盤上的pending 事務或者 noncommited 事務。InnoDB自動回滾未提交的事務,刷新已提交的事務到數據文件中。
另一種情況:如果是文件系統崩潰或者硬件文件,假設MySQL磁盤數據在重啟后不可用。這時就需要使用備份恢復。
建立備份策略
假設現在是周日下午一點,做包含所有InnoDB表的全庫備份,比如:
shell> mysqldump --all-databases --master-data --single-transaction > backup_sunday_1_PM.sql
注:在MySQL 8.0 中默認情況下只有mysql schema下的兩張日志表使用CSV存儲引擎,其他表全部使用InnoDB存儲引擎,在做備份時,mysqldump工具只會備份mysql.general_log、mysql_slow_log這兩張日志的定義,而不會備份它們的數據。
這里使用--single-transaction,會在備份開始時,獲取一個全局讀鎖(FLUSH TABLES WITH READ LOCK),在獲取二進制日志的坐標位置后釋放鎖。如果在FLUSH語句執行時,有長時間運行的更新,備份操作可能要等它們完成。--single-transaction使用讀一致性保證mysqldump看到的數據不會改變。這就需要沒有其他語句破環讀一致性,比如ALTER TABLE, DROP TABLE, RENAME TABLE,TRUNCATE TABLE等。
相對於連續的全備,一種有效的做法是:先做全備,然后做增量備份。增量備份更小,花時間也更短。但增量備份給恢復帶來一些麻煩,比如:恢復是不能單純的只應用一個全備,還需要應用增量備份。
在使用增量備份時,可以使用mysqldump工具提供的--flush-logs選項。這個選項會在備份時刷新二進制日志,這樣mysqldump的備份中就包含刷新的二進制日志之前的所有數據。在做恢復時,在應用完全備后,可以方便的應用全備后生成的二進制日志。通過mysqldump工具的--maser-data可以知道全備之后的增量備份(二進制日志文件名)。
可以優化前面的備份腳本,比如:
shell> mysqldump --single-transaction --flush-logs --master-data=2 --all-databases > backup_sunday_1_PM.sql
假設現在是周一下午一點,做增量備份,比如:
shell> mysql'admin flush-logs
注:經二進制日志拷貝到安全位置。
假設現在是周二下午一點,做增量備份,比如:
shell> mysql'admin flush-logs
注:經二進制日志拷貝到安全位置。
補充:
為節約磁盤空間,在mysqldump全備后可以通過--delete-master-logs 選項刪除二進制日志。但是在復制環境中,如果是Master Server,這樣做可能對於沒有完全接收二進制日志的Slave有影響。如果是在Slave Server端,可以考慮使用該選項。因為現在是在Slave端做的備份,可以修改之前的全備腳本如下:
shell> mysqldump --single-transaction --flush-logs --master-data=2 --all-databases --delete-master-logs > backup_sunday_1_PM.sql
注:mysqldump支持備份例程、事件、觸發器,如果需要備份,可以添加--routines、--events 選項。
使用備份進制恢復
假設周三上午八點,發生了災難性崩潰,需要使用備份進行恢復,首選進行全備恢復,比如:
shell> mysql < backup_sunday_1_PM.sql
現在數據已經恢復到周日下午一點,需要做增量恢復,比如:
shell> mysqlbinlog gbichot2-bin.000007 gbichot2-bin.000008 | mysql
現在數據已經恢復到周二下午一點,但是到周三上午八點的數據還是沒有恢復。所以MySQL建議:將日志文件放在一個安全的地方,比如RAID地盤 SAN 等,不同於存放數據目錄的磁盤。
如果日志文件沒有損壞,可以通過繼續應用增量備份,將數據恢復到崩潰發生的時間點,比如:
shell> mysqlbinlog gbichot2-bin.000009 | mysql
備份策略總結
在操作系統崩潰或者電源故障的情況下,InnoDB可以自動恢復,但是為了能夠睡的更好,可以完成下面的建議:
將日志文件存放在安全的位置,同時與數據目錄在不同的磁盤設備上。這樣做也可以做到磁盤的負載均衡,提升了性能。
定期做全量備份
定期做增量備份
注:這里做增量備份是每天做的,所有二進制日志文件大小應該要能夠容納至少一天的業務數據。
mysqldump 工具
A dump file can be used in several ways:
• As a backup to enable data recovery in case of data loss.
• As a source of data for setting up replication slaves.
• As a source of data for experimentation:
• To make a copy of a database that you can use without changing the original data.
• To test potential upgrade incompatibilities.
mysqldump工具根據是否添加 --tab 選項產生不同的DUMP文件:
沒有 --tab 選項:產生一個SQL文件
添加 --tab 選項:產生兩種類型文件:數據文件、數據庫對象定義文件
導出SQL 格式的DUMP文件:
--databases 選項:將選項后面的參數作為數據庫名稱;如果沒有這個選項,最第一個參數作為數據庫名稱,后面的參數作為表名稱。
--databases選項、--all-databases選項 會在DUMP文件中添加CREATE DATABASE ... IF NOT EXISTS語句和USE DATABASE語句。
如果GTID開啟,在導入時可能會報如下錯誤:
ERROR 3546 (HY000) at line 24: @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
解決方法:在導出時指定--set-gtid-purged=off 或者 comment。或者再導入前,刪除DUMP文件中SET GTID_PURGED語句。
使用mysqldump工具導出Delimited-Text 格式的數據文件
在使用 mysqldump --tab=tab_dir選項時,可能會遇到下面的錯誤:
mysqldump: Got error: 1290: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement when executing 'SELECT INTO OUTFILE'
說明:--secure-file-priv 變量控制LOAD DATA類型的操作目錄,有三個取值:' '、null、dir。
注:使用--tab 選項,最好是在本地。如果是遠程使用這個選項:txt文件在遠程主機(server),sql文件在本地主機(client)。
mysqldump --tab 一些格式化輸出:
• --fields-terminated-by=str
The string for separating column values (default: tab).
• --fields-enclosed-by=char
The character within which to enclose column values (default: no character).
• --fields-optionally-enclosed-by=char
The character within which to enclose non-numeric column values (default: no character).
• --fields-escaped-by=char
The character for escaping special characters (default: no escaping).
• --lines-terminated-by=str
The line-termination string (default: newline).
比如:
mysqldump --tab=./ --fields-terminated-by=, --fields-optionally-enclosed-by='"' --lines-terminated-by=0x0d0a -uroot -poracle test
導入mysqldump --tab 選項導出的DUMP文件:
先導入SQL文件:
cat *.sql | mysql -uroot -poracle test
在導入TXT文件:
使用mysqlimport工具:
mysqlimport -uroot -poracle --fields-terminated-by=, --fields-optionally-enclosed-by='"' --lines-terminated-by=0x0d0a test /usr/local/mysql-8.0.18-linux-glibc2.12-x86_64/data/dump/*.txt
使用LOAD DATA語句:
mysql> USE db1;
mysql> LOAD DATA INFILE 't1.txt' INTO TABLE t1
FIELDS TERMINATED BY ','
FIELDS ENCLOSED BY '"'
LINES TERMINATED BY '\r\n';
導出存儲程序:
--routines(存儲過程和函數)
--events(Event Scheduler events)
--triggers(觸發器默認會隨着定義的表而導出)
跳過的話:--skip-routines --skip-events --skip-triggers
分離表定義和表數據:
mysqldump -uroot -poracle --no-data --databases test > test-no-data.dump
mysqldump -uroot -poracle --no-create-info --databases test > test-only-data.dump
使用mysqldump工具測試升級可能的不兼容性:
比如,先在升級后的數據庫系統導入數據庫定義:
mysqldump -uroot -poracle --all-databases --no-data --routines --events > dump-defs.sql
mysql -uroot -poracle < dump-defs.sql
如果測試升級后的系統沒有問題,可以再導入數據:
mysqldump -uroot -poracle --all-databases --no-create-info > dump-data.sql
mysql -uroot -poracle < dump-defs.sql
時間點恢復(增量恢復)
假設人為誤刪除了一張大表,現在做恢復:
如果之前做了全備,比如通過如下語句:
mysqldump -uroot -poracle --all-databases --master-data=2 --single-transaction --routines --events > all.dump
現在先做全備的恢復,比如:
mysql -uroot -poracle < all.dump
可能會報下面的錯誤:
ERROR 3546 (HY000) at line 26: @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
出現這個錯誤的原因:DUMP文件中設置的GTID_PURGED變量值與現在系統中GTID_EXECUTED變量值有重疊。
如果MySQL Server開啟了GTID模式,備份還原到源系統,可能會產生這個錯誤。
解決錯誤的一些做法:
將全備中SET @@GLOBAL.GTID_PURGED語句刪除。
或者在備份時,添加--set-gtid-purged=off 或者 comment,比如:
mysqldump -uroot -poracle --all-databases --master-data=2 --set-gtid-purged=comment --single-transaction --routines --events > all.dump
注:之前MySQL版本沒有--set-gtid-purged=comment,這個參數在不需要在DUMP中設置GTID,同時又希望知道DUMP文件包含的事務信息時可以使用這個選項。
在完成全備恢復后,可以使用mysqlbinlog工具應用二進制日志做增量恢復:
mysqlbinlog --skip-gtids --exclude-gtids='bb65156d-500b-11ea-8a8f-080027b78051:63-65' /usr/local/mysql/log/log-bin.000018 | mysql -uroot -poracle
注:二進制日志中在每個事務前有一個與之相關的GTID,如果二進制日志不做處理,會與系統現在的GTID沖突,這樣系統會不再執行相同GTID的事務。
在MySQL文檔中給出了兩種做增量恢復方法:
通過--stop-datetime 、--start-datetime選項做基於時間的恢復,這種恢復對於同一時間有大量事務的系統,對於日志的截取比較困難。
另一種是通過--stop-position、--start-position 選項基於events位置做的,與上一種方法一樣,兩段截取。
對於現在的系統如果開啟的GTID事務模式,使用GTID截取事務是非常方便的。