(7) MySQL數據庫備份詳解

對於任何數據庫來講,備份都是很是重要的mysql

數據庫複製不能取代備份的做用sql

好比咱們因爲誤操做,在主數據庫上刪除了一些數據,因爲主從複製的時間很短,在發現時,從數據庫上的數據可能也已經被刪除了,
咱們不能使用從數據庫上的數據來恢復主數據庫上的數據,只能經過備份進行誤刪除數據的恢復數據庫

一. 備份的分類

1.按備份的結果來分:

邏輯備份

其備份結果爲SQL語句,適合於全部存儲引擎,恢復時須要較多時間,邏輯備份時,對於MyISAM存儲引擎是須要進行鎖表操做的,經過使用的mysqldump就是一種邏輯備份工具安全

物理備份

是對數據庫目錄的拷貝,其備份結果的大小一般也與備份數據的數據目錄大小相同,物理備份和恢復一般比邏輯備份要快,由於只須要對mysql數據目錄拷貝便可,也正是由於這點,對於內存表只能備份其結構,沒法備份數據(由於其數據存儲在內存中,沒有實際的物理數據文件)bash

物理備份的方式

進行物理備份,咱們能夠採用離線備份和在線備份的方式進行備份

 離線備份:須要對數據庫進行停機,或對整個數據庫進行鎖定的狀況下進行
 在線備份:須要使用第三方工具,如  XtraBackup

2. 按備份的數據庫的內容來分

2.1 全量備份

是對整個數據庫的一個完整備份服務器

2.2 增量備份

是在上次全量或增量備份的基礎上,對更改過的數據進行的備份網絡

注意

Mysql官方提供的mysqldump命令並不支持增量備份app

一般狀況要使用mysqldump來進行增量備份的話,增量備份只能經過備份Mysql的二進制日誌來實現socket

XtraBackup自己就提供了增量備份的功能,因此對於Innodb來講,使用XtraBackup進行備份更加安全高效ide

不管是使用XtraBackup仍是Mysqldump 進行備份,要進行基於時間點的恢復時都須要利用Mysql的二進制日誌,因此一般狀況下咱們須要對Mysql的二進制日誌也進行備份

二. 使用mysqldump進行備份

mysqldump 是mysql官方提供的邏輯備份工具,其備份結果是可讀的SQL文件

mysqldump 支持多種語法

1. 經常使用語法

對一個數據庫下的一個或多個表進行備份

mysqldump [OPTIONS] database [tables]

備份多個表時,table直接用空格進行分隔

對指定的多個數據庫進行備份

mysqldump [OPTIONS] --database [OPTIONS] DB1 [DB2..]

對整個mysql實例下的全部數據庫進行備份

mysqldump [OPTIONS] --all-database [OPTIONS]

2. 經常使用參數

-u,--user = name    #  指定備份時所使用的數據庫帳號
-p. --password [=name]    # 指定帳號的密碼
--single-transaction  # 使用此參數會在備份前先執行start transaction命令啓動一個事務,以此來得到數據庫備份時的數據的一致性,因爲是經過事務保證數據的一致性,因此此參數只對Innodb存儲引擎有效;當使用此參數進行備份時,要確保沒有任何DDL語句在執行,由於Innodb的數據一致性的隔離級別並不能隔離DDL操做

-l, --lock-tables  # 若是沒有使用非事務存儲引擎,使用此參數保證備份時數據的一致性,在備份時會依次鎖住每一個數據庫下的全部表,通常用於MyISAM存儲引擎的備份,使用了此參數,在數據庫備份時,只能進行讀操做,因爲此參數是鎖住一個數據庫下的全部表,備份時能夠保證一個數據庫下的全部表的數據一致性,但不能保證整個Mysql實例下的全部數據庫的全部表的數據一致性,這也是爲何推薦使用Innodb引擎的一個緣由
 
lock-tables 與 single-transaction 參數是互斥的,不能同時使用,因此數據庫中若是混合使用了Innodb表和MyISAM表就只能使用lock-tables來進行備份了

-x, --lock-all-tables  # 此參數能夠對整個Mysql實例下的全部數據庫進行加鎖,能夠避免lock-tables不能保證整個Mysql實例下的全部數據庫的全部表的數據一致性的問題,備份時一樣會將數據庫變爲只讀的狀態

--master-data = [1/2]    # 不管是時間恢復仍是新建slave實例都要用到這個參數,此參數有兩個可選值,當值爲1時,備份中只記錄change_master語句,當值爲2時,change_master語句會以註釋的形式出如今備份文件中;默認值爲1,且當使用了此參數時會忽略lock-tables參數,在備份時若是使用了此參數,可是沒有使用single-transaction參數,則會自動使用lock-all-tables參數

