總結:
備份方法 | 備份速度 | 恢復速度 | 便捷性 | 功能 | 一般用於 |
---|---|---|---|---|---|
cp | 快 | 快 | 一般、靈活性低 | 很弱 | 少量數據備份 |
mysqldump | 慢 | 慢 | 一般、可無視存儲引擎的差異 | 一般 | 中小型數據量的備份 |
lvm2快照 | 快 | 快 | 一般、支持幾乎熱備、速度快 | 一般 | 中小型數據量的備份 |
xtrabackup | 較快 | 較快 | 實現innodb熱備、對存儲引擎有要求 | 強大 | 較大規模的備份 |
我們試着想一想, 在生產環境中什么最重要?如果我們服務器的硬件壞了可以維修或者換新, 軟件問題可以修復或重新安裝, 但是如果數據沒了呢?這可能是最恐怖的事情了吧, 我感覺在生產環境中應該沒有什么比數據跟更為重要. 那么我們該如何保證數據不丟失、或者丟失后可以快速恢復呢?只要看完這篇, 大家應該就能對
MySQL
中實現數據備份和恢復能有一定的了解。
為什么需要備份數據?
其實在
前言
中也大概說明了為什么要備份數據, 但是我們還是應該具體了解一下為什么要備份數據在生產環境中我們數據庫可能會遭遇各種各樣的不測從而導致數據丟失, 大概分為以下幾種.
硬件故障
軟件故障
自然災害
黑客攻擊
誤操作 (占比最大)
所以, 為了在數據丟失之后能夠恢復數據, 我們就需要定期的備份數據, 備份數據的策略要根據不同的應用場景進行定制, 大致有幾個參考數值, 我們可以根據這些數值從而定制符合特定環境中的數據備份策略
能夠容忍丟失多少數據
恢復數據需要多長時間
需要恢復哪一些數據
數據的備份類型
數據的備份類型根據其自身的特性主要分為以下幾組
完全備份
部分備份
完全備份指的是備份整個數據集( 即整個數據庫 )、部分備份指的是備份部分數據集(例如: 只備份一個表)
而部分備份又分為以下兩種
增量備份
差異備份
增量備份指的是備份自上一次備份以來(增量或完全)以來變化的數據; 特點: 節約空間、還原麻煩
差異備份指的是備份自上一次完全備份以來變化的數據 特點: 浪費空間、還原比增量備份簡單示意圖
MySQL備份數據的方式
在
MySQl
中我們備份數據一般有幾種方式
熱備份
溫備份
冷備份
熱備份指的是當數據庫進行備份時, 數據庫的讀寫操作均不是受影響
溫備份指的是當數據庫進行備份時, 數據庫的讀操作可以執行, 但是不能執行寫操作
冷備份指的是當數據庫進行備份時, 數據庫不能進行讀寫操作, 即數據庫要下線
MySQL
中進行不同方式的備份還要考慮存儲引擎是否支持
MyISAM
熱備 ×
溫備 √
冷備 √
InnoDB
熱備 √
溫備 √
冷備 √
我們在考慮完數據在備份時, 數據庫的運行狀態之后還需要考慮對於
MySQL
數據庫中數據的備份方式物理備份一般就是通過
tar
,cp
等命令直接打包復制數據庫的數據文件達到備份的效果
邏輯備份一般就是通過特定工具從數據庫中導出數據並另存備份(邏輯備份會丟失數據精度)
物理備份
邏輯備份
備份需要考慮的問題
定制備份策略前, 我們還需要考慮一些問題
我們要備份什么?
一般情況下, 我們需要備份的數據分為以下幾種
數據
二進制日志, InnoDB事務日志
代碼(存儲過程、存儲函數、觸發器、事件調度器)
服務器配置文件
備份工具
這里我們列舉出常用的幾種備份工具
mysqldump
: 邏輯備份工具, 適用於所有的存儲引擎, 支持溫備、完全備份、部分備份、對於InnoDB存儲引擎支持熱備cp, tar 等歸檔復制工具
: 物理備份工具, 適用於所有的存儲引擎, 冷備、完全備份、部分備份lvm2 snapshot
: 幾乎熱備, 借助文件系統管理工具進行備份mysqlhotcopy
: 名不副實的的一個工具, 幾乎冷備, 僅支持MyISAM存儲引擎xtrabackup
: 一款非常強大的InnoDB/XtraDB熱備工具, 支持完全備份、增量備份, 由percona
提供
設計合適的備份策略
針對不同的場景下, 我們應該制定不同的備份策略對數據庫進行備份, 一般情況下, 備份策略一般為以下三種
直接cp,tar復制數據庫文件
mysqldump+復制BIN LOGS
lvm2快照+復制BIN LOGS
xtrabackup
以上的幾種解決方案分別針對於不同的場景
如果數據量較小, 可以使用第一種方式, 直接復制數據庫文件
如果數據量還行, 可以使用第二種方式, 先使用mysqldump對數據庫進行完全備份, 然后定期備份BINARY LOG達到增量備份的效果
如果數據量一般, 而又不過分影響業務運行, 可以使用第三種方式, 使用
lvm2
的快照對數據文件進行備份, 而后定期備份BINARY LOG達到增量備份的效果如果數據量很大, 而又不過分影響業務運行, 可以使用第四種方式, 使用
xtrabackup
進行完全備份后, 定期使用xtrabackup
進行增量備份或差異備份
實戰演練
使用cp進行備份
我們這里使用的是使用yum安裝的
mysql-5.1
的版本, 使用的數據集為從網絡上找到的一個員工數據庫
查看數據庫的信息
mysql> SHOW DATABASES; #查看當前的數據庫, 我們的數據庫為employees
+--------------------+
| Database |
+--------------------+
| information_schema |
| employees |
| mysql |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> USE employees;
Database changed
mysql> SHOW TABLES; #查看當前庫中的表
+---------------------+
| Tables_in_employees |
+---------------------+
| departments |
| dept_emp |
| dept_manager |
| employees |
| salaries |
| titles |
+---------------------+
6 rows in set (0.00 sec)
mysql> SELECT COUNT(*) FROM employees; #由於篇幅原因, 我們這里只看一下employees的行數為300024
+----------+
| COUNT(*) |
+----------+
| 300024 |
+----------+
1 row in set (0.05 sec)
向數據庫施加讀鎖
mysql> FLUSH TABLES WITH READ LOCK; #向所有表施加讀鎖
Query OK, 0 rows affected (0.00 sec)
備份數據文件
[root@node1 ~]# mkdir /backup #創建文件夾存放備份數據庫文件
[root@node1 ~]# cp -a /var/lib/mysql/* /backup #保留權限的拷貝源數據文件
[root@node1 ~]# ls /backup #查看目錄下的文件
employees ibdata1 ib_logfile0 ib_logfile1 mysql mysql.sock test
模擬數據丟失並恢復
[root@node1 ~]# rm -rf /var/lib/mysql/* #刪除數據庫的所有文件
[root@node1 ~]# service mysqld restart #重啟MySQL, 如果是編譯安裝的應該不能啟動, 如果rpm安裝則會重新初始化數據庫
mysql> SHOW DATABASES; #因為我們是rpm安裝的, 連接到MySQL進行查看, 發現數據丟失了!
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.00 sec)
[root@node1 ~]# rm -rf /var/lib/mysql/* #這一步可以不做
[root@node1 ~]# cp -a /backup/* /var/lib/mysql/ #將備份的數據文件拷貝回去
[root@node1 ~]# service mysqld restart #重啟MySQL
#重新連接數據並查看
mysql> SHOW DATABASES; #數據庫已恢復
+--------------------+
| Database |
+--------------------+
| information_schema |
| employees |
| mysql |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> USE employees;
mysql> SELECT COUNT(*) FROM employees; #表的行數沒有變化
+----------+
| COUNT(*) |
+----------+
| 300024 |
+----------+
1 row in set (0.06 sec)
##完成
使用mysqldump+復制BINARY LOG備份
我們這里使用的是使用yum安裝的
mysql-5.1
的版本, 使用的數據集為從網絡上找到的一個員工數據庫我們通過mysqldump進行一次完全備份, 再修改表中的數據, 然后再通過binary log進行恢復 二進制日志需要在mysql配置文件中添加 log_bin=on 開啟
mysqldump
命令介紹
mysqldump
是一個客戶端的邏輯備份工具, 可以生成一個重現創建原始數據庫和表的SQL語句, 可以支持所有的存儲引擎, 對於InnoDB支持熱備
#基本語法格式
shell> mysqldump [options] db_name [tbl_name ...] 恢復需要手動CRATE DATABASES
shell> mysqldump [options] --databases db_name ... 恢復不需要手動創建數據庫
shell> mysqldump [options] --all-databases 恢復不需要手動創建數據庫
其他選項:
-E, --events: 備份事件調度器
-R, --routines: 備份存儲過程和存儲函數
--triggers: 備份表的觸發器; --skip-triggers
--master-date[=value]
1: 記錄為CHANGE MASTER TO 語句、語句不被注釋
2: 記錄為注釋的CHANGE MASTER TO語句
基於二進制還原只能全庫還原
--flush-logs: 日志滾動
鎖定表完成后執行日志滾動
查看數據庫的信息
mysql> SHOW DATABASES; #查看當前的數據庫, 我們的數據庫為employees
+--------------------+
| Database |
+--------------------+
| information_schema |
| employees |
| mysql |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> USE employees;
Database changed
mysql> SHOW TABLES; #查看當前庫中的表
+---------------------+
| Tables_in_employees |
+---------------------+
| departments |
| dept_emp |
| dept_manager |
| employees |
| salaries |
| titles |
+---------------------+
6 rows in set (0.00 sec)
mysql> SELECT COUNT(*) FROM employees; #由於篇幅原因, 我們這里只看一下employees的行數為300024
+----------+
| COUNT(*) |
+----------+
| 300024 |
+----------+
1 row in set (0.05 sec)
使用mysqldump
備份數據庫
[root@node1 ~]# mysql -uroot -p -e 'SHOW MASTER STATUS' #查看當前二進制文件的狀態, 並記錄下position的數字
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 106 | | |
+------------------+----------+--------------+------------------+
[root@node1 ~]# mysqldump --all-databases --lock-all-tables > backup.sql #備份數據庫到backup.sql文件中
mysql> CREATE DATABASE TEST1; #創建一個數據庫
Query OK, 1 row affected (0.00 sec)
mysql> SHOW MASTER STATUS; #記下現在的position
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 191 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
[root@node1 ~]# cp /var/lib/mysql/mysql-bin.000003 /root #備份二進制文件
[root@node1 ~]# service mysqld stop #停止MySQL
[root@node1 ~]# rm -rf /var/lib/mysql/* #刪除所有的數據文件
[root@node1 ~]# service mysqld start #啟動MySQL, 如果是編譯安裝的應該不能啟動(需重新初始化), 如果rpm安裝則會重新初始化數據庫
mysql> SHOW DATABASES; #查看數據庫, 數據丟失!
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.00 sec)
mysql> SET sql_log_bin=OFF; #暫時先將二進制日志關閉
Query OK, 0 rows affected (0.00 sec)
mysql> source backup.sql #恢復數據,所需時間根據數據庫時間大小而定
mysql> SET sql_log_bin=ON; 開啟二進制日志
mysql> SHOW DATABASES; #數據庫恢復, 但是缺少TEST1
+--------------------+
| Database |
+--------------------+
| information_schema |
| employees |
| mysql |
| test |
+--------------------+
4 rows in set (0.00 sec)
[root@node1 ~]# mysqlbinlog --start-position=106 --stop-position=191 mysql-bin.000003 | mysql employees #通過二進制日志增量恢復數據
mysql> SHOW DATABASES; #現在TEST1出現了!
+--------------------+
| Database |
+--------------------+
| information_schema |
| TEST1 |
| employees |
| mysql |
| test |
+--------------------+
5 rows in set (0.00 sec)
#完成
使用lvm2快照備份數據
做實驗之前我們先回顧一下
lvm2-snapshot
的知識
LVM
快照簡單來說就是將所快照源分區一個時間點所有文件的元數據進行保存,如果源文件沒有改變,那么訪問快照卷的相應文件則直接指向源分區的源文件,如果源文件發生改變,則快照卷中與之對應的文件不會發生改變。快照卷主要用於輔助備份文件。 這里只簡單介紹,點擊查看詳細介紹
部署lvm環境
添加硬盤; 這里我們直接實現SCSI硬盤的熱插拔, 首先在虛擬機中添加一塊硬盤, 不重啟
[root@node1 ~]# ls /dev/sd* #只有以下幾塊硬盤, 但是我們不重啟可以讓系統識別新添加的硬盤
/dev/sda /dev/sda1 /dev/sda2
[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host0/scan
[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host1/scan
[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host2/scan
[root@node1 ~]# ls /dev/sd* #看!sdb識別出來了
/dev/sda /dev/sda1 /dev/sda2 /dev/sdb
[root@node1 ~]# fdisk /dev/sdb #分區
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xd353d192.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-2610, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-2610, default 2610): +15G
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
Syncing disks.
You have new mail in /var/spool/mail/root
[root@node1 ~]# partx -a /dev/sdb
BLKPG: Device or resource busy
error adding partition 1
##創建邏輯卷
[root@node1 ~]# pvcreate /dev/sdb1
Physical volume