《解鎖MySQL備份恢復(fù)的4種正確姿勢》要點:
本文介紹了解鎖MySQL備份恢復(fù)的4種正確姿勢,希望對您有用。如果有疑問,可以聯(lián)系我們。
作者介紹:
馮帥,點融網(wǎng)高級DBA,獲有Oracle OCM、MySQL OCP,目前從事MySQL相關(guān)的運維和架構(gòu)工作,擅長異構(gòu)數(shù)據(jù)庫交互.
分享大綱:
mysqldump
mysqlbackup
mysqlhotcopy
xtrabackup/innobackupex
備份高于一切,今天匯總一下常用的幾種備份方法,以及恢復(fù)的步驟.
在日常工作中,我們會使用mysqldump命令創(chuàng)建SQL格式的轉(zhuǎn)儲文件來備份數(shù)據(jù)庫.或者我們把數(shù)據(jù)導(dǎo)出后做數(shù)據(jù)遷移,主備搭建等操作.mysqldump是一個邏輯備份工具,復(fù)制原始的數(shù)據(jù)庫對象定義和表數(shù)據(jù)產(chǎn)生一組可執(zhí)行的SQL語句. 默認(rèn)情況下,生成insert語句,也能生成其它分隔符的輸出或XML格式的文件.
shell> mysqldump [arguments] > file_name
我們簡單來看一下日常的用法:
備份所有的數(shù)據(jù)庫:
shell> mysqldump –all-databases > dump.sql (不包含INFORMATION_SCHEMA,performance_schema,sys,如果想要導(dǎo)出的話還要結(jié)合–skip-lock-tables和–database一起用)
備份指定的數(shù)據(jù)庫:
shell> mysqldump –databases db1 db2 db3 > dump.sql
當(dāng)我們只備份一個數(shù)據(jù)的時候可以省去 –databases 直接寫成:mysqldump test > dump.sql 不過有一些細微的差別,如果不加的話,數(shù)據(jù)庫轉(zhuǎn)儲輸出不包含創(chuàng)建數(shù)據(jù)庫和use語句,所以可以不加這個參數(shù)直接導(dǎo)入到其它名字的數(shù)據(jù)庫里.
當(dāng)然我們也可以只備份某個表 :
mysqldump –user [username] –password=[password] [database name] [table name] table_name.sql
了解了簡單的一些用法后我們再著重看一下幾個參數(shù):
剛剛我們說過在使用mysqldump的時候會鎖表,我們來詳細看一下它的鎖機制.
我們開兩個窗口,在第一個里面執(zhí)行mysqldump -uroot -pxxxxx –master-data=2 –databases dbname > /tmp/dbnamedate +%F.sql 然后第二個窗口登陸進去,使用show process的命令可以看到目前dump的session正在執(zhí)行.
SELECT /!40001 SQL_NO_CACHE?/ * FROM table_name; 可以看到這條SQL正在以no_cache的模式查詢數(shù)據(jù).
然后我們在同樣的表上執(zhí)行一下select,發(fā)現(xiàn)被阻塞了.光標(biāo)一直不返回.
一般遇到這種文件,我們會想是不是有鎖呢? 為了驗證我們查看一下鎖的信息,可以發(fā)現(xiàn)dump的進程實際上是加了鎖的.
一般遇到這種文件,我們會想是不是有鎖呢? 為了驗證我們查看一下鎖的信息,可以發(fā)現(xiàn)dump的進程實際上是加了鎖的.
我們把具體的general_log打開,然后看一下當(dāng)時的操作:
4101044 Query FLUSH /!40101 LOCAL?/ TABLES
4101044 Query FLUSH TABLES WITH READ LOCK
(關(guān)閉所有打開的表,同時對于所有數(shù)據(jù)庫中的表都加一個讀鎖,直到顯示地執(zhí)行unlock tables,該操作常常用于數(shù)據(jù)備份的時候.)
4101044 Query SHOW MASTER STATUS
(這是因為我用了–master-data=2)
所以這個時候表就會被鎖住.
如果我不加–master-data參數(shù)(mysqldump -uroot -pxx –databases db > /tmp/dbnamedate +%F.sql) mysql會顯示的對每一張要備份的表執(zhí)行 LOCK TABLES?table_name1?READ,LOCK TABLES?table_name2?READ ,并且也不會有讀的阻塞.
那有沒有不鎖的方法,其實也是有的,就是使用–single-transaction把備份的操作放在一個事務(wù)里去進行.
帶上–single-transaction參數(shù)的mysqldump備份過程:
如果是5.6版本的MySQL
在備份之間同樣的先FLUSH TABLES WITH READ LOCK,然后設(shè)置事務(wù)級別SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ,然后開啟一個事務(wù)START TRANSACTION進行備份,這個時候備份的過程就很意思,它先創(chuàng)建了一個savepoint,然后把數(shù)據(jù)庫里的表依次的進行備份,備份完成了之后又回滾到了之前的savepoint,來保證數(shù)據(jù)的一致性.
如果是5.7版本的MySQL
備份前的操作相同,只是沒有了savepoint.
不過不管是哪個版本,只有InnoDB表是在一個一致性的狀態(tài).其它的任何MyISAM表或內(nèi)存表是沒有用的. mysqldump的優(yōu)勢是可以查看或者編輯十分方便,它也可以靈活性的恢復(fù)之前的數(shù)據(jù).它也不關(guān)心底層的存儲引擎,既適用于支持事務(wù)的,也適用于不支持事務(wù)的表.不過它不能作為一個快速備份大量的數(shù)據(jù)或可伸縮的解決方案.如果數(shù)據(jù)庫過大,即使備份步驟需要的時間不算太久,但有可能恢復(fù)數(shù)據(jù)的速度也會非常慢,因為它涉及的SQL語句插入磁盤I/O,創(chuàng)建索引等等. 對于大規(guī)模的備份和恢復(fù),更合適的做法是物理備份,復(fù)制其原始格式的數(shù)據(jù)文件,可以快速恢復(fù):如果你的表主要是InnoDB表,或者如果你有一個InnoDB和MyISAM表,可以考慮使用MySQL的mysqlbackup命令備份.
恢復(fù)操作:
先看一下當(dāng)前的數(shù)據(jù):
dbadmin@test 11:10:34>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
+——-+
1 row in set (0.00 sec)
備份;
mysqldump -uroot -proot@1234 –master-data=1 test >test.sql
模擬增量操作:
dbadmin@test 11:15:17>insert into t values (2);
Query OK, 1 row affected (0.00 sec)
dbadmin@test 11:15:36>select * from t; +——+ | id | +——+ | 1 | | 2 | +——+ 2 rows in set (0.00 sec)
模擬誤操作:
dbadmin@test 11:15:41>truncate table t;
Query OK, 0 rows affected (0.01 sec)
dbadmin@test 11:16:14>select * from t;
Empty set (0.00 sec)
模擬恢復(fù)操作:
step 1:找到誤操作的log position
dbadmin@test 11:20:57>show master logs;
dbadmin@(none) 11:21:37>show binlog events in ‘mysql-bin.000004’;
查看可以看到是444.
step 2:恢復(fù)到備份
dbadmin@test 11:16:25>source test.sql
dbadmin@test 11:17:26>select?from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
+——-+
1 row in set (0.00 sec)
step 3: 因為我們在備份的時候使用了master-data的參數(shù),所以可以直接看到備份時候的最后位置,然后應(yīng)用中間的log.查看可以看到是187.
我們使用mysqlbinlog得到這一段時間的操作,其實我們也可以用這個工具得到操作后使用sed進行undo的操作.
mysqlbinlog –start-position=187 –stop-position=444 mysql-bin.000004 > increment.sql
dbadmin@test 11:44:37>source /u01/my3307/log/increment.sql dbadmin@test 11:44:50>select?from t; +——+ | id | +——+ | 1 | | 2 | +——+
至此數(shù)據(jù)恢復(fù).
mysqlbackup是Oracle公司提供的針對企業(yè)的備份軟件,全名叫做MySQL Enterprise Backup,是一個收費的軟件.
下載地址:https://www.mysql.com/products/enterprise/backup.html?,可以試用下載.
我們簡單來看一下這個工具的使用.
查看所有的幫助:
我這里只是截取了一小部分,這個幫助很長,參數(shù)很多,功能很全,是oracle官方主推的備份方式.
全量備份
mysqlbackup –user=root –password=ucjmh –databases=’t1′ –encrypt-password=1 –with-timestamp –backup-dir=/u01/backup/ backup
解釋一下參數(shù):
backup 是備份的方式, 一共有如下幾種方式,我會在一個恢復(fù)案例里把常用的幾個都用到.
Backup operations: backup, backup-and-apply-log, backup-to-image
Update operations: apply-log, apply-incremental-backup
Restore operations: copy-back, copy-back-and-apply-log
Validation operation: validate
Single-file backup operations: image-to-backup-dir, backup-dir-to-image, list-image, extract
其實,在大多數(shù)情況下,單個文件備份,使用backup-to-image命令創(chuàng)建,性能優(yōu)于backup.buckup這個命令只執(zhí)行一個完整的備份過程的初始階段.需要通過再次運行mysqlbackup運用apply-log 命令,使備份一致.
mysqlbackup –user=root –password=ucjmh –databases=’t1′ –encrypt-password=1 –with-timestamp –backup-dir=/u01/backup/2017-04-28_12-49-35/ apply-log
當(dāng)然你可以直接用backup-and-apply-log 不過這個時候的備份將不能用于增量了.
增量備份:
mysqlbackup –user=root –password=ucjmh –databases=’t1′ –encrypt-password=1 –with-timestamp –backup-dir=/u01/backup/ –incremental –incremental-base=dir:/u01/backup/2017-04-28_12-49-35 –incremental-backup-dir=/u01/backup/incremental backup
這個是基于上次的備份做的備份,當(dāng)然也可以基于某一個log position之后做.
–incremental:代表增量備份;
–incremental-base:上次全備的目錄;
–incremental-backup-dir:增量備份的保存的目錄
再多說一點關(guān)于image的備份:
使用如下命令可以進行備份:
mysqlbackup –user=root –password=ucjmh –databases=’t1′ –encrypt-password=1 –with-timestamp –backup-dir=/u01/backup/ –backup-image=all.mbi backup-to-image
備份之后可以很清楚的發(fā)現(xiàn)這個比backup要節(jié)省很多空間,把所有的文件都以二進制的方式放在了all.mbi這個文件里,可以使用list-image來查看具體內(nèi)容.
mysqlbackup –backup-image=/u01/backup/2017-04-28_14-50-17/all.mbi list-image
同樣的也可以使用 mysqlbackup –backup-image=/u01/backup/2017-04-28_14-50-17/all.mbi extract 來解壓出來具體的內(nèi)容.
因為這是一個Oracle出的工具,有很深的rman的影子在,0級,1級備份,加密,異構(gòu)機器還原等特性.
更多的參數(shù)可以參看online help:
恢復(fù)操作:
查看當(dāng)前數(shù)據(jù)
dbadmin@test 11:51:32>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
+——-+
1 row in set (0.01 sec)
全量備份
mysqlbackup –user=root –password=root@1234 –databases=’test’ –with-timestamp –backup-dir=/data/backup/ backup
模擬增量操作:
dbadmin@test 11:54:04>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
+——-+
2 rows in set (0.00 sec)
增量備份:
mysqlbackup –user=root –password=root@1234 –databases=’test’ –with-timestamp –backup-dir=/data/backup/ –incremental –incremental-base=dir:/data/backup/2017-04-29_11-53-20 –incremental-backup-dir=/data/backup/incremental backup
模擬無備份操作:
dbadmin@test 11:57:10>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
| ?3 ?|
+——-+
3 rows in set (0.00 sec)
模擬誤操作:
dbadmin@test 11:57:17>truncate table t; Query OK, 0 rows affected (0.01 sec)
模擬恢復(fù)操作:
step 1:找到誤操作的log position
dbadmin@test 11:58:06>show master logs;
dbadmin@test 11:58:18>show binlog events in ‘mysql-bin.000001’;
1333
step 2:恢復(fù)全量
檢測并應(yīng)用日志:
mysqlbackup –backup-dir=/data/backup/2017-04-29_11-53-20 apply-log
step 3:應(yīng)用增量
mysqlbackup –backup-dir=/data/backup/2017-04-29_11-53-20 –incremental-backup-dir=/data/backup/incremental/2017-04-29_11-55-54 apply-incremental-backup
step 4:物理文件復(fù)制還原
mysqlbackup –backup-dir=/data/backup/2017-04-29_11-53-20 copy-back
數(shù)據(jù)恢復(fù)到備份的時候:
dbadmin@test 12:09:49>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
+——-+
2 rows in set (0.00 sec)
恢復(fù)完成之后,data目錄下會生成backup_variables.txt的文件(其實在備份的時候就已經(jīng)有這些文件的),找到備份的時候的log position,然后從binlog恢復(fù)無備份的數(shù)據(jù).
binlog_position=mysql-bin.000001:1076 mysqlbinlog mysql-bin.000001 –start-position=1076 –stop-position=1333 -vv >increment.sql
dbadmin@test 12:14:07>source /u01/my3307/log/increment.sql dbadmin@test 12:14:16>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
| ?3 ?|
+——-+
3 rows in set (0.00 sec)
至此數(shù)據(jù)恢復(fù).
大致梳理一下操作步驟,來了解一下恢復(fù)的原理:
首先檢測并應(yīng)用全備事務(wù)日志文件(這里是因為我備份的時候用的是backup而不是backup-and-apply-log),然后基于全備去應(yīng)用增量的log.這個時候如果有多次增量備份也可以(基于LSN點向后應(yīng)用). 所有的都應(yīng)用完成之后就是一個可以直接cp的數(shù)據(jù)庫了.
個人感覺這個工具比xtrabackup好用,但是xtrabackup是開源的,所以市場占有量才會大,才會更有名,更多人用吧.
?mysqlhotcopy使用lock tables、flush tables和cp或scp來快速備份數(shù)據(jù)庫.它是備份數(shù)據(jù)庫或單個表最快的途徑,完全屬于物理備份,但只能用于備份MyISAM存儲引擎和ARCHIVE引擎,并且是一個服務(wù)器命令,只能運行在數(shù)據(jù)庫目錄所在的機器上.與mysqldump備份不同,mysqldump屬于邏輯備份,備份時是執(zhí)行的sql語句.使用mysqlhotcopy命令前需要要安裝相應(yīng)的軟件依賴包. 因為這個功能很弱,我們只簡單的介紹一個怎么用:
備份一個庫
mysqlhotcopy db_name [/path/to/new_directory]
備份一張表
mysqlhotcopy db_name./table_name/ /path/to/new_directory
更詳細的使用可以使用perldoc mysqlhotcopy查看.
Percona XtraBackup是一款基于MySQL的熱備份的開源實用程序,它可以備份5.1到5.7版本上InnoDB,XtraDB,MyISAM存儲引擎的表, Xtrabackup有兩個主要的工具:xtrabackup、innobackupex .
(1)xtrabackup只能備份InnoDB和XtraDB兩種數(shù)據(jù)表,而不能備份MyISAM數(shù)據(jù)表
(2)innobackupex則封裝了xtrabackup,是一個腳本封裝,所以能同時備份處理innodb和myisam,但在處理myisam時需要加一個讀鎖.
首先我們先來簡單的了解一下xtrabackup是怎么工作的.xtrabackup基于innodb的crash-recovery(實例恢復(fù))功能,先copy innodb的物理文件(這個時候數(shù)據(jù)的一致性是無法滿足的),然后進行基于redo log進行恢復(fù),達到數(shù)據(jù)的一致性.
詳細的信息可以參數(shù)https://www.percona.com/doc/percona-xtrabackup/LATEST/how_xtrabackup_works.html?我就不翻譯了.
我們還是簡單來看一下日常工作中具體的使用:
全備:
xtrabackup –backup –target-dir=/data/backup/base
可以先看到
在備份過程中,可以看到很多輸出顯示數(shù)據(jù)文件被復(fù)制,以及日志文件線程反復(fù)掃描日志文件和復(fù)制.
同樣的,它也輸出了當(dāng)前的binlog filename和position,如果有g(shù)tid(同樣也會輸出) 可以用于搭建主從.最后一行一定會是你的lsn被copy的信息. 這是因為每次啟動備份,都會記錄170429 12:54:10 >> log scanned up to (1676085)),然后開始拷貝文件,一般來講數(shù)據(jù)庫越大拷貝文件是要花費越長的時間,所以說這期間一般情況都會有新的操作,所以說所有文件也可能記錄的并不是一個時間點的數(shù)據(jù), 為了解決數(shù)據(jù)這個問題,XtraBackup 就會啟動一個后臺進程來每秒1次的觀測mysql的事務(wù)日志,直到備份結(jié)束.而且把事務(wù)日志中的改變記錄下來.我們知道事物日志是會重用的(redo log),所以這個進程會把redolog寫到自己的日志文件xtrabackup_log,這個后臺監(jiān)控進程會記錄所有的事務(wù)日志的改變,用于保證數(shù)據(jù)一致性所.
增量備份:
當(dāng)我們做過全量備份以后會在目錄下產(chǎn)生xtrabackup_checkpoints的文件 這里面記錄了lsn和備份方式,我們可以基于這次的全量做增量的備份.
$cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 1676085
last_lsn = 1676085
compact = 0
recover_binlog_info = 0
xtrabackup –backup –target-dir=/data/backup/inc1 –incremental-basedir=/data/backup/base
這個時候xtrabackup也是去打開了xtrabackup_checkpoints文件進行上一次備份的信息查看.這個時候去查看增量備份的xtrabackup_checkpoints也記錄了這些信息.
$cat xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1676085
to_lsn = 1676085
last_lsn = 1676085
compact = 0
recover_binlog_info = 0
這也意味著你可以在增量的備份上繼續(xù)增量的備份.
同樣的,xtrabackup也支持壓縮(–compress)、加密(–encrypt)、并行(–parallel)等操作,但是和mysqlbackup不同的是這個沒有同時的備份binlog,而mysqlbackup是備份了binlog的.
我們來模擬一個恢復(fù)的過程深入的了解一下原理.
查看當(dāng)前數(shù)據(jù):
dbadmin@test 03:04:33>select?from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
+——-+
1 row in set (0.00 sec)
全量備份
$xtrabackup –backup –target-dir=/data/backup/base
模擬增量數(shù)據(jù)
dbadmin@test 03:07:16>select?from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
+——-+
2 rows in set (0.00 sec)
進行增量備份:
$xtrabackup –backup –target-dir=/data/backup/inc1 –incremental-basedir=/data/backup/base
模擬無備份操作:
dbadmin@test 03:09:42>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
| ?3 ?|
+——-+
3 rows in set (0.00 sec)
模擬誤操作:
dbadmin@test 03:09:45>truncate table t; Query OK, 0 rows affected (0.00 sec)
模擬恢復(fù)操作:
step 1:找到誤操作的log position
dbadmin@test 03:10:19>show master logs;
dbadmin@test 03:10:47>show binlog events in ‘mysql-bin.000001’;
1333
我們需要分別對全量、增量備份各做一次prepare操作.
xtrabackup –prepare –apply-log-only –target-dir=/data/backup/base
增量
xtrabackup –prepare –apply-log-only –target-dir=/data/backup/base \ –incremental-dir=/data/backup/inc1
如果我們使用它自帶的還原命令的時候就要先把data目錄給清空.不然就會報如下的錯誤
$innobackupex –copy-back /data/backup/base/
170429 15:37:19 innobackupex: Starting the copy-back operation
IMPORTANT: Please check that the copy-back run completes successfully.
At the end of a successful copy-back run innobackupex prints “completed OK!”.
innobackupex version 2.4.6 based on MySQL server 5.7.13 Linux (x86_64) (revision id: 8ec05b7) Original data directory /u01/my3307/data is not empty!
當(dāng)然我們大多數(shù)據(jù)時候是不會在原來的實例上做操作的,都會把相應(yīng)的備份在奇他的實例上進行恢復(fù),然后再導(dǎo)出導(dǎo)入到誤操作的實例.這里我們直接清掉目錄,然后再次運行,查看恢復(fù)后的數(shù)據(jù):
dbadmin@test 03:41:56>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
+——-+
2 rows in set (0.00 sec)
同樣的被恢復(fù)的目錄里會多出來兩個文件,一個是xtrabackup_binlog_pos_innodb,一個是xtrabackup_info.在這兩個文件中都可以看到你最后的log,pos.在info里還可以看到lsn.我們基于這個pos再進行binlog的重演,恢復(fù)在binlog沒有被備份的數(shù)據(jù).
1076
$mysqlbinlog mysql-bin.000001 –start-position=1076 –stop-position=1333 -vv >increment.sql
dbadmin@test 03:51:25>source /u01/my3307/log/increment.sql dbadmin@test 03:51:34>select * from t;
+——-+
| ?id ?|
+——-+
| ?1 ?|
| ?2 ?|
| ?3 ?|
+——-+
3 rows in set (0.00 sec)
至此數(shù)據(jù)恢復(fù)完成.
MySQL還有一種非常簡單的備份方法,就是將MySQL中的數(shù)據(jù)庫文件直接復(fù)制出來.這是最簡單,速度最快的方法. 不過在此之前,要先將服務(wù)器停止,這樣才可以保證在復(fù)制期間數(shù)據(jù)庫的數(shù)據(jù)不會發(fā)生變化.如果在復(fù)制數(shù)據(jù)庫的過程中還有數(shù)據(jù)寫入,就會造成數(shù)據(jù)不一致.這種情況在開發(fā)環(huán)境可以,但是在生產(chǎn)環(huán)境中很難允許備份服務(wù)器.
注意:這種方法不適用于InnoDB存儲引擎的表,而對于MyISAM存儲引擎的表很方便.同時,還原時MySQL的版本最好相同. 只所以提這一點是因為當(dāng)有停機窗口時,搭建主從的時候,這個往往是最快的.
一般生產(chǎn)環(huán)境的備份都會用percona-xtrabackup或者mysqlbackup,結(jié)合自己的情況,選擇合適的備份策略,適時拿出來驗證備份的有效性.
Q1:用innobackupex備份MySQL5.5版本的數(shù)據(jù),恢復(fù)的時候用backu5.6恢復(fù),出現(xiàn)ibdata1找不到,這是什么原因呢?
A1:跨版本恢復(fù)以后,恢復(fù)出來的數(shù)據(jù)的元信息還是以前低版本的,在起動服務(wù)器之前需要先執(zhí)行一下mysql_upgrade.這其實也是一個升級的問題,我們當(dāng)然可以采用innobackupex來做升級操作了,同樣的mysqlbackup也是可以的.因為有些時候我們的庫太大了,不適合導(dǎo)入導(dǎo)出來升級的操作.
Q2:你講的方法適合集群嗎?如果不適合集群的話,用什么方法?
A2:當(dāng)然,其實都是一樣的.原理只是對數(shù)據(jù)庫的數(shù)據(jù)進行復(fù)制,主從、PXC、MHA等多種環(huán)境都是有在用的.
Q3:生產(chǎn)環(huán)境,1T數(shù)據(jù)量用什么備份好?
A3:我的建議是你可以使用mysqlbackup,比較下來,這個速度算是很快的,不過當(dāng)你的數(shù)據(jù)量達到一個T時,也應(yīng)該去考慮如何分庫分表,當(dāng)做到這一點的時候,也是化整為零,可以把備份和正常的負(fù)載都分?jǐn)偟蕉嗯_服務(wù)器上.
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/3735.html