若是咱們要備份的數據庫中包含了存儲過程,觸發器,數據庫調度事件時,要備份這些數據庫對象時,必須指定如下參數才能對相應數據庫進行備份

-R, --routines     # 指定要備份的數據庫中存在的的存儲過程
--triggers     # 指定要備份的數據庫中存在的的觸發器
-E,--events      # 指定要備份的數據庫中存在的的調度事件

除了以上參數,還有一些參數在備份時也會用到

--hex-blob    # 由於mysqldump備份導出的是文本文件,若是導出的數據中含有以上類型,在文本格式下,有些字符是不可見的,若是使用了此參數使,將會對數據庫中所存在binary、varbinary、blob類型的數據以16進制的形式保存,就不會出現有些字符不可見的狀況了
--tab =path    # 使用了此參數會在指定的路徑下對數據庫的每一個表生成兩個文件,一個文件用於存儲表結構,另外一個用於存儲表中的數據
-w, --where = '過濾條件'    # 導出指定條件的數據(只支持單表數據條件導出)


 備份帳號所須要的權限 : SELECT, RELOAD, LOCK TABLES, REPLICATION CLIENT, SHOW VIEW, PROCESS
若是使用--tab參數則還須要:FILE權限

3. 演示

首先建立備份用戶

create user 'backup'@'localhost' identified by '123456';

賦予用戶備份權限

grant select,reload,lock tables,replication client,show view,event,process on *.*  to 'backup'@'localhost';

使用mysqldump進行全量備份

備份某個數據庫

[root@localhost db_backup]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events mc_orderdb > mc_orderdb.sql
若是遇到如下問題
mysqldump: Error: Binlogging on server not active

MySQL中二進制日誌功能默認是關閉,去/etc/my.cnf 文件中加入下面配置,開啓log_bin(數據庫的操做日誌)功能,而後重啓mysql便可解決問題

log_bin=mysql-bin

以後使用 「systemctl start mysql」 重啓服務器,報錯

Job for mysql.service failed because the control process exited with error code. See "systemctl status mysql.service" and "journalctl -xe" for details.
解決方法:

在設置 log-bin 的時候同時須要設置 server-id 變量,即在配置文件中添加:

[mysqld]  
log-bin=mysql  
server-id=1

而後再次重啓便可

補充知識
裝mysql,運行一段時間後,在mysql目錄下出現一堆相似mysql-bin.000***,從mysql-bin.000001開始一直排列下來,並且佔用了大量硬盤空間,高達幾十個G. 對於這些超大空間佔用量的文件咱們應該怎麼辦呢?

那麼mysql數據庫文件夾中的mysql-bin.00001是什麼文件?
mysql-bin.00000一、mysql-bin.000002等文件是數據庫的操做日誌,例如UPDATE一個表,或者DELETE一些數據,即便該語句沒有匹配的數據,這個命令也會存儲到日誌文件中,還包括每一個語句執行的時間,也會記錄進去的。

這些形如mysql-bin.00001的文件主要是用來作什麼的呢?
1:數據恢復
若是你的數據庫出問題了,而你以前有過備份,那麼能夠看日誌文件,找出是哪一個命令致使你的數據庫出問題了,想辦法挽回損失。

2:主從服務器之間同步數據 
主服務器上全部的操做都在記錄日誌中,從服務器能夠根據該日誌來進行,以確保兩個同步。

若是不想要這些文件應該怎麼作呢?
1:只有一個mysql服務器,那麼能夠簡單的註釋掉這個選項就好了。
vi /etc/my.cnf把裏面的 log-bin 這一行註釋掉,重啓mysql服務便可。

2:若是你的環境是主從服務器,那麼就須要作如下操做了。 
A:在每一個從屬服務器上,使用SHOW SLAVE STATUS來檢查它正在讀取哪一個日誌。
B:使用SHOW MASTER LOGS得到主服務器上的一系列日誌。
C:在全部的從屬服務器中斷定最先的日誌,這個是目標日誌,若是全部的從屬服務器是更新的,就是清單上的最後一個日誌。
D:清理全部的日誌,可是不包括目標日誌,由於從服務器還要跟它同步。

簡單地說,這些MySQL目錄下的形如mysql-bin.000***的文件時MySQL的事務日誌。

刪除複製服務器已經拿走的binlog是安全的,通常來講網絡情況好的時候,保留最新的那一個足以。

