MySQL數據庫備份是一項非常重要的工作,mysql的備份主要分為邏輯備份和物理備份,同時,不同的生產環境要備份的策略也不會不同。下面先說一說備份時要考慮到的一些因素,然后再實際操作進行不同方式的數據備份。
備份要注意的地方
在備份工作中,定制合理的備份策略是很重要的,一下是備份恢復過程中要注意的一些因素:
-
確定使用全備還是增量備份,全備的優點是備份保持最新備份恢復的時候可以一次恢復,花費的時間比較少,缺點是如果數據量大,那么會花費比較大的時間,長時間的備份操作會對系統造成負載;而增量備份,剛好相反,只需要備份在原來備份基礎上增加的內容,備份時間少,對系統負載也小,比較麻煩的是,恢復時,需要全備份加上增量備份的部分,恢復時間比較長,而且要保證每次的增量備份數據可恢復,因為每一次增量恢復都需要依賴前一次的備份為基礎。
-
要定期做備份,備份的周期要充分考慮系統可以承受的恢復時間,備份操作要在系統負載較小的時候進行
-
確保mysql的bin-log日志的打開的,使用bin-log日志mysql可以在必要的時候做完整的恢復,或基於時間點的恢復,或基於pos位置的恢復。
-
要經常做備份恢復測試,確保備份是有效的,並且是可以恢復的
-
定期或不定期進行災難演練,從演練過程中發現存在的問題和隱患
邏輯備份
在mysql中邏輯備份的最大優點是對不同的存儲引擎都可以使用同樣的方法來備份,而物理備份則不同的存儲引擎有不同的備份方法。
mysql的邏輯備份是將數據庫中的數據備份為一個文本文件,在mysqldump工具完成邏輯備份。
- 備份指定的數據庫或者指定數據庫中的表
shell > mysqldump -u user -p password dbname > /path/backupdb.sql
shell > mysqldump -u user -p password dbname tbname > /path/backupdb.sql
示例:備份db4庫中的tb1表到/opt,沒有指定用戶密碼是因為沒有設置密碼
[root@localhost ~]# mysqldump db4 tb1 > /opt/db4-tb1.sql
- 備份一個或者多個庫
shell > mysqldump -u user -p password db1 db2 db3 > /path/backupdb.sql
- 備份所有庫
shell > mysqldump -u user -p password --all-database > /path/all-db.sql
如果沒有指定數據庫中的任何表,默認導出數據庫中所有的表。
mysqldump工具的使用
- -A : --all-databases 備份所有數據庫,含create database
- -B :-databases db_name… 指定備份的數據庫,包括create database語句
- -E : --events:備份相關的所有event scheduler
- -R : --routines:備份所有存儲過程和存儲函數
- --triggers:備份表相關的觸發器,默認啟用,用--skip-triggers,不備份觸發器
- --master-data[=#]: 此選項須啟用二進制日志
1:所備份的數據之前加一條記錄為change master to語句,非注釋,不指定#,默認為1
2:記錄為注釋的change master to語句
此選項會自動關閉--lock-tables功能,自動打開--lock-all-tables功能(除非開啟--single-transaction) - -F, --flush-logs :備份前滾動日志,鎖定表完成后,執行flush logs命令,生成新的二進制日志文件,配合-A時,會導致刷新多次數據庫,在同一時刻執行轉儲和日志刷新,則應同時使用--
flush-logs和-x,--master-data或-single-transaction,此時只刷新一次
建議:和-x,--master-data或 --single-transaction一起使用 - --compact 去掉注釋,適合調試,生產不使用
- -d :--no-data 只備份表結構
- -t : --no-create-info 只備份數據,不備份create table
- -n : --no-create-db 不備份create database,可被-A或-B覆蓋
- --flush-privileges 備份mysql或相關時需要使用
- -f : --force 忽略SQL錯誤,繼續執行
- --hex-blob使用十六進制符號轉儲二進制列(例如,“abc”變為0x616263),受影響的數據類
型包括BINARY, VARBINARY,BLOB,BIT - -q: --quick 不緩存查詢,直接輸出,加快備份速度
備份與恢復數據庫示列
將db4數據庫整庫備份,然后將其刪除后恢復:
備份db4庫
[root@localhost ~]# mysqldump -uroot -pcentos -l -F db4 > /opt/db4.sql
[root@localhost ~]# ls /opt/
db4.sql
刪除db4數據庫:
[root@localhost ~]# mysqladmin -uroot -pcentos DROP db4
Dropping the database is potentially a very bad thing to do.
Any data stored in the database will be destroyed.
Do you really want to drop the 'db4' database [y/N] y
Database "db4" dropped
查看驗證
[root@localhost ~]# mysqlshow -uroot -pcentos
+--------------------+
| Databases |
+--------------------+
| db10 |
| db5 |
| hellodb |
| mysql |
| test |
+--------------------+
恢復庫
[root@localhost ~]# mysql -uroot -pcentos < /opt/db4.sql
ERROR 1046 (3D000) at line 22: No database selected
看到這里有錯誤,是以為在上面備份的時候沒有 -B 參數,-B 參數作用是在備份時加上create database的建庫語句,因為沒有加這個參數,所以恢復時沒有這個數據庫錯,這樣只能登錄到mysql創建一個同名的數據庫然后執行恢復
MariaDB [(none)]> create database db4;
Query OK, 1 row affected (0.08 sec)
MariaDB [db4]> use db4; #創建后必須要指定到庫
MariaDB [(none)]> source /opt/db4.sql; 在mysql終端里使用 source 指令執行導入
MariaDB [db4]> show tables;
+---------------+
| Tables_in_db4 |
+---------------+
| tb1 |
+---------------+
1 row in set (0.00 sec)
MariaDB [db4]> select * from tb1 limit 3;
+------+-------+
| id | name |
+------+-------+
| 1 | demo |
| 2 | demo2 |
| 3 | demo3 |
+------+-------+
3 rows in set (0.00 sec)
以上的備份恢復是基於整庫備份和恢復的,下面基於全量備份 + bin-log 日志實現完全恢復
在db4數據庫中,先進行一次全量備份,備份后創建表 tb2 ,寫入數據,然后將數據庫db4刪掉進行恢復
備份整庫數據
[root@localhost ~]# mysqldump -u root -pcentos -B -l -F db4 > /opt/full_db4.sql
參數說明:
- -B :備份時添加建庫語句
- -l (小寫l): 給數據庫表添加只讀鎖
- -F:刷新bin-log日志文件,相當於執行flush logs指令,生成新的bin-log日志文件,這些備份后的寫入數據日志都放在新的bin-log日志文件中,利於查找
創建新表寫入數據
MariaDB [db4]> create table tb2 (
-> id int,
-> name varchar(20)
-> ) charset=utf8;
Query OK, 0 rows affected (2.04 sec)
MariaDB [db4]> insert into tb2 values (1,'demo1'),(2,'demo2');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
刪除數據庫
MariaDB [db4]> drop database db4;
Query OK, 2 rows affected (0.05 sec)
恢復數據
剛才在上面備份時沒有使用 -B 參數,直接恢復失敗了,現在加上 -B 選項直接在命令行用mysql指令恢復
[root@localhost ~]# mysql -uroot -pcentos < /opt/full_db4.sql
查看數據庫
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db10 |
| db4 | #備份被恢復
| db5 |
| hellodb |
| mysql |
| test |
+--------------------+
8 rows in set (0.00 sec)
MariaDB [(none)]> use db4;
Database changed
MariaDB [db4]> show tables;
+---------------+
| Tables_in_db4 |
+---------------+
| tb1 |
+---------------+
1 row in set (0.00 sec)
增量恢復
mysqlbinlog使用比較簡單,可以查看前面文章使用
恢復備份后的數據要結合bin-log日志文件,查看當前使用的bin-log文件:
MariaDB [db4]> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000009 | 2198 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
使用mysqlbinlog工具查看 master-bin.000009內容,恢復bin-log數據選擇是pos值位置恢復,查找對應位置的pos值
# at 245
#180612 21:29:11 server id 1 end_log_pos 370 Query thread_id=25 exec_time=2 error_code=0
use `db4`/*!*/;
SET TIMESTAMP=1528810151/*!*/;
SET @@session.pseudo_thread_id=25/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=2, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table tb2 (
id int,
name varchar(20)
) charset=utf8
/*!*/;
# at 370
#180612 21:29:52 server id 1 end_log_pos 442 Query thread_id=25 exec_time=0 error_code=0
SET TIMESTAMP=1528810192/*!*/;
BEGIN
/*!*/;
# at 442
#180612 21:29:52 server id 1 end_log_pos 555 Query thread_id=25 exec_time=0 error_code=0
SET TIMESTAMP=1528810192/*!*/;
insert into tb2 values (1,'demo1'),(2,'demo2')
/*!*/;
# at 555
#180612 21:29:52 server id 1 end_log_pos 582 Xid = 281
COMMIT/*!*/;
# at 582
注意上面最后三行,結束的position位置要包含COMMIT,如果不包含登錄沒有提交事務
恢復bin-log日志數據
mysqlbinlog的用法比較簡單,可以查看前面文章
[root@localhost mysql]# mysqlbinlog --start-position=245 --stop-position=582 /var/lib/mysql/master-bin.000009 | mysql -uroot -pcentos
查看數據
MariaDB [db4]> show tables;
+---------------+
| Tables_in_db4 |
+---------------+
| tb1 |
| tb2 |
+---------------+
2 rows in set (0.00 sec)
MariaDB [db4]> select * from tb2;
+------+-------+
| id | name |
+------+-------+
| 1 | demo1 |
| 2 | demo2 |
+------+-------+
2 rows in set (0.00 sec)
細說mysqldump幾個參數
在上面的備份恢復過程中,看似完成了整個備份恢復的過程,但是上面的方式並不嚴謹,使用mysqldump備份的過程默認是會加讀鎖的,只有在備份MyISAM引擎的數據時才需要加鎖,而現在數據據庫基本使用的都是InnoDB存儲引擎。
下面說一說mysqldump幾個關鍵參數的作用:
- -l: --lock-tables:
對於需要備份的每個數據庫,在啟動備份之前分別鎖定其所有表,默認為on,--skip-lock-tables選項可禁用,對備份MyISAM的多個庫,可能會造成數據不一致,備份數據量大的表庫時間會比較長,並且在鎖表過程中數據是不可寫入的
- --master-data= # :
mysqldump導出數據時,當這個參數的值為1的時候mysqldump出來的文件就會包括CHANGE MASTER TO這個語句CHANGE MASTER TO后面緊接着就是file和position的記錄,在slave上導入數據時就會執行這個語句,salve就會根據指定這個文件位置從master端復制binlog。默認情況下這個值是1 ,當這個值是2的時候,chang master to也是會寫到dump文件里面去的,但是這個語句是被注釋的狀態。
master-data參數在建立slave數據庫的時候會經常用到,因為這是一個比較好用的參數,默認值為1,默認情況下,會包含change master to,這個語句包含file和position的記錄始位置。master-data=2的時候,在mysqldump出來的文件包含CHANGE MASTER TO這個語句,處於被注釋狀態。
- --single-transaction :
該選項Innodb中推薦使用,不適用MyISAM,此選項會開始備份前,先執行START TRANSACTION指令開啟事務此選項通過在單個事務中轉儲所有表來創建一致的快照。 僅適用於存儲在支持多版本控制的存儲引擎中的表(目前只有InnoDB可以); 轉儲不保證與其他存儲引擎保持一致。 在進行單事務轉儲時,要確保有效的轉儲文件(正確的表內容和二進制日志位置),沒有其他連接應該使用以下語句:ALTER TABLE,DROP TABLE,RENAME TABLE,TRUNCATE TABLE此選項和--lock-tables(此選項隱含提交掛起的事務)選項是相互排斥備份大型表時,建議將--single-transaction選項和--quick結合一起使用
上面的幾個參數是比較重要的參數,尤其是--single-transaction和--master-data參數,在備份InnoDB引擎數據的時候這兩個參數是常放一起組合使用,看一下備份過程中的日志內容
- 只使用了--single-transaction參數備份過程:
[root@localhost mysql]# cat localhost.log
180613 21:45:24 10 Connect root@localhost as anonymous on
10 Query /*!40100 SET @@SQL_MODE='' */
10 Query /*!40103 SET TIME_ZONE='+00:00' */
10 Query FLUSH TABLES
180613 21:45:26 10 Query FLUSH TABLES WITH READ LOCK
10 Refresh
/usr/libexec/mysqld, Version: 5.5.56-MariaDB (MariaDB Server). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time Id Command Argument
10 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
10 Query START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */
10 Query UNLOCK TABLES
10 Query set optimizer_switch='semijoin=off'
- 加 --singing-transaction和--master-data參數的備份過程
180613 21:47:51 11 Connect root@localhost as anonymous on
11 Query /*!40100 SET @@SQL_MODE='' */
11 Query /*!40103 SET TIME_ZONE='+00:00' */
11 Query SHOW STATUS LIKE 'binlog_snapshot_%'
11 Query FLUSH /*!40101 LOCAL */ TABLES
11 Query FLUSH TABLES WITH READ LOCK
11 Refresh
/usr/libexec/mysqld, Version: 5.5.56-MariaDB (MariaDB Server). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time Id Command Argument
11 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
11 Query START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */
11 Query SHOW STATUS LIKE 'binlog_snapshot_%'
11 Query UNLOCK TABLES
11 Query set optimizer_switch='semijoin=off'
對比上面的日志開頭內容,在執行了FLUSH TABLES WITH READ LOCK后,添加START TRANSACTION 語句,用來開啟單一事務 ,這個時候的加鎖,僅僅是為了確定master-data中的binlog的具體位置和開啟事務,開啟事務后,就已經把讀鎖釋放了
可靠的備份方式如下:
[root@localhost mysql]# mysqldump -uroot -pcentos -B -F --single-transaction --master-data=1 db5 > /opt/db5.sql