1. 程式人生 > >Mysql——3、mysql備份和恢復

Mysql——3、mysql備份和恢復

一、為什麼要備份?

災難恢復:硬體故障、軟體故障、自然災害、黑客攻擊、誤操作;
測試:
要注意的要點:
可容忍丟失多少資料;
恢復需要在多長時間內完成;
需要恢復哪些資料;
(1)做還原測試,用於測試備份的可用性;
(2)還原演練

二、備份型別

2.1 完全備份,部分備份:
完全備份:整個資料集
部分備份:僅備份其中的一張表或多張表;

2.2 完全備份,增量備份,差異備份
增量備份:僅備份最近一次完全備份或增量備份(如果存在增量)之後變化的資料部分;
差異備份:僅備份最近一次完全備份以來變化的資料;

2.3 熱備份、溫備份和冷備份:
熱備份:線上備份,讀寫操作不受影響;
溫備份:線上備份,讀操作可繼續進行,但寫操作不允許;
冷備份:離線備份,資料庫伺服器離線,備份期間不能為業務提供讀寫服務;

MyISAM: 溫備
InnoDB: 熱備

2.4 物理備份和邏輯備份:
物理備份:直接複製資料檔案進行的備份;
邏輯備份:從資料庫中“匯出”資料另存而進行的備份(與儲存引擎無關);

2.5 規則備份時需要考慮的因素:
持鎖的時長
備份過程時長
備份負載
恢復過程時長

三、備份什麼?

資料、額外的資料(二進位制日誌和InnoDB的事務日誌)、程式碼(儲存過程和儲存函式、觸發器、事件排程器等)、伺服器配置檔案

3.1 設計備份方案:
資料集:完全備份+增量備份;
備份手段:物理備份、邏輯備份;

3.2 備份工具:
(1)mysqldump: 邏輯備份工具,適用於所有儲存引擎,溫備;完全備份,部分備份;對InnoDB儲存引擎支援熱備;
(2)cp, tar等檔案系統工具:物理備份工具,適用於所有儲存引擎;冷備;完全備份,部分備份;
(3)lvm2的快照:幾乎熱備;藉助於檔案系統管理工具實現物理備份;
(4)mysqlhotcopy: 幾乎冷備;僅適用於MyISAM儲存引擎;

3.3 備份工具的選擇:
(1)mysqldump+複製binlog:
mysqldump:完全備份;
複製binlog中指定時間範圍的event:通過備份二進位制日誌實現增量備份;
(2)lvm2快照+binlog:
lvm2快照:使用cp, tar等做物理備份,完全備份;
複製binlog中指定時間範圍的event:增量備份;
(3)xtrabackup:
由Percona提供的支援對InnoDB做熱備(物理備份)的工具,支援完全備份和增量備份
(4)對MyISAM引擎:溫備,只支援完全備份

三、備份工具使用

邏輯備份工具:mysqldump, mydumper, phpMyAdmin
Schema和資料儲存一起、巨大的SQL語句、單個巨大的備份檔案
3.1 mysqldump


客戶端命令,通過mysql協議連線至mysqld;
mysqldump [options] [db_name [tb1_name …]]
命令的語法格式:
mysqldump [OPTIONS] database [tables]:備份單個庫,或庫指定的一個或多個表
mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3…]:備份一個或多個庫
mysqldump [OPTIONS] --all-databases [OPTIONS]:備份所有庫
例如: mysqldump -uroot -P13506 -p --databases hellodb > /tmp/hellodb.sql

