前言:本篇主要講 1.使用Mysqldump結合binlog日誌備份與恢復
2.使用xtrabackup進行Mysql數據庫備份與恢復
################# mysqldump備份結合binlog日誌恢復功能介紹 #####################
MySQL備份一般採取全庫備份加日誌備份的方式,例如每天執行一次全備份,每小時執行一次二進制日誌備份。這樣在MySQL故障後可以使用全備份和日誌備份將數據恢復到最後一個二進制日誌備份前的任意位置或時間。
1、binlog介紹
mysql的二進制日誌記錄着該數據庫的所有增刪改的操作日誌(前提是要在自己的服務器上開啓binlog),還包括了這些操作的執行時間。爲了顯示這些二進制內容,我們可以使用mysqlbinlog命令來查看。
Binlog的用途
1:主從同步
2:恢復數據庫
開啓binary log功能
通過編輯my.cnf中的log-bin選項可以開啓二進制日誌;形式如下:
log-bin [=DIR/[filename]]
其中,DIR參數指定二進制文件的存儲路徑;filename參數指定二級制文件的文件名,其形式爲filename.number,number的形式爲000001、000002等。每次重啓mysql服務或運行mysql> flush logs;都會生成一個新的二進制日誌文件,這些日誌文件的number會不斷地遞增。除了生成上述的文件外還會生成一個名爲filename.index的文件。這個文件中存儲所有二進制日誌文件的清單又稱爲二進制文件的索引
配置保存以後重啓mysql的服務器,用mysql> show variables like 'log_bin';查看bin-log是否開啓;
查看產生的binary log 注:查看binlog內容是爲了恢復數據
bin-log因爲是二進制文件,不能通過文件內容查看命令直接打開查看,mysql提供兩種方式查看方式,在介紹之前,我們先對數據庫進行一下增刪改的操作,否則log裏邊數據有點空。
#mysql -uroot -p -e "resetmaster"
#mysql -uroot -p -e "createdatabase test"
#mysql -uroot -p -e "usetest;create table tb1(id int primary key auto_increment,name varchar(20))"
#mysql -uroot -p -e "insert intotest.tb1(name) values('lisi')"
#mysql -uroot -p -e "insert intotest.tb1(name) values('zhangsan')"
重新開始一個新的日誌文件
#mysql -uroot -p -e "flushlogs"
#mysql -uroot -p -e "delete fromtest.tb1 where id=2"
#mysql -uroot -p -e "insert intotest.tb1(name) values('tom')"
# mysql -uroot -p -e "select * fromtest.tb1"
Enter password:
+----+------+
| id | name |
+----+------+
| 1 | lisi |
| 3 | tom |
+----+------+
查看MySQL Server上的二進制日誌
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 1087 |
| mysql-bin.000002 | 673 |
+------------------+-----------+
查看二進制日誌信息的命令:
語法格式:SHOW BINLOG EVENTS [IN
'log_name'] [FROMpos] [LIMIT [offset,] row_count]
查看二進制日誌中的事件
mysql> show binlog events;
默認顯示可找到的第一個二進制日誌文件中的事件,包含了日誌文件名、事件的開始位置、事件類型、結束位置、信息等內容
+------------------+------+----------------+-----------+-------------+----------------------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+------+----------------+-----------+-------------+----------------------------------------------------------------------------------+
| mysql-bin.000001 | 4 | Format_desc | 1 | 123 | Server ver:5.7.13-log, Binlog ver: 4 | //此事件爲格式描述事件
| mysql-bin.000001 | 123 | Previous_gtids | 1| 154 | |
| mysql-bin.000001 | 154 | Anonymous_Gtid | 1| 219 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000001 | 219 | Query | 1 | 313 | create database test | //爲查詢事件
| mysql-bin.000001 | 313 | Anonymous_Gtid | 1| 378 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000001 | 378 | Query | 1 | 520 | use `test`; create table tb1(idint primary key auto_increment,name varchar(20)) |
| mysql-bin.000001 | 520 | Anonymous_Gtid | 1| 585 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000001 | 585 | Query | 1 | 653 | BEGIN | //爲查詢事件,事務開始
| mysql-bin.000001 | 653 | Table_map | 1 | 702 | table_id: 110(test.tb1) | //爲表映射事件
| mysql-bin.000001 | 702 | Write_rows | 1 | 747 | table_id: 110flags: STMT_END_F | //爲我們執行的insert事件
| mysql-bin.000001 | 747 | Xid | 1 | 778 | COMMIT /* xid=2052 */ | //Xid時間是自動提交事務的動作
| mysql-bin.000001 | 778 | Anonymous_Gtid | 1| 843 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000001 | 843 | Query | 1 | 911 | BEGIN |
| mysql-bin.000001 | 911 | Table_map | 1 | 960 | table_id: 110(test.tb1) |
| mysql-bin.000001 | 960 | Write_rows | 1 | 1009 | table_id: 110flags: STMT_END_F |
| mysql-bin.000001 | 1009 | Xid | 1 | 1040 | COMMIT /* xid=2055 */ |
| mysql-bin.000001 | 1040 | Rotate | 1 | 1087 |mysql-bin.000002;pos=4 //爲日誌輪換事件,是我們執行flush logs開啓新日誌文件引起的。
查看指定的二進制日誌中的事件
mysql> show binlog events in'mysql-bin.000002';
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| mysql-bin.000002 | 4 | Format_desc | 1 | 123 | Server ver:5.7.13-log, Binlog ver: 4 |
| mysql-bin.000002 | 123 |Previous_gtids | 1 | 154 | |
| mysql-bin.000002 | 154 |Anonymous_Gtid | 1 | 219 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000002 | 219 | Query | 1 | 287 | BEGIN |
| mysql-bin.000002 | 287 | Table_map | 1 | 336 | table_id: 110(test.tb1) |
| mysql-bin.000002 | 336 | Delete_rows | 1 | 385 | table_id: 110 flags:STMT_END_F |
| mysql-bin.000002 | 385 | Xid | 1 | 416 | COMMIT /* xid=2068 */ |
| mysql-bin.000002 | 416 |Anonymous_Gtid | 1 | 481 | SET @@SESSION.GTID_NEXT='ANONYMOUS' |
| mysql-bin.000002 | 481 | Query | 1 | 549 | BEGIN |
| mysql-bin.000002 | 549 | Table_map | 1 | 598 | table_id: 110(test.tb1) |
| mysql-bin.000002 | 598 | Write_rows | 1 | 642 | table_id: 110 flags:STMT_END_F |
| mysql-bin.000002 | 642 | Xid | 1 | 673 | COMMIT /* xid=2071 */ |
該命令還包含其他選項以便靈活查看
mysql> show binlog events in'mysql-bin.000002' from 219 limit 1,3;
+------------------+-----+-------------+-----------+-------------+---------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+---------------------------------+
| mysql-bin.000002 | 287 |Table_map | 1 | 336 | table_id: 110 (test.tb1) |
| mysql-bin.000002 | 336 | Delete_rows| 1 | 385 | table_id: 110 flags: STMT_END_F |
| mysql-bin.000002 | 385 | Xid | 1 | 416 | COMMIT /* xid=2068 */ |
SHOW BINARY LOGS等價於 SHOW MASTER LOGS
PURGE BINARY LOGS用於刪除二進制日誌,如:
PURGE BINARY LOGS TO 'mysql-bin.00010'; //把這個文件之前的其他文件都刪除掉
PURGE BINARY LOGS BEFORE '2016-08-28 22:46:26';//把指定時間之前的二進制文件刪除了
RESET MASTER 與 RESET SLAVE
前者清空index文件中列出的所有二進制日誌,重置index文件爲空,並創建一個新的二進制日誌文件,一般用於MASTER首次啓動時。後者使SLAVE忘記其在MASTER二進制日誌文件中的複製位置,它會刪除master.info、relay-log.info和所有中繼日誌文件並開始一個新的中繼日誌文件,以便於開始一個乾淨的複製。在使用RESET SLAVE前需先關閉 SLAVE複製線程。
上述方式可以查看到服務器上存在的二進制日誌文件及文件中的事件,但是想查看到文件中具體的內容並應於恢復場景還得藉助mysqlbinlog這個工具。
語法格式: mysqlbinlog [options] log_file ...
輸出內容會因日誌文件的格式以及mysqlbinlog工具使用的選項不同而略不同。
mysqlbinlog的可用選項可參考man手冊。
二進制日誌文件的格式包含行模式、語句模式和混合模式(也即有服務器決定在什麼情況下記錄什麼類型的日誌),基於語句的日誌中事件信息包含執行的語句等,基於行的日誌中事件信息包含的是行的變化信息等。混合模式的日誌中兩種類型的事件信息都會記錄。
爲了便於查看記錄了行變化信息的事件在當時具體執行了什麼樣的SQL語句可以使用mysqlbinlog工具的-v(--verbose)選項,該選項會將行事件重構成被註釋掉的僞SQL語句,如果想看到更詳細的信息可以將該選項給兩次如-vv,這樣可以包含一些數據類型和元信息的註釋內容,如
先切換到binlog所在的目錄下
#mysqlbinlog mysql-bin.000001
#mysqlbinlog -v mysql-bin.000001
#mysqlbinlog -vv mysql-bin.000001
另外mysqlbinlog和可以通過--read-from-remote-server選項從遠程服務器讀取二進制日誌文件,這時需要一些而外的連接參數,如-h,-P,-p,-u等,這些參數僅在指定了--read-from-remote-server後有效。
無論是本地二進制日誌文件還是遠程服務器上的二進制日誌文件,無論是行模式、語句模式還是混合模式的二進制日誌文件,被mysqlbinlog工具解析後都可直接應用與MySQL Server進行基於時間點、位置或數據庫的恢復。
下面我們就來演示如何使用binlog恢復之前刪除數據(id=2那條記錄)
注意:在實際生產環境中,如果遇到需要恢復數據庫的情況,不要讓用戶能訪問到數據庫,以避免新的數據插入進來,以及在主從的環境下,關閉主從。
查看binlog文件,從中找出delete from test.tb1 where id=2
# cd /usr/local/mysql/data/
# mysqlbinlog -v mysql-bin.000002
顯示結果
# at 219
#160913 20:59:51 server id1 end_log_pos 287CRC32 0x1a97741b Query thread_id=42 exec_time=0 error_code=0
SETTIMESTAMP=1473771591/*!*/;
SET @@session.pseudo_thread_id=42/*!*/;
SET@@session.foreign_key_checks=1, @@session.sql_auto_is_null=0,@@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET@@session.sql_mode=1075838976/*!*/;
SET@@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET@@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET@@session.lc_time_names=0/*!*/;
SET@@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at287
#160913 20:59:51 server id1 end_log_pos 336 CRC32 0x930ab248 Table_map: `test`.`tb1` mapped to number 125
# at 336
#160910 23:17:43 server id 1 end_log_pos 385CRC32 0xdede3eb7 Delete_rows: table id 110 flags: STMT_END_F
BINLOG '
FyTUVxMBAAAAMQAAAFABAAAAAG4AAAAAAAEABHRlc3QAA3RiMQACAw8CPAAC2t7UdQ==
FyTUVyABAAAAMQAAAIEBAAAAAG4AAAAAAAEAAgAC//wCAAAACHpoYW5nc2Futz7e3g==
'/*!*/;
### DELETE FROM `test`.`tb1`
### WHERE
### @1=2
### @2='zhangsan'
# at385
#160910 23:17:43 server id1 end_log_pos416 CRC32 0x7881c9da Xid = 2068
COMMIT/*!*/;
從中可以看出delete事件發生position是287,事件結束position是416
恢復流程:直接用bin-log日誌將數據庫恢復到刪除位置287前,然後跳過故障點,再進行恢復下面所有的操作,命令如下
由於之前沒有做過全庫備份,所以要使用所有binlog日誌恢復,所以生產環境中需要很長時間恢復,導出相關binlog文件
#mysqlbinlog /usr/local/mysql/data/mysql-bin.000001> /opt/mysql-bin.000001.sql
#mysqlbinlog --stop-position=287/usr/local/mysql/data/mysql-bin.000002 > /opt/287.sql
#mysqlbinlog --start-position=416/usr/local/mysql/data/mysql-bin.000002 > /opt/416.sql
刪除test數據庫
mysql>drop database test;
利用binlog恢復數據
#mysql -uroot -p123456</opt/mysql-bin.000001.sql
#mysql -uroot -p123456< /opt/287.sql
#mysql -uroot -p123456< /opt/416.sql
恢復完成後,我們檢查下表的數據是否完整
mysql> select * from test.tb1;
+----+----------+
| id | name |
+----+----------+
| 1 | lisi |
| 2 | zhangsan |
| 3 | tom |
+----+----------+
Ok完整的都恢復過來了
mysqlbinlog 選項示例
常見的選項有以下幾個:
--start-datetime
從二進制日誌中讀取指定時間戳或者本地計算機時間之後的日誌事件。
--stop-datetime
從二進制日誌中讀取指定時間戳或者本地計算機時間之前的日誌事件。
--start-position
從二進制日誌中讀取指定position 事件位置作爲開始。
--stop-position
從二進制日誌中讀取指定position 事件位置作爲事件截至。
2、mysqldump介紹
mysqldump是mysql用於備份和數據轉移的一個工具。它主要產生一系列的SQL語句,可以封裝到文件,該文件包含有所有重建你的數據庫所需要的 SQL命令如CREATE DATABASE,CREATE TABLE,INSERT等等。可以用來實現輕量級的快速遷移或恢復數據庫。
mysqldump 是將數據表導成 SQL 腳本文件,在不同的 MySQL 版本之間升級時相對比較合適,這也是最常用的備份方法。
mysqldump一般在數據量很小的時候(幾個G)可以用於備份。當數據量比較大的情況下,就不建議用mysqldump工具進行備份了。
數據庫的導出
導出對象說明:
mysqldump可以針對單個表、多個表、單個數據庫、多個數據庫、所有數據庫進行導出的操作
# mysqldump [options] db_name [tbl_name...] //導出指定數據庫或單個表
# mysqldump [options] --databases db_name... //導出多個數據庫
#mysqldump [options] --all-databases //導出所有
導出數據庫test
# mysqldump -uroot -p --flush-logs test> /opt/test.sql //--flush-logs這個選項就會完整備份的時候重新開啓一個新binlog
數據庫的導入
# mysql -uroot -p test </opt/test.sql
在前面我們介紹了mysql的binlog和mysqldump工具,下面我們來學習如何實現mysqldump全庫備份+binlog的數據恢復
環境準備與備份還原:
檢查開啓binlog
先創建一些原始數據
mysql> reset master;
mysql> create database test_db;
mysql> use test_db;
mysql> create table tb1(id intprimary key auto_increment,name varchar(20));
mysql> insert into tb1(name)values('tom1');
mysql> insert into tb1(name)values('tom2');
mysql> commit;
mysql> select * from tb1;
+----+------+
| id | name |
+----+------+
| 1 | tom1 |
| 2 | tom2 |
+----+------+
實施方案:mysqldump全庫備份+binlog還原
1、mysqldump備份方案:
每週一凌晨1點全庫備份
2、備份步驟
(1) 創建備份目錄
# mkdir /opt/mysqlbackup
# mkdir /opt/mysqlbackup/daily
(2)全庫備份
這裏我們模擬週一的完整備份數據庫任務
#mysqldump -uroot -p --flush-logstest_db > /opt/mysqlbackup/test_db_2016_09_12.sql
[root@localhost data]# ls -l/opt/mysqlbackup/
-rw-r--r--. 1 root root 1871 Sep 1321:06 test_db_2016_09_12.sql
備份mysqldump全庫備份之前的binlog日誌文(注:生產環境中可能不只一個binlog文件)
# cp/usr/local/mysql/data/mysql-bin.000001 /opt/mysqlbackup/daily/
# mysql -uroot -p -e "purge binarylogs to 'mysql-bin.000002'"
模擬下操作失誤,將數據修改錯誤了。
mysql> use test_db;
mysql> delete from tb1 where id=1;
mysql> commit;
mysql> insert into tb1(name)values('tom3');
mysql> commit;
備份自mysqldump之後的binlog日誌文件
cp/usr/local/mysql/data/mysql-bin.000002 /opt/mysqlbackup/daily/
上面的模擬的誤操作是刪除了id=1的記錄
(3)現在我們使用mysqldump的全庫備份和binlog來恢復數據。
使用mysqldump的備份進行全庫恢復
# mysql -uroot -p test_db </opt/mysqlbackup/test_db_2016_09_12.sql
查詢一下數據
[root@localhost ~]# mysql -uroot -p -e"select * from test_db.tb1"
Enter password:
+----+------+
| id | name |
+----+------+
| 1 | tom1 |
| 2 | tom2 |
+----+------+
從顯示結果可以看到使用mysqldump備份將數據還原到了備份時的狀態,剛纔刪除的數據(id=2)恢復回來了,但備份後產生的數據卻丟失了所以還得利用binlog進一步不原
因爲刪除是在全庫備份後發生的,而mysqldump全庫備份時使用--flush-logs選項,所以只需要分析全庫備份後的binlog即mysql-bin.000002。
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000002| 1853 |
+------------------+-----------+
查看mysql-bin.000002中的事件,可以看到有刪除事件
mysql> show binlog events in'mysql-bin.000002';
| mysql-bin.000002 | 219 |Query | 1 | 294 | BEGIN |
| mysql-bin.000002 | 294 | Table_map | 1 | 346 | table_id: 118 (test_db.tb1) |
| mysql-bin.000002 | 346 | Delete_rows | 1 | 391 | table_id: 118 flags:STMT_END_F |
| mysql-bin.000002 | 391 | Xid | 1 | 422 | COMMIT /* xid=2739 */
使用mysqlbinlog 命令可以查看備份的binlog文件的詳細事件。
恢復流程:我們直接用bin-log日誌將數據庫恢復到刪除位置前,然後跳過故障點,再進行恢復刪除後的所有操作。
# mysqlbinlog -v /opt/mysqlbackup/daily/mysql-bin.000002
我們先用mysqlbinlog命令找到delete那條語句的位置
# at 219
#160911 17:19:55 server id 1 end_log_pos 294 CRC32 0x84590493 Query thread_id=66 exec_time=0 error_code=0
SET TIMESTAMP=1473585595/*!*/;
SET @@session.pseudo_thread_id=66/*!*/;
SET @@session.foreign_key_checks=1,@@session.sql_auto_is_null=0, @@session.unique_checks=1,@@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET@@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET@@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET@@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 294
#160911 17:19:55 server id 1 end_log_pos 346 CRC32 0x5cdccf9e Table_map: `test_db`.`tb1` mapped to number 118
# at 346
#160911 17:19:55 server id 1 end_log_pos 391 CRC32 0x320c4935 Delete_rows: table id 118 flags:STMT_END_F
BINLOG '
uyHVVxMBAAAANAAAAFoBAAAAAHYAAAAAAAEAB3Rlc3RfZGIAA3RiMQACAw8CPAACns/cXA==
uyHVVyABAAAALQAAAIcBAAAAAHYAAAAAAAEAAgAC//wBAAAABHRvbTE1SQwy
'/*!*/;
### DELETE FROM `test_db`.`tb1`
### WHERE
### @1=1
### @2='tom1'
# at 391
#160911 17:19:55 server id 1 end_log_pos 422 CRC320x5e4a6699 Xid = 2739
COMMIT/*!*/;
通過mysqlbinlog命令所顯示的結果可以看到誤操作delete的開始postion爲219,結束position是422。
從二進制日誌中讀取指定position=219事件位置作爲截至,即把數據恢復到delete刪除前
# mysqlbinlog --stop-position=219/opt/mysqlbackup/daily/mysql-bin.000002 | mysql -u root -p
從二進制日誌中讀取指定position=422事件位置作爲開始,即跳過刪除事件,恢復刪除事件之後對數據的正常操作
#mysqlbinlog --start-position=422/opt/mysqlbackup/daily/mysql-bin.000002 | mysql -u root -p
查看恢復結果:
# mysql -uroot -p -e "select * fromtest_db.tb1"
Enter password:
+----+------+
| id | name |
+----+------+
| 1 | tom1 |
| 2 | tom2 |
| 3 | tom3 |
+----+------+
從上面顯示可以看出數據恢復到正常狀態
生產環境中Mysql數據庫的備份是週期性重複的操作,所以通常是要編寫腳本實現,通過crond計劃任務週期性執行備份腳本
mysqldump備份方案:
週日凌晨1點全庫備份
週一到週六凌晨每隔4個小時增量備份一次
設置crontab任務,每天執行備份腳本
# crontab –e
#每個星期日凌晨1:00執行完全備份腳本
0 1 * * 0 /root/mysqlfullbackup.sh >/dev/null 2>&1
#週一到週六每隔4個小時增量備份一次
0 */4 * * 1-6 /root/mysqldailybackup.sh >/dev/null 2>&1
mysqlfullbackup.sh腳本內容:
[root@localhost ~]# catmysqlfullbackup.sh
#!/bin/sh
# Name:mysqlFullBackup.sh
# 定義數據庫目錄
mysqlDir=/usr/local/mysql
# 定義用於備份數據庫的用戶名和密碼
user=root
userpwd=123456
dbname=test_db
# 定義備份目錄
databackupdir=/opt/mysqlbackup
[ ! -d $databackupdir ] && mkdir$databackupdir
# 定義郵件正文文件
emailfile=$databackupdir/email.txt
# 定義郵件地址
# 定義備份日誌文件
logfile=$databackupdir/mysqlbackup.log
DATE=`date -I`
echo "" > $emailfile
echo $(date +"%y-%m-%d%H:%M:%S") >> $emailfile
cd $databackupdir
# 定義備份文件名
dumpfile=mysql_$DATE.sql
gzdumpfile=mysql_$DATE.sql.tar.gz
# 使用mysqldump備份數據庫,請根據具體情況設置參數
$mysqlDir/bin/mysqldump -u$user-p$userpwd --flush-logs -x $dbname > $dumpfile
# 壓縮備份文件
if [ $? -eq 0 ]; then
tar czf $gzdumpfile $dumpfile >> $emailfile 2>&1
echo "BackupFileName:$gzdumpfile" >> $emailfile
echo "DataBase Backup Success!" >> $emailfile
rm -f $dumpfile
else
echo "DataBase Backup Fail!" >> $emailfile
fi
# 寫日誌文件
echo "--------------------------------------------------------">> $logfile
cat $emailfile >> $logfile
# 發送郵件通知
cat $emailfile | mail -s "MySQLBackup" $email
mysqldailybackup.sh腳本內容:
[root@localhost ~]# catmysqldailybackup.sh
#!/bin/sh
# Name:mysqlDailyBackup.sh
# 定義數據庫目錄和數據目錄
mysqldir=/usr/local/mysql
datadir=$mysqldir/data
# 定義用於備份數據庫的用戶名和密碼
user=root
userpwd=123456
# 定義備份目錄,每日備份文件備份到$dataBackupDir/daily
databackupdir=/opt/mysqlbackup
dailybackupdir=$databackupdir/daily
[ ! -d $dailybackupdir ] &&mkdir -p $databackupdir/daily
# 定義郵件正文文件
emailfile=$databackupdir/email.txt
# 定義郵件地址
# 定義日誌文件
logfile=$databackupdir/mysqlbackup.log
echo "" > $emailfile
echo $(date +"%y-%m-%d%H:%M:%S") >> $emailfile
#
# 刷新日誌,使數據庫使用新的二進制日誌文件
$mysqldir/bin/mysqladmin -u$user-p$userpwd flush-logs
cd $datadir
# 得到二進制日誌列表
filelist=`cat mysql-bin.index`
icounter=0
for file in $filelist
do
icounter=`expr $icounter + 1`
done
nextnum=0
ifile=0
for file in $filelist
do
binlogname=`basename $file`
nextnum=`expr $nextnum + 1`
# 跳過最後一個二進制日誌(數據庫當前使用的二進制日誌文件)
if [ $nextnum -eq $icounter ]; then
echo "Skip lastest!" > /dev/null
else
dest=$dailybackupdir/$binlogname
# 跳過已經備份的二進制日誌文件
if [ -e $dest ]; then
echo "Skip exist $binlogname!" > /dev/null
else
# 備份日誌文件到備份目錄
cp $binlogname $dailybackupdir
if [ $? -eq 0 ]; then
ifile=`expr $ifile + 1`
echo "$binlogname backup success!" >> $emailfile
fi
fi
fi
done
if [ $ifile -eq 0 ];then
echo "No Binlog Backup!" >> $emailfile
else
echo "Backup $ifile File(s)." >> $emailfile
echo "Backup MySQL Binlog OK!" >> $emailfile
fi
# 發送郵件通知
cat $emailfile | mail -s "MySQLBackup" $email
# 寫日誌文件
echo"--------------------------------------------------------" >>$logfile
cat $emailfile >> $logfile
################### 使用xtrabackup進行MySQL數據庫備份 #########################
前面介紹mysqldump備份方式是採用邏輯備份,其最大的缺陷就是備份和恢復速度都慢,對於一個小於50G的數據庫而言,這個速度還是能接受的,但如果數據庫非常大,那再使用mysqldump備份就不太適合了。
這時就需要一種好用又高效的工具,xtrabackup就是其中一款,號稱免費版的InnoDB HotBackup。
Xtrabackup實現不是物理備份,而且是物理熱備
目前主流的有兩個工具可以實現物理熱備:ibbackup和xtrabackup;ibbackup是商業軟件,需要授權,非常昂貴。而xtrabackup功能比ibbackup還要強大,但卻是開源的。因此我們這裏就來介紹xtrabackup的使用。
Xtrabackup提供了兩種命令行工具:
xtrabackup:專用於備份InnoDB和XtraDB引擎的數據;
innobackupex:這是一個perl腳本,在執行過程中會調用xtrabackup命令,這樣用該命令即可以實現備份InnoDB,也可以備份MyISAM引擎的對象。
Xtrabackup是由percona提供的mysql數據庫備份工具,特點:
(1)備份過程快速、可靠;
(2)備份過程不會打斷正在執行的事務;
(3)能夠基於壓縮等功能節約磁盤空間和流量;
(4)自動實現備份檢驗;
(5)還原速度快。
官方鏈接地址:http://www.percona.com/software/percona-xtrabackup;可以下載源碼編譯安裝,也可以下載適合的RPM包或使用yum進行安裝或者下載二進制源碼包。
安裝xtrabackup
1)下載xtrabackup
2)解壓
# tar zxf percona-xtrabackup-2.4.4-Linux-x86_64.tar.gz
3)進入解壓目錄
# cdpercona-xtrabackup-2.4.4-Linux-x86_64/
4)複製bin下的所有程序到/usr/bin
[[email protected]_64]# cp bin/* /usr/bin/
Xtrabackup中主要包含兩個工具:
xtrabackup:是用於熱備份innodb,xtradb表中數據的工具,支持在線熱備份,可以在不加鎖的情況下備份Innodb數據表,不過此工具不能操作Myisam引擎表;
innobackupex:是將xtrabackup進行封裝的perl腳本,能同時處理Innodb和Myisam,但在處理Myisam時需要加一個讀鎖。
由於操作Myisam時需要加讀鎖,這會堵塞線上服務的寫操作,而Innodb沒有這樣的限制,所以數據庫中Innodb表類型所佔的比例越大,則越有利。
4)安裝相關插件
#yum install perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSLperl-TermReadKey.x86_64 perl-Digest-MD5 –y
5)下載percona-toolkit並安裝
#wget https://www.percona.com/downloads/percona-toolkit/2.2.19/RPM/percona-toolkit-2.2.19-1.noarch.rpm
# rpm -vih percona-toolkit-2.2.19-1.noarch.rpm
下面就可以啓動備份了
方案一:xtrabackup完全備份+binlog增量備份
1、備份
創建備份目錄
# mkdir -p/opt/mysqlbackup/{full,inc}
full:全備存放的目錄;inc:增量備份存放的目錄
1)完全備份
基本語法:# innobackupex--user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/
執行下面的命令進行完全備份:
#innobackupex --user=root --password=123456 /opt/mysqlbackup/full
注: --defaults-file=/etc/my.cnf 指定mysql的配置文件my.cfg,如果指定則必須是第一個參數。
/path/to/BACKUP-DIR/指定備份所存放的目標目錄,備份過程會創建一個以當時備份時間命名的目錄存放備份文件。
出現如下提示。表示成功
備份後的文件:
在備份的同時,備份數據會在備份目錄下創建一個以當前日期時間爲名字的目錄存放備份文件:
各文件說明:
(1)xtrabackup_checkpoints—— 備份類型(如完全或增量)、備份狀態(如是否已經爲prepared狀態)和LSN(日誌序列號)範圍信息;
每個InnoDB頁(通常爲16k大小)都會包含一個日誌序列號,即LSN。LSN是整個數據庫系統的系統版本號,每個頁面相關的LSN能夠表明此頁面最近是如何發生改變的。
(2)xtrabackup_binlog_info—— mysql服務器當前正在使用的二進制日誌文件及至備份這一刻爲止二進制日誌事件的位置。
(3)xtrabackup_binlog_pos_innodb—— 二進制日誌文件及用於InnoDB或XtraDB表的二進制日誌文件的當前position。
(4)xtrabackup_binary—— 備份中用到的xtrabackup的可執行文件;
(5)backup-my.cnf—— 備份命令用到的配置選項信息;
在使用innobackupex進行備份時,還可以使用--no-timestamp選項來阻止命令自動創建一個以時間命名的目錄;如此一來,innobackupex命令將會創建一個BACKUP-DIR目錄來存儲備份數據
注意:相關選項說明:
其中,--user指定連接數據庫的用戶名,--password指定連接數據庫的密碼,--defaults-file指定數據庫的配置文件,innobackupex要從其中獲取datadir等信息;--database指定要備份的數據庫,這裏指定的數據庫只對MyISAM表有效,對於InnoDB 數據來說都是全備(所有數據庫中的InnoDB數據都進行了備份,不是隻備份指定的數據庫,恢復時也一樣);/opt/mysqlbackup/full是備份文件的存放位置。
注意:備份數據庫的用戶需要具有相應權限,如果要使用一個最小權限的用戶進行備份,則可基於如下命令創建此類用戶:
mysql> create user 'bkpuser'@'localhost' identified by'123456';
mysql> revoke all privileges,grant option from'bkpuser'@'localhost';
mysql> grant reload,lock tables,replication client,process on *.* to 'bkpuser'@'localhost';
mysql> flush privileges;
至此全備完全成功,然後向mysql某個庫插入幾條數據,然後進行增量備份
對完全備份的後數據庫更改進行二進制日誌增量備份:
查看完全備份時binlog日誌位置(position):
模擬數據庫修改:
2)增量備份二進制文件:
#mysqlbinlog--start-position=2378 /usr/local/mysql/data/mysql-bin.000023 >/opt/mysqlbackup/inc/`date +%F`.sql
2、還原數據庫:
模擬數據庫損壞:
我這裏直接使用刪除數據目錄文件來模擬損壞。
# rm -fr/usr/local/mysql/data/*
還原完全備份:
(1)準備(prepare)一個完全備份
一般情況下,在備份完成後,數據尚且不能用於恢復操作,因爲備份的數據中可能會包含尚未提交的事務或已經提交但尚未同步至數據文件中的事務。因此,此時數據文件仍處理不一致狀態。“準備”的主要作用正是通過回滾未提交的事務及同步已經提交的事務至數據文件也使得數據文件處於一致性狀態。
在準備(prepare)過程結束後,InnoDB表數據已經前滾到整個備份結束的點,而不是回滾到xtrabackup剛開始時的點。
innobakupex命令的--apply-log選項可用於實現上述功能。如下面的命令:
--apply-log指明是將日誌應用到數據文件上,完成之後將備份文件中的數據恢復到數據庫中:
#innobackupex --apply-log /opt/mysqlbackup/full/2016-09-12_11-29-55/
注:/opt/mysqlbackup/full/2016-09-12_11-29-55/備份文件所在目錄名稱
如果執行正確,其最後輸出的幾行信息通常如下:
在實現“準備”的過程中,innobackupex通常還可以使用--use-memory選項來指定其可以使用的內存的大小,默認通常爲100M。如果有足夠的內存可用,可以多劃分一些內存給prepare的過程,以提高其完成速度。
innobackupex命令的--copy-back選項用於執行恢復操作,其通過複製所有數據相關的文件至mysql服務器DATADIR目錄中來執行恢復過程。innobackupex通過backup-my.cnf來獲取DATADIR目錄的相關信息。
(2)還原數據庫語法:
#innobackupex --copy-back /opt/mysqlbackup/full/2016-09-12_11-29-55/
這裏的--copy-back指明是進行數據恢復。數據恢復完成之後,需要修改相關文件的權限mysql數據庫才能正常啓動。
如果執行正確,其輸出信息的最後幾行通常如下:
請確保如上信息的最行一行出現“completedOK!”。
修改還原後的數據目錄權限:
當數據恢復至DATADIR目錄以後,還需要確保所有數據文件的屬主和屬組均爲正確的用戶,如mysql,否則,在啓動mysqld之前還需要事先修改數據文件的屬主和屬組。如:
# chown -Rmysql:mysql /usr/local/mysql/data/
重啓動MySQL:
# systemctlrestart mysqld
驗證還原後的數據:
mysql>select * from tb1;
+----+------+
| id | name |
+----+------+
| 1 | tom1 |
| 2 | tom2 |
+----+------+
(3)還原增量備份:
爲了防止還原時產生大量的二進制日誌,在還原時可臨時關閉二進制日誌後再還原:
mysql> setsql_log_bin=0;
mysql>source /opt/mysqlbackup/inc/2016-09-12.sql
重新啓動二進制日誌並驗證還原數據:
mysql> setsql_log_bin=1;
驗證數據是否恢復回來:
方案二、xtrabackup完全備份+xtrabacup增量備份
前面我們進行增量備份時,使用的還是老方法:備份二進制日誌。其實xtrabackup還支持進行增量備份。
先介紹下xtrabackup的備份原理
在InnoDB內部會維護一個redo日誌文件,我們也可以叫做事務日誌文件(transaction log,事務日誌)。事務日誌會存儲每一個InnoDB表數據的記錄修改。當InnoDB啓動時,InnoDB會檢查數據文件和事務日誌,並執行兩個步驟:它應用已經提交的事務日誌到數據文件,並將修改過但沒有提交的數據進行回滾操作。
xtrabackup在啓動時會記住logsequence number(LSN),並且複製所有的數據文件。複製過程需要一些時間,所以這期間如果數據文件有改動,那麼將會使數據庫處於一個不同的時間點。這時,xtrabackup會運行一個後臺進程,用於監視事務日誌,並從事務日誌複製最新的修改。xtrabackup必須持續的做這個操作,是因爲事務日誌是會輪轉重複的寫入,並且事務日誌可以被重用。所以xtrabackup自啓動開始,就不停的將事務日誌中每個數據文件的修改都記錄下來。這就是xtrabackup的備份過程
所以每個InnoDB的頁面都會包含一個LSN信息,每當相關的數據發生改變,相關的頁面的LSN就會自動增長。這正是InnoDB表可以進行增量備份的基礎。
xtraBackup基於InnoDB的crash-recovery功能。它會複製innodb的data file,由於不鎖表,複製出來的數據是不一致的,在恢復的時候使用crash-recovery,使得數據恢復一致。
當InnoDB啓動的時候,它會先去檢查datafile和transaction log,並且會做二步操作:
1.It appliescommitted transaction logentries to the data files
2.it performsan undo operation on anytransactions that modified data but did not commit.
所以在prepare過程中,XtraBackup使用複製到的transactionslog對備份出來的innodb data file進行crash recovery。
測試環境準備
創建一個測試數據庫,並創建一張表輸入幾行數據
mysql>create database test;
mysql> usetest;
mysql>create table xx(id int,name varchar(20));
mysql>insert into xx values(1,'tom1');
mysql>insert into xx values(2,'tom2');
1、 xtrabacup進行備份
執行完全備份:
備份命令:
# xtrabackup --defaults-file=/etc/my.cnf --user=root--password="123456" --port=3306 --backup--target-dir=/opt/mysqlbackup/full/full_incre_$(date +%Y%m%d_%H%M%S)
部分顯示信息如下圖所示:
其中,--defaults-file指定數據庫的配置文件,如果使用該參數必須做爲第一個參數;--user指定連接數據庫的用戶名;--password指定連接數據庫的密碼;--port指定連接數據庫的端口號;--backup 實施備份到target-dir; --target-dir=name 備份文件的存放目錄路徑。innobackupex要從其中獲取datadir等信息;--database指定要備份的數據庫,這裏指定的數據庫只對MyISAM表和InnoDB表的表結構有效,對於InnoDB 數據來說都是全備(所有數據庫中的InnoDB數據都進行了備份,不是隻備份指定的數據庫,恢復時也一樣);/opt/mysqlbackup/full/是備份文件的存放位置。
查看完全備份文件
[root@localhost~]# ls /opt/mysqlbackup/full/ -l
drwxr-x---. 8root root 4096 Sep 12 22:11 full_incre_20160912_221111
xtrabackup進行增量備份
先錄入些數據,實現第一次增量數據:
mysql> use test;
mysql> insert into xx values(3,'tom3');
再進行增量備份1
備份命令:
# xtrabackup --defaults-file=/etc/my.cnf --user=root--password="123456" --port=3306 --backup--target-dir=/opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S) --incremental-basedir=/opt/mysqlbackup/full/full_incre_20160912_221111/
部分顯示信息如下圖所示:
其中,--incremental-basedir指定上次完整備份或者增量備份文件的位置(即如果是第一次增量備份則指向完全備份所在目錄,在執行過增量備份之後再一次進行增量備份時,其--incremental-basedir應該指向上一次的增量備份所在的目錄)。
查看增量備份文件:
[root@localhost ~]# ls -l /opt/mysqlbackup/inc/
drwxr-x---. 8 root root 4096 Sep 12 22:15 incre_20160912_221510
注:
這裏的增量備份其實只針對的是InnoDB,對於MyISAM來說,還是完整備份。
向表中再插入幾行數據,繼續第二次增量備份
mysql> usetest;
mysql>insert into xx values(4,'tom4');
mysql>commit;
進行第二次增量備份
備份命令:
# xtrabackup --defaults-file=/etc/my.cnf --user=root--password="123456" --port=3306 --backup--target-dir=/opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S)--incremental-basedir=/opt/mysqlbackup/inc/incre_20160912_221510/
部分顯示信息如下圖所示:
注:第二次增量備份--incremental-basedir指向上一次增量備份文件的位置。
查看增量備份文件
[root@localhost~]# ls -l /opt/mysqlbackup/inc/
drwxr-x---. 8root root 4096 Sep 12 22:15 incre_20160912_221510
drwxr-x---. 8root root 4096 Sep 12 22:19 incre_20160912_221916
1、 xtrabacup進行增量恢復
爲了驗證比對,先刪除兩個增量備份前表裏面的數據
mysql> usetest;
mysql>delete from xx where id=3;
完整備份恢復:
在進行恢復前,如果完整備份在遠程主機上,首先將完整備份複製到本地主機上,如果是tar包,則需要先解包,解包命令爲:tar –izxf xxx.tar,這裏必須使用-i參數(忽略存檔中的 0 字節塊(通常意味着文件結束))。
開始全備份恢復
命令如下:
# xtrabackup --defaults-file=/etc/my.cnf --prepare --user=root--password="123456" --apply-log-only --target-dir=/opt/mysqlbackup/full/full_incre_20160912_221111/
部分顯示信息如下圖所示:
恢復到第一次增量的時刻
增量備份恢復的步驟和完整備份恢復的步驟基本一致,只是應用日誌的過程稍有不同。增量備份恢復時,是先將所有的增量備份挨個應用到完整備份的數據文件中,然後再將完整備份中的數據恢復到數據庫中。
恢復命令:
# xtrabackup --defaults-file=/etc/my.cnf --prepare--user=root --password="123456" --apply-log-only --target-dir=/opt/mysqlbackup/full/full_incre_20160912_221111/--incremental-dir=/opt/mysqlbackup/inc/incre_20160912_221510/
部分顯示信息如下圖所示:
恢復到第二次增量備份前面:
恢復命令:
# xtrabackup --defaults-file=/etc/my.cnf --prepare--user=root --password="123456" --apply-log-only--target-dir=/opt/mysqlbackup/full/full_incre_20160912_221111/--incremental-dir=/opt/mysqlbackup/inc/incre_20160912_221916/
部分顯示信息如下圖所示:
恢復整個庫
恢復命令:
# xtrabackup --defaults-file=/etc/my.cnf --prepare--user=root --password="123456"--target-dir=/opt/mysqlbackup/full/full_incre_20160912_221111/
部分顯示信息如下圖所示:
然後停止mysql數據庫:
[root@localhost ~]# systemctl stop mysqld
開始rsync數據文件:
# cd /opt/mysqlbackup/full/full_incre_20160912_221111/
#rsync -rvt --exclude 'xtrabackup_checkpoints' --exclude'xtrabackup_logfile' ./ /usr/local/mysql/data/
當數據恢復至DATADIR目錄以後,還需要確保所有數據文件的屬主和屬組均爲正確的用戶,如mysql,否則,在啓動mysqld之前還需要事先修改數據文件的屬主和屬組。
授予mysql訪問權限:
# chown -R mysql:mysql /usr/local/mysql/data/
啓動mysql服務:
# systemctl start mysqld
驗證
登錄mysql,看到以前在備份之後刪除的數據已經通過2次增量備份恢復過來了,如下所示:
[root@localhost ~]# mysql -uroot -p123456 -e "select * fromtest.xx"
+------+------+
| id | name |
+------+------+
| 1 | tom1 |
| 2 | tom2 |
| 3 | tom3 |
| 4 | tom4 |
+------+------+
方案三:innobackupex全庫備份+innobackupex增量備份
測試環境準備
創建一個測試數據庫,並創建一張表輸入幾行數據
mysql>create database test2;
mysql> usetest2;
mysql>create table yy(id int,name varchar(20));
mysql>insert into yy values(1,'kim1');
mysql>insert into yy values(2,'kim2');
1、innobackupex先做完全備份
命令如下:
# innobackupex --defaults-file=/etc/my.cnf --user=root--password="123456" /opt/mysqlbackup/full/full_incre_$(date +%Y%m%d_%H%M%S) --no-timestamp
部分顯示信息如下圖所示:
查看完全備份文件
# ll /opt/mysqlbackup/full/
drwxr-x---. 10 root root 4096 Sep 12 23:52 full_incre_20160912_235237
innobackupex做增量備份
做第一次增量備份
先錄入增量數據
mysql> use test2;
mysql> insert into yy values(3,'kim3');
再進行增量備份,命令如下:
# innobackupex --incremental/opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S)--incremental-basedir=/opt/mysqlbackup/full/full_incre_20160912_235237/--user=root --password="123456" --no-timestamp
部分顯示信息如下圖所示:
查看增量備份文件
# ll/opt/mysqlbackup/inc/
drwxr-x---.10 root root 4096 Sep 12 23:56 incre_20160912_235636
基於全備和第一個增量備份來做第二次增量備份
先錄入增量數據錄入
mysql> use test2;
mysql> insert into yy values(4,'kim4');
開始進行第二次增量備份,備份命令:
# innobackupex --incremental/opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S) --incremental-basedir=/opt/mysqlbackup/inc/incre_20160912_235636/--user=root --password="123456" --no-timestamp
部分顯示信息如下圖所示:
查看增量備份文件
# ll /opt/mysqlbackup/inc/
drwxr-x---. 10 root root 4096 Sep 12 23:56 incre_20160912_235636
drwxr-x---. 10 root root 4096 Sep 12 23:59 incre_20160912_235942
2、innobackupex做增量恢復
先刪除兩次增量數據,用來查看驗證恢復結果
mysql> use test2;
mysql> delete from yy where id=3;
開始做恢復,恢復全備份
命令如下:
# innobackupex --apply-log --redo-only/opt/mysqlbackup/full/full_incre_20160912_235237/
部分顯示信息如下圖所示:
--redo-only 用於準備增量備份內容把數據合併到全備份目錄,配合incremental-dir 增量備份目錄使用
基於全備份進行第一次增量備份的恢復
命令如下:
# innobackupex --apply-log --redo-only/opt/mysqlbackup/full/full_incre_20160912_235237/--incremental-dir=/opt/mysqlbackup/inc/incre_20160912_235636/
基於全備份和第一次增量備份,恢復第二次增量備份
命令如下:
#innobackupex --apply-log --redo-only/opt/mysqlbackup/full/full_incre_20160912_235237/ --incremental-dir=/opt/mysqlbackup/inc/incre_20160912_235942/
恢復整個數據庫
停止數據庫
# systemctl stop mysqld
清空數據目錄下所有文件
# mkdir -p /tmp/mysqldatabak
# mv /usr/local/mysql/data/* /tmp/mysqldatabak/
將恢復好的數據按照配置文件的需求拷貝到相應目錄
# innobackupex --defaults-file=/etc/my.cnf --user=root--password="123456" --copy-back/opt/mysqlbackup/full/full_incre_20160912_235237/
當數據恢復至DATADIR目錄以後,還需要確保所有數據文件的屬主和屬組均爲正確的用戶,如mysql,否則,在啓動mysqld之前還需要事先修改數據文件的屬主和屬組。
賦予mysql賬號權限
# chown -R mysql:mysql /usr/local/mysql/data/
啓動mysql服務
# systemctl start mysqld
登錄mysql界面,查看數據是否已經恢復,如下所示:
mysql> use test2;
mysql> select * from yy;
+------+------+
| id | name |
+------+------+
| 1 | kim1 |
| 2 | kim2 |
| 3 | kim3 |
| 4 | kim4 |
+------+------+
附:Xtrabackup的“流”及“備份壓縮”功能
Xtrabackup對備份的數據文件支持“流”功能,即可以將備份的數據通過STDOUT傳輸給tar程序進行歸檔,而不是默認的直接保存至某備份目錄中。要使用此功能,僅需要使用--stream選項即可。如:
# innobackupex --user=root --password="123456" --stream=tar/opt/mysqlbackup/full/ | gzip >/opt/mysqlbackup/full/full_`date+%F_%H%M%S`.tar.gz