再次執行以前的備份命令,便可成功被封mc_orderdb數據庫下的全部表,咱們能夠查詢一下備份的SQL文件中是否包含全部表

[root@localhost db_backup]# grep "CREATE TABLE" mc_orderdb.sql
CREATE TABLE `order_cart` (
CREATE TABLE `order_customer_addr` (
CREATE TABLE `order_detail` (
CREATE TABLE `order_master` (
CREATE TABLE `region_info` (
CREATE TABLE `shipping_info` (
CREATE TABLE `warehouse_info` (
CREATE TABLE `warehouse_proudct` (
[root@localhost db_backup]#

經過上面結果能夠看出咱們的幾個表都在其中

備份某個數據庫下的某個表

[root@localhost db_backup]#  mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events mc_orderdb order_master > order_master.sql
Enter password: 
[root@localhost db_backup]# ls
mc_orderdb.sql  order_master.sql

備份MySQL實例下的全部數據庫

[root@localhost db_backup]#  mysqldump -ubackup -p --master-data=1 --single-transaction --routines --triggers --events  --all-databases > mc.sql
Enter password: 
[root@localhost db_backup]# ls
mc_orderdb.sql  mc.sql  order_master.sql

因爲master-data的值設置爲1,change master命令並無被註釋掉,若是咱們使用這個命令進行恢復,change master命令就會被執行,在一些狀況下可能會形成一些錯誤,因此建議使用時最好仍是設置爲2

能夠經過下面的命令查看,備份文件中包含哪些數據庫

[root@localhost db_backup]# grep "Current Database" mc.sql
-- Current Database: `mc_orderdb`
-- Current Database: `mc_productdb`
-- Current Database: `mc_userdb`
-- Current Database: `mysql`
[root@localhost db_backup]#

使用-tab參數指定備份文件的位置

首先在/tmp 目錄下創建一個mc_orderdb目錄用來存放指定的備份文件,之因此使用在此目錄下創建目錄,是由於使用--tab參數時,用戶必須對目標目錄有可寫權限,而tmp目錄對任何用戶都有可寫權限

[root@localhost db_backup]#  mkdir -p /tmp/mc_orderdb

如今咱們可使用--tab參數指定備份路徑

[root@localhost db_backup]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events --tab="/tmp/mc_orderdb" mc_orderdb 
Enter password: 

--
-- Position to start replication or point-in-time recovery from
--

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;
mysqldump: Got error: 1045: Access denied for user 'backup'@'localhost' (using password: YES) when executing 'SELECT INTO OUTFILE'

能夠發現,報錯了,其實咱們在這以前還缺乏一步,因爲用戶須要有寫文件的權限,因此咱們還須要對備份用戶賦予file權限

mysql> grant file on *.*  to 'backup'@'localhost';
Query OK, 0 rows affected (0.00 sec)

咱們再次執行上面的備份命令

[root@localhost db_backup]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events --tab="/tmp/mc_orderdb" mc_orderdb 
Enter password: 

--
-- Position to start replication or point-in-time recovery from
--

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=347;
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'

能夠很清楚地從提示看到是由於mysql服務啓用了–secure-file-priv,因此纔沒法執行。
那麼–secure-file-priv又是什麼呢,應該如何解決才能是它能夠備份呢?
--secure-file-priv=name :
Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory

能夠看到secure-file-priv參數是用來限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()傳到哪一個指定目錄的。

當secure_file_priv的值爲null ,表示限制mysqld 不容許導入|導出

當secure_file_priv的值爲/tmp/ ,表示限制mysqld 的導入|導出只能發生在/tmp/目錄下

當secure_file_priv的值沒有具體值時,表示不對mysqld 的導入|導出作限制

查看數據庫當前該參數的值

mysql> show global variables like '%secure%'; 
+--------------------------+-----------------------+
| Variable_name            | Value                 |
+--------------------------+-----------------------+
| require_secure_transport | OFF                   |
| secure_auth              | ON                    |
| secure_file_priv         | /var/lib/mysql-files/ |
+--------------------------+-----------------------+
3 rows in set (0.00 sec)

清楚地看到secure_file_priv 的值是NULL,說明此時限制導入導出的
因此應該改變該參數
但是查看了mysql.cnf中竟然沒有對這個參數進行設定,就說明這個參數默認即是null
因此再mysql.cnf中的[mysqld]加入secure_file_priv =

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/home/mysql/data    # mysql數據存放的目錄
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

log_bin=mysql-bin
server-id=1  
secure_file_priv =

再重啓mysql服務

[root@localhost tmp]# systemctl restart mysqld

而後再查一下此時參數的值

mysql> show global variables like '%secure%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| require_secure_transport | OFF   |
| secure_auth              | ON    |
| secure_file_priv         |       |
+--------------------------+-------+
3 rows in set (0.01 sec)

已是咱們要的結果 ,如今咱們再次執行備份命令

[root@localhost tmp]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events --tab="/tmp/mc_orderdb" mc_orderdb 
Enter password: 

--
-- Position to start replication or point-in-time recovery from
--

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
mysqldump: Got error: 1: Can't create/write to file '/tmp/mc_orderdb/order_cart.txt' (Errcode: 13 - Permission denied) when executing 'SELECT INTO OUTFILE'

結果仍是權限被拒絕,沒法寫入,咱們能夠查詢一下目錄mc_orderdb的權限,

[root@localhost tmp]# ls -lh mc_orderdb/
total 4.0K
-rw-r--r-- 1 root root 1.9K Jan 10 10:51 order_cart.sql

能夠發現,是root用戶創建的目錄,咱們須要修改其所屬用戶爲mysql用戶,而後再次執行備份命令

[root@localhost tmp]#  chown mysql:mysql  mc_orderdb
[root@localhost tmp]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events --tab="/tmp/mc_orderdb" mc_orderdb 
Enter password: 

--
-- Position to start replication or point-in-time recovery from
--

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;

--
-- Dumping events for database 'mc_orderdb'
--

--
-- Dumping routines for database 'mc_orderdb'
--
[root@localhost tmp]#

能夠發現,修改爲功後便可備份成功

進入該目錄下會發現mc_orderdb數據庫下的每一個表都有兩種文件,一種.sql結尾記錄是表結構,一種是.txt結尾的表數據

[root@localhost tmp]# cd mc_orderdb/
[root@localhost mc_orderdb]# ls
order_cart.sql  order_customer_addr.sql  order_detail.sql  order_master.sql  region_info.sql  shipping_info.sql  warehouse_info.sql  warehouse_proudct.sql
order_cart.txt  order_customer_addr.txt  order_detail.txt  order_master.txt  region_info.txt  shipping_info.txt  warehouse_info.txt  warehouse_proudct.txt

mysqldump如何使用全備where參數

使用場景

假設咱們要對訂單id爲1000到1050的主表進行修改,修改以前,咱們須要先對數據進行備份,這裏咱們就可使用where參數來完成此需求

執行命令進行備份

[root@localhost db_backup]# mysqldump -ubackup -p --master-data=2 --single-transaction  --where "order_id>1000 and order_id<1050" mc_orderdb  order_master > order_master_1000_1050.sql
Enter password:

查看備份文件能夠發現,訂單id是從1001開始的

在日程工做中咱們不可能一直手工備份,因此咱們須要將備份進行腳本話,而後使用計劃任務去執行腳本

定義備份腳本

腳本文件

#!/bin/bash
###############Basic parameters##########################
DAY=`date +%Y%m%d`    # 記錄發生備份的當前日期
Environment=$(/sbin/ifconfig | grep "inet" | head -1 |grep -v "127.0.0.1" | awk '{print $2;}' )    # 當前主機的IP
USER="backup"
PASSWD="123456"
HostPort="3306"
MYSQLBASE="/home/mysql/"
DATADIR="/home/db_backup/${DAY}"    # 備份存放的目錄(/home/db_backup目錄下的以日期命名的子目錄中)
MYSQL=`/usr/bin/which mysql`    # 定義mysql命令的目錄
MYSQLDUMP=`/usr/bin/which mysqldump`    # 定義mysqldump命令的目錄
mkdir -p ${DATADIR}    # 建立存儲目錄

# 定義備份函數,使用到上面定義的變量

Dump(){
 ${MYSQLDUMP} --master-data=2 --single-transaction  --routines --triggers --events -u${USER} -p${PASSWD} -P${HostPort} ${database}  > ${DATADIR}/${Environment}-${database}.sql
 cd ${DATADIR}
 gzip ${Environment}-${database}.sql    # 對文件進行了壓縮
}

# 利用for循環對當前服務器下的每個數據庫(排除了一些系統視圖所在的數據庫)分別來調用上面的Dump函數來進行備份

for db in `echo "SELECT schema_name FROM information_schema.schemata where schema_name not in ('information_schema','sys','performance_schema')" | ${MYSQL} -u${USER} -p${PASSWD} --skip-column-names`
do
   database=${db}
   Dump
done

執行腳本文件

[root@localhost home]# bash backup.sh 
mysql: [Warning] Using a password on the command line interface can be insecure.
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@localhost home]# cd db_backup/
[root@localhost db_backup]# ls
20190110  mc_orderdb.sql  mc.sql  order_master_1000_1050.sql  order_master.sql
[root@localhost db_backup]# cd 20190110/
[root@localhost 20190110]# ls
172.17.0.1-mc_orderdb.sql.gz  172.17.0.1-mc_productdb.sql.gz  172.17.0.1-mc_userdb.sql.gz  172.17.0.1-mysql.sql.gz

能夠看到結果已備份,可使用crontab命令定時執行此腳本

如何恢復mysqldump備份的數據庫

方法一:

mysql -u -p dbname < backup.sql

方法二:

mysql>  source /tmp/backup.sql

使用mysqldump備份時,恢復的速度徹底取決於MySQL實例執行SQL的速度和服務器的IO性能,而且恢復過程是單線程的,因此對於很是大的數據集來講,要恢復的話可能須要很長的時間

演示:

把剛纔的全備數據恢復到bak數據庫中

建立bak_orderdb數據庫

[root@localhost db_backup]# mysql -uroot -p -e"create database bak_orderdb"
Enter password:

將mc_orderdb備份的數據恢復到bak數據庫中

[root@localhost db_backup]#  mysql -uroot -p bak_orderdb < mc_orderdb.sql
Enter password: 
[root@localhost db_backup]#

檢驗恢復結果的正確性

mysql> SELECT COUNT(*) FROM mc_orderdb.order_master;
+----------+
| COUNT(*) |
+----------+
|    10010 |
+----------+
1 row in set (0.00 sec)

mysql> SELECT COUNT(*) FROM bak_orderdb.order_master;
+----------+
| COUNT(*) |
+----------+
|    10010 |
+----------+
1 row in set (0.00 sec)
模擬誤操做並恢復數據

假設咱們如今不當心刪除了mc_orderdb下的order_master中的10條數據,咱們如今須要經過剛剛恢復的備份數據庫把這10條數據恢復回來

mysql> DELETE FROM mc_orderdb.order_master LIMIT 10;
Query OK, 10 rows affected (0.01 sec)

mysql>  SELECT COUNT(*) FROM mc_orderdb.order_master;
+----------+
| COUNT(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.00 sec)

首先查出被誤刪的數據
SELECT a.* FROM bak_orderdb.order_master a LEFT JOIN mc_orderdb.order_master b ON a.order_id=b.order_id WHERE b.order_id IS NULL;
而後執行insert語句將查出的數據插入回去

完整語句爲

INSERT INTO mc_orderdb.order_master(
order_id,order_sn,customer_id,shipping_user,province,city,district,address,
payment_method,order_money,district_money,shipping_money,payment_money,
shipping_comp_name,shipping_sn,create_time,shipping_time,pay_time,receive_time,
order_status,order_point,invoice_title,modified_time)
SELECT a.* FROM bak_orderdb.order_master a 
LEFT JOIN mc_orderdb.order_master b ON a.order_id=b.order_id
WHERE b.order_id IS NULL;

執行結果:

mysql> INSERT INTO mc_orderdb.order_master(
    -> order_id,order_sn,customer_id,shipping_user,province,city,district,address,
    -> payment_method,order_money,district_money,shipping_money,payment_money,
    -> shipping_comp_name,shipping_sn,create_time,shipping_time,pay_time,receive_time,
    -> order_status,order_point,invoice_title,modified_time)
    -> SELECT a.* FROM bak_orderdb.order_master a 
    -> LEFT JOIN mc_orderdb.order_master b ON a.order_id=b.order_id
    -> WHERE b.order_id IS NULL;
Query OK, 10 rows affected (0.03 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> SELECT COUNT(*) FROM mc_orderdb.order_master;
+----------+
| COUNT(*) |
+----------+
|    10010 |
+----------+
1 row in set (0.00 sec)

對於一些靜態型數據咱們能夠這樣進行,可是對於一些時刻有數據在往表裏寫的數據還原,就不能使用這種方式了

對於生產環境中,時刻有數據寫入的表如何進行數據恢復呢?

mysqldump單表備份恢復(使用了--tab參數備份的結果集)

須要進入mysql客戶端中

先恢復表結構

mysql>  source /tmp/mc_orderdb/region_info.sql;

再導入數據

mysql>     load data infile '/tmp/mc_orderdb/region_info.txt' info table region_info;

如何進行指定時間點的恢復

進行某一時間點的數據恢復,恢復到誤操做的時間

先決條件:

具備指定時間點前的mysqldump的全備
具備全備到指定時間點的mysql二進制日誌

演示

首先咱們須要有個數據庫的全備,此處咱們對mc_orderdb 數據庫進行全備

[root@localhost db_backup]# mysqldump -ubackup -p --master-data=2 --single-transaction --routines --triggers --events mc_orderdb > mc_orderdb.sql

而後咱們模擬一下生產環境中對數據庫的操做,這樣才能看到時間點恢復的效果

咱們到mc_orderdb數據庫中新建一個統計表 t, uid列是用戶id,cnt 是用戶的總消費金額,將統計結果插入表t中後,模擬誤操做,刪除表t中的100行數據

mysql> use mc_orderdb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> create table t(id int auto_increment not null,uid int,cnt decimal(8,2),primary key (id));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t(uid,cnt) select customer_id,sum(order_money) from order_master group by customer_id;
Query OK, 6314 rows affected (0.05 sec)
Records: 6314  Duplicates: 0  Warnings: 0

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|     6314 |
+----------+
1 row in set (0.00 sec)

mysql> delete from t limit 100;
Query OK, 100 rows affected (0.01 sec)

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|     6214 |
+----------+
1 row in set (0.01 sec)

先恢復一個最近的全備,進行全量數據恢復

[root@localhost db_backup]# mysql -uroot -p mc_orderdb < mc_orderdb.sql

而後查看mc_orderdb.sql文件中change master命令中

在進行這個全備時Mysql二進制日誌的文件名(MASTER_LOG_FILE),以及時間點(MASTER_LOG_POS)

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;

此處文件名爲mysql-bin.000001,日誌時間點爲154;

下面咱們要恢復這個時間點(154)以後到第一次刪除數據以前的數據

要找到這個時間點(154)以後到第一次刪除數據以前的數據

查看二進制日誌,進行分析

[root@localhost db_backup]# cd /home/mysql
[root@localhost mysql]# mysqlbinlog --base64-output=decode-rows -vv --start-position=154 --database=mc_orderdb mysql-bin.000001| grep -B3 DELETE | more
#190110 13:44:54 server id 1  end_log_pos 83285 CRC32 0xf679d195    Table_map: `mc_orderdb`.`t` mapped to number 119
# at 83285
#190110 13:44:54 server id 1  end_log_pos 84620 CRC32 0xa3408e6c    Delete_rows: table id 119 flags: STMT_END_F
### DELETE FROM `mc_orderdb`.`t`
--
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1042.34 /* DECIMAL(8,2) meta=2050 nullable=1 is_null=0 */
### DELETE FROM `mc_orderdb`.`t`
--
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=803.37 /* DECIMAL(8,2) meta=2050 nullable=1 is_null=0 */

...省略

從中能夠看到剛剛的二進制日誌中的第一個DELETE,在它以前的日誌結束點爲84620

因此咱們須要恢復的是154 到84620 之間,且數據庫爲mc_orderdb ,日誌所在文件名 爲mysql-bin.000001的數據

咱們經過mysqlbinlog 將這些數據導出來

[root@localhost mysql]# mysqlbinlog --start-position=154 --stop-position=84620 --database=mc_orderdb mysql-bin.000001 > mc_order_diff.sql

將數據導入恢復

[root@localhost mysql]# mysql -uroot -p mc_orderdb < mc_order_diff.sql

實時二進制日誌備份

Mysql5.6版本以後,能夠實時備份Binlog(二進制日誌)

要使用這個功能,咱們須要進行如下配置
首先新建一個用戶,這個用戶要有replication slave 權限

mysql>  grant replication slave on *.* to 'repl'@'localhost' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)

創建一個存儲備份的二進制日誌文件的目錄

mkdir -p binlog_backup

最後在這個目錄下,執行如下命令,就能夠實時的進行二進制日誌的備份了

[root@localhost binlog_bak]# mysqlbinlog --raw --read-from-remote-server --stop-never --host localhost --port 3306 -u repl -p123456 mysql-bin.000001
mysqlbinlog: [Warning] Using a password on the command line interface can be insecure.

raw:表明這個命令是輸出的是raw格式的二進制日誌
read-from-remote-server: 從mysql服務器上讀取這個日誌
stop-never:備份的這個進程會持續在後臺運行
最後的是指定要備份的二進制文件的名稱

此命令執行後這個終端會一直執行這個命令
如今打開另一個終端,進入備份的目錄進行查看

[root@localhost mysql]# cd /home/binlog_bak/
[root@localhost binlog_bak]# ls
mysql-bin.000001

能夠看到日誌已經備份成功
進入mysql命令行,刷新日誌

mysql> flush logs;
Query OK, 0 rows affected (0.01 sec)

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |   3560467 |
| mysql-bin.000002 |       154 |
+------------------+-----------+
2 rows in set (0.00 sec)

如今有兩個日誌,咱們再回到備份目錄進行查看

[root@localhost binlog_bak]# ls
mysql-bin.000001  mysql-bin.000002

能夠看到最新的日誌也已實時備份

三. xtrabackup

1. xtrabackup介紹

xtrabackup 物理備份工具,用於在線備份innodb存儲引擎的表

在全部表全是innodb存儲引擎表的狀況下:
xtrabackup 能夠保證在備份過程當中,不影響表的讀寫操做
在最初的時候,xtrabackup 自己只支持對innodb存儲引擎表的備份,且只會備份數據文件,不會備份表的結構
innobackupex 是對xtrabackup 的插件,提供了備份表結構及其餘配置信息的功能,並支持MyISAM表的備份,但也會鎖表

由於在當前的mysql版本下,還有一些系統表使用的是MyISAM存儲引擎,因此通常狀況下使用的是innobackupex 腳本進行備份的

2. 安裝xtrabackup

3. 利用innobackupex 進行全備

innobackupex --user=backup --password=123456 --parallel=2 /home/db_backup/
[root@localhost home]# innobackupex --user=backup --password=123456 --parallel=2 /home/db_backup/
xtrabackup: recognized server arguments: --datadir=/home/mysql --log_bin=mysql-bin --server-id=1 --parallel=2 
xtrabackup: recognized client arguments: --datadir=home/mysql --log_bin=mysql-bin --server-id=1 --parallel=2 
190110 15:15:30 innobackupex: Starting the backup operation

IMPORTANT: Please check that the backup run completes successfully.
           At the end of a successful backup run innobackupex
           prints "completed OK!".

... 省略

190110 15:15:37 [00] Writing /home/db_backup/2019-01-10_15-15-30/xtrabackup_info
190110 15:15:37 [00]        ...done
xtrabackup: Transaction log of lsn (79088947) to (79088956) was copied.
190110 15:15:37 completed OK!

當看到completed OK!表明備份已完成

和mysqldump單線程備份不一樣,咱們能夠經過parallel參數指定備份的線程數
/home/db_backup/ 是咱們指定的備份文件的存儲目錄

xtrabackup 會已當前時間在目標目錄中生成一個子目錄用來存放當前的備份文件

咱們進入目錄中查看一下

[root@localhost db_backup]# ls
20190110  2019-01-10_15-15-30  mc_orderdb.sql  mc.sql  order_master_1000_1050.sql  order_master.sql
[root@localhost db_backup]# cd 2019-01-10_15-15-30/
[root@localhost 2019-01-10_15-15-30]# ls
backup-my.cnf  ib_buffer_pool  mc_orderdb    mc_userdb  performance_schema  xtrabackup_binlog_info  xtrabackup_info
bak_orderdb    ibdata1         mc_productdb  mysql      sys                 xtrabackup_checkpoints  xtrabackup_logfile

與原數據文件目錄相比,少了ib_logfile0等日誌文件

xtrabackup_binlog_info 比較重要,其中記錄了備份的日誌名和日誌點,至關於mysqldump中設置master-data參數的做用

若是咱們不想以時間戳的形式自動生成子目錄,咱們能夠經過指定--no-timestamp參數來實現

innobackupex --user=backup --password=123456 --parallel=2  /home/db_backup/2019-01-10 --no-timestamp
[root@localhost db_backup]#  innobackupex --user=backup --password=123456 --parallel=2  /home/db_backup/2019-01-10 --no-timestamp
[root@localhost db_backup]# ls
20190110  2019-01-10  2019-01-10_15-15-30  mc_orderdb.sql  mc.sql  order_master_1000_1050.sql  order_master.sql
[root@localhost db_backup]# cd 2019-01-10
[root@localhost 2019-01-10]# ls
backup-my.cnf  ib_buffer_pool  mc_orderdb    mc_userdb  performance_schema  xtrabackup_binlog_info  xtrabackup_info
bak_orderdb    ibdata1         mc_productdb  mysql      sys                 xtrabackup_checkpoints  xtrabackup_logfile
[root@localhost 2019-01-10]#

4. 利用innobackupex 進行全備的恢復

innobackupex  --apply-log /path/to/BACKUP-DIR
mv /path/to/BACKUP-DIR /home/mysql/data

利用xtrabackup備份產生的備份集並不能直接用於數據庫的恢復
進行數據庫恢復以前,咱們必須把備份中產生的備份集 進行應用,此處咱們使用的是備份文件的目錄僞2019-01-10

[root@localhost db_backup]# innobackupex --apply-log /home/db_backup/2019-01-10
[root@localhost db_backup]# cd 2019-01-10
[root@localhost 2019-01-10]# ls
backup-my.cnf   ib_logfile0  mc_productdb        sys                           xtrabackup_info
bak_orderdb     ib_logfile1  mc_userdb           xtrabackup_binlog_info        xtrabackup_logfile
ib_buffer_pool  ibtmp1       mysql               xtrabackup_binlog_pos_innodb  xtrabackup_master_key_id
ibdata1         mc_orderdb   performance_schema  xtrabackup_checkpoints

能夠發現,使用了上面的命令後,備份集中多出了以前缺乏的ib_logfile0等文件

使用xtrabackup進行數據庫恢復時,咱們必須對數據庫實例進行重啓
先停用mysql服務

而後將原數據庫文件所在的文件夾重命名爲data_bak,而後將此時的 2019-01-10文件夾移動到data_bak所在的文件夾,並重命名爲data,即覆蓋了原來的文件

而後 chown -R mysql:mysql data
對文件夾修改所屬用戶

最後重啓mysql服務便可

5. 利用innobackupex 進行增量備份

innobackupex --user=backup --password=123456 /home/db_backup    # 先進行全備
  
innobackupex --user=backup --password=123456 --incremental  /home/db_backup/  --incremental-basedir=/home/db_backup/2019-01-10/

incremental :表示咱們要進行的是一個全備, 指定全備的目錄
incremental-basedir :指定增量備份所依賴的數據基礎的備份目錄,這個增量備份所依賴的上一個全備

演示:

先進行全備

innobackupex --user=backup --password=123456 /home/db_backup

在 /home/db_backup 目錄下生產了一個新的全備子目錄 2019-01-10_16-19-37

再依賴上個全量備份進行增量備份

innobackupex --user=backup --password=123456 --incremental  /home/db_backup/  --incremental-basedir=/home/db_backup/2019-01-10_16-19-37/

此時在 /home/db_backup 目錄下生產了一個增量備分的子目錄2019-01-10_16-22-09
增量備份會把自上一個全備後的數據變動記錄下來

而後再進行一次增量備份,此時的命令和前面基本相同,只是所基於的增量備份的數據目錄要變成上次增量備份生成的目錄

innobackupex --user=backup --password=123456 --incremental  /home/db_backup/  --incremental-basedir=/home/db_backup/2019-01-10_16-22-09/

此時,第二次增量備份的生成的目錄名爲2019-01-10_16-24-09

6. 利用innobackupex 進行增量恢復

innobackupex  --apply-log  --redo-only 全備目錄

咱們要循環的在屢次增量備份中應用上面步驟

innobackupex  --apply-log  --redo-only 全備目錄  --incremental-dir=第一次增量目錄

全部增量備份的都應有了上面的命令後,就能夠像全備同樣,在全備目錄上再進行崩潰恢復的過程

innobackupex  --apply-log /path/to/BACKUP-DIR
    mv /path/to/BACKUP-DIR /home/mysql/data

最後和全備同樣,要用全備目錄替換mysql數據庫目錄

演示

下面演示只恢復到第一次備份

[root@localhost db_backup]#   innobackupex  --apply-log  --redo-only    /home/db_backup/2019-01-10_16-19-37

[root@localhost db_backup]#   innobackupex  --apply-log  --redo-only    /home/db_backup/2019-01-10_16-19-37  --incremental-basedir=/home/db_backup/2019-01-10_16-22-09

[root@localhost db_backup]#   innobackupex  --apply-log   /home/db_backup/2019-01-10_16-19-37 

[root@localhost db_backup]#  mv 2019-01-10_16-19-37  /home/mysql

[root@localhost db_backup]#  cd  /home/mysql

[root@localhost mysql]#  systemctl stop  mysqld

[root@localhost mysql]#  mv 2019-01-10_16-19-37 data

[root@localhost mysql]# chown -R mysql:mysql data

[root@localhost mysql]#  systemctl start mysqld

四. 要制定備份計劃

天天凌晨對數據庫進行一次全備 實時對二進制日誌進行遠程備份

相關文章
相關標籤/搜索