**3.2 MyISAM:**支援溫備:不能熱備,不能增備;鎖定備份庫,而後啟動備份操作;
鎖定方法:
–lock-all-tables:鎖定所有庫的所有表;
–lock-tables:對於每個單獨的資料庫,在啟動備份之前鎖定其所有表;
對InnoDB表一樣生效,實現溫備;
3.3 InnoDB:支援熱備,增備:
–single-transaction 啟動一個大的單一事務實現備份
-B, --databases db_name1 db_name2 …:備份指定的資料庫
-C, --compress:壓縮傳輸;
其它選項:
-E, --events:備份指定庫的所有事件排程器;
-R, --routines:備份指定庫的儲存過程和儲存函式;
–triggers:備份表相關的觸發器
–master-data[=#]:
1:記錄CHANGE MASTER TO語句;此語句未被註釋;
2:記錄為註釋語句的CHANGE MASTER TO語句;
–flush-logs, -F:鎖定表之後,執行flush logs命令;
注意:二進位制日誌檔案與資料檔案不應該放置於同一磁碟!!!

使用案例:小規模,每週完全備份,每日增量備份

使用一: 用mysqldump實現對指定資料庫的備份;

#!bin/bash
cd /tmp
a=`date +%Y%m%d-%H%M%S`
#備份全部資料庫的資料和結構
mysqldump -u資料使用者名稱 -p資料庫密碼 --all-databases > backup-$a.sql
#備份全部資料庫的結構(加 -d 引數)
#mysqldump -uroot -p123456 -A -d > /data/mydb.sql
#備份全部資料庫的資料(加 -t 引數)
#mysqldump -uroot -p123456 -A -t > /data/mydb.sql

指令碼示例:
1.首先設定各項引數,例如number最多需要備份的數目,備份路徑,使用者名稱,密碼等。
2.執行mysqldump命令儲存備份檔案,並將操作列印至同目錄下的log.txt中標記操作日誌。
3.定義需要刪除的檔案:通過ls命令獲取第九列,即檔名列,再通過head -1實現定義操作時間最晚的那個需要刪除的檔案。
4.定義備份數量:通過ls命令加上wc -l統計以sql結尾的檔案的行數。
5.如果檔案超出限制大小,就刪除最早建立的sql檔案

#!/bin/bash

#儲存備份個數,備份31天資料
number=31
#備份儲存路徑
backup_dir=/root/mysqlbackup
#日期
dd=`date +%Y-%m-%d-%H-%M-%S`
#備份工具
tool=mysqldump
#使用者名稱
username=root
#密碼
password=TankB214
#將要備份的資料庫
database_name=edoctor

#如果資料夾不存在則建立
if [ ! -d $backup_dir ]; 
then     
    mkdir -p $backup_dir; 
fi

#簡單寫法  mysqldump -u root -p123456 users > /root/mysqlbackup/users-$filename.sql
$tool -u $username -p$password $database_name > $backup_dir/$database_name-$dd.sql

#寫建立備份日誌
echo "create $backup_dir/$database_name-$dd.dupm" >> $backup_dir/log.txt

#找出需要刪除的備份
delfile=`ls -l -crt  $backup_dir/*.sql | awk '{print $9 }' | head -1`

#判斷現在的備份數量是否大於$number
count=`ls -l -crt  $backup_dir/*.sql | awk '{print $9 }' | wc -l`

if [ $count -gt $number ]
then
  #刪除最早生成的備份,只保留number數量的備份
  rm $delfile
  #寫刪除檔案日誌
  echo "delete $delfile" >> $backup_dir/log.txt
fi

定期執行編寫的定時任務指令碼(記得先給shell指令碼執行許可權)

0 2 * * * /root/mysql_backup_script.sh

還原備份檔案(第一種是在MySQL命令列中,第二種是使用SHELL行完成還原):

#1.在系統命令列中,輸入如下實現還原:
mysql -uroot -p123456 < /data/mydb.sql
#2.在登入進入mysql系統中,通過source指令找到對應系統中的檔案進行還原:
mysql> source /data/mydb.sql

使用二:實現利用binary logs完成增量備份;

首先在進行增量備份之前需要檢視一下配置檔案,檢視 log_bin 是否開啟,因為要做增量備份首先要開啟 log_bin 。首先,進入到 myslq 命令列,輸入如下命令:

show variables like '%log_bin%';

如下命令所示,則為未開啟

mysql> show variables like '%log_bin%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin                         | OFF   |
| log_bin_basename                |       |
| log_bin_index                   |       |
| log_bin_trust_function_creators | OFF   |
| log_bin_use_v1_row_events       | OFF   |
| sql_log_bin                     | ON    |
+---------------------------------+-------+

修改 MySQL 配置項到如下程式碼段:vim /etc/mysql/mysql.conf.d/mysqld.cnf

# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
​
#
# The MySQL  Server configuration file.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
​
[mysqld]
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
datadir     = /var/lib/mysql
#log-error  = /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address   = 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
​
#binlog setting,開啟增量備份的關鍵
log-bin=/var/lib/mysql/mysql-bin
server-id=123454

修改之後,重啟 mysql 服務,輸入:

show variables like '%log_bin%';

狀態如下:

mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name                   | Value                          |
+---------------------------------+--------------------------------+
| log_bin                         | ON                             |
| log_bin_basename                | /var/lib/mysql/mysql-bin       |
| log_bin_index                   | /var/lib/mysql/mysql-bin.index |
| log_bin_trust_function_creators | OFF                            |
| log_bin_use_v1_row_events       | OFF                            |
| sql_log_bin                     | ON                             |
+---------------------------------+--------------------------------+

好了,做好了充足的準備,那我們就開始學習增量備份了。
檢視當前使用的 mysql_bin.000*** 日誌檔案,

show master status;

狀態如下:

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000015 |      610 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

當前正在記錄日誌的檔名為 mysql-bin.000015 。
當前資料庫中有如下資料:

mysql> select * from users;
+-------+------+----+
| name  | sex  | id |
+-------+------+----+
| zone  | 0    |  1 |
| zone1 | 1    |  2 |
| zone2 | 0    |  3 |
+-------+------+----+

我們插入一條資料:

insert into `zone`.`users` ( `name`, `sex`, `id`) values ( 'zone3', '0', '4');

檢視效果:

mysql> select * from users;
+-------+------+----+
| name  | sex  | id |
+-------+------+----+
| zone  | 0    |  1 |
| zone1 | 1    |  2 |
| zone2 | 0    |  3 |
| zone3 | 0    |  4 |
+-------+------+----+

我們執行如下命令,使用新的日誌檔案:

mysqladmin -uroot -123456 flush-logs

日誌檔案從 mysql-bin.000015 變為 mysql-bin.000016,而 mysql-bin.000015 則記錄著剛剛 insert 命令的日誌。上句程式碼的效果如下:

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000016 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

那麼到現在為止,其實已經完成了增量備份了。
恢復增量備份
那麼現在將剛剛插入的資料刪除,效果如下:

delete from `zone`.`users` where `id`='4' 
mysql> select * from users;
+-------+------+----+
| name  | sex  | id |
+-------+------+----+
| zone  | 0    |  1 |
| zone1 | 1    |  2 |
| zone2 | 0    |  3 |
+-------+------+----+

那麼現在就是重點時間了,從 mysql-bin.000015 中恢復資料:

mysqlbinlog /var/lib/mysql/mysql-bin.000015 | mysql -uroot -p123456 zone;

上一句程式碼指定了,需要恢復的 mysql_bin 檔案,指定了使用者名稱:root 、密碼:123456 、資料庫名:zone。效果如下:

mysql> select * from users;
+-------+------+----+
| name  | sex  | id |
+-------+------+----+
| zone  | 0    |  1 |
| zone1 | 1    |  2 |
| zone2 | 0    |  3 |
| zone3 | 0    |  4 |
+-------+------+----+

OK,整一個增量備份的操作流程都在這裡了,那麼我們如何將它寫成指令碼檔案呢,程式碼如下:

#!/bin/bash
#在使用之前,請提前建立以下各個目錄
BakDir=/usr/local/work/backup/daily
#增量備份時複製mysql-bin.00000*的目標目錄,提前手動建立這個目錄
BinDir=/var/lib/mysql
#mysql的資料目錄
LogFile=/usr/local/work/backup/bak.log
BinFile=/var/lib/mysql/mysql-bin.index
#mysql的index檔案路徑,放在資料目錄下的
​
mysqladmin -uroot -p123456 flush-logs

#這個是用於產生新的mysql-bin.00000*檔案
# wc -l 統計行數
# awk 簡單來說awk就是把檔案逐行的讀入,以空格為預設分隔符將每行切片,切開的部分再進行各種分析處理。
Counter=`wc -l $BinFile |awk '{print $1}'`
NextNum=0
#這個for迴圈用於比對$Counter,$NextNum這兩個值來確定檔案是不是存在或最新的
for file in `cat $BinFile`
do
    base=`basename $file`
    echo $base
    #basename用於擷取mysql-bin.00000*檔名,去掉./mysql-bin.000005前面的./
    NextNum=`expr $NextNum + 1`
    if [ $NextNum -eq $Counter ]
    then
        echo $base skip! >> $LogFile
    else
        dest=$BakDir/$base
        if(test -e $dest)
        #test -e用於檢測目標檔案是否存在,存在就寫exist!到$LogFile去
        then
            echo $base exist! >> $LogFile
        else
            cp $BinDir/$base $BakDir
            echo $base copying >> $LogFile
         fi
     fi
done
echo `date +"%Y年%m月%d日 %H:%M:%S"` $Next Bakup succ! >> $LogFile

四、物理備份:資料檔案的時間一致性?

基於lvm2快照+cp(tar)的備份

1、請求鎖定所有表:

mysql> FLUSH TABLES WITH READ LOCK;

2、記錄二進位制日誌檔案及事件位置:

mysql> SHOW MASTER STATUS;
mysql -e 'SHOW MASTER STATUS' > /PATH/TO/SOMEFILE

3、建立快照:
lvcreate -L SIZE -s -p r -n NAME /dev/VG_NAME/LV_NAME
如:

lvcreate -L 2G -s -n  mydata-snap -p r /dev/myvg/mydata
mke2fs -t ext4 /dev/myvg/mydata-snap
mount /dev/myvg/mydata-snap /data
mkdir -v /data/{mysql,binlogs}
chown -R mysql.mysql /data/*

修改/etc/my.cnf.d/server.conf的二進位制日誌存放位置:log_bin=/data/binlogs/mysql-bin
啟動資料庫systemctl start mariadb
4、釋放鎖:

mysql> UNLOCK TABLES

5、掛載快照卷,複製資料進行備份;
cp, rsync, tar等命令複製資料;
6、備份完成之後,刪除快照卷;

mysql> SET SESSION sql_log_bin=0;
mysql> SOURCE /path/from/somefile.sql;
mysql> SET SESSION sql_log_bin=1;

mysql> FLUSH TABLES WITH READ LOCK;
mysql> FLUSH LOGS;

7、制定好策略,通過原卷備份二進位制日誌

mysql -e 'SHOW MASTER STATUS';> /root/pos-`date +%F`

五、Xtrabackup(MySQL 資料庫物理熱備的備份工具)

www.percona.com
下載地址:https://www.percona.com/downloads/XtraBackup/LATEST/
innobackupex: 客戶端工具, 以mysql協議連入mysqld,不支援離線備份

完整備份策略:完整備份 + 增量備份 + 二進位制日誌

注意:
1、將資料和二進位制檔案放置於不同的裝置;二進位制日誌也應該週期性地備份;
2、將資料和備份分開存放,建議不在同一裝置、同一主機、同一機房、同一地域;
3、每次災難恢復後都應該立即做一次完全備份;
4、備份後的資料應該週期性地做還原測試;

從備份中恢復應該遵循的步驟:
1、停止MySQL伺服器;
2、記錄伺服器配置和檔案許可權;
3、將備份恢復到MySQL資料目錄;此步驟依賴具體的備份工具;
4、改變配置和檔案許可權;
5、以限制方式啟動MySQL伺服器:比如通過網路訪問;
[mysqld]
skip-networking
socket=/tmp/mysql-recovery.sock
6、載入額外的邏輯備份;而檢查和重放二進位制日誌;
7、檢查已經還原的資料;
8、以完全訪問模式重啟伺服器;

其它的備份工具:
	SELECT ... INTO OUTFILE ''
	LOAD FILE 

	mylvmbackup