centos7下mysql定時全量備份、增量備份實現方法


最近學習的數據庫自動定時備份的方法,從網上看的很多資料,大部分文章都是用的腳本之家的那個模板(原代碼地址:https://www.jb51.net/article/99938.htm),但是都沒有很詳細的解釋,作為小白自己弄懂如何實現還是要花一點功夫,所以記錄一下自己的學習過程。本文大部分內容都是從多篇文章中把有用的知識點復制過來整合而成的。

在數據庫的日常維護工作中,除了保證業務的正常運行以外,就是要對數據庫進行備份,以免造成數據庫的丟失,從而給企業帶來重大經濟損失。
  通常備份可以按照備份時數據庫狀態分為熱備和冷備,按照備份數據庫文件的大小分為增量備份、差異備份和全量備份。

 

完整備份:每次都將所有數據(不管自第一次備份以來有沒有修改過),進行一次完整的復制,備份后會清除文件的存檔屬性(存檔屬性可以理解為對文件修改並保存以后做的標記),方便日后增量備份或者差異備份進行版本比較。

特點:占用空間大,備份速度慢,但恢復時一次恢復到位,恢復速度快。

 

增量備份:在第一次完整備份之后,第二次開始每次都將添加了存檔屬性的文件進行備份,並且在備份之后再把這些存檔屬性清除。為什么要清除存檔屬性呢?這就是為了下一次備份的時候判斷是否有文件變化,因為用戶在每次備份以后修改這些被清除存檔屬性的文件,存檔屬性就會自動加上,相當於用戶告訴系統,這些文件有變化,你下一次就備份這些文件,其他沒有存檔屬性的就不需要備份,這就是增量備份的工作機制。

(相當於機器人把地板打掃干凈了,你踩過,就會有腳印(增加標記),下次機器人就把腳印記錄下來,並且把腳印打掃干凈(清除標記),始終保持地板干凈。機器人每次記錄並打掃的腳印就相當於每次增量備份的內容)

特點:因每次僅備份自上一次備份(注意是上一次,不是第一次)以來有變化的文件,所 以備份體積小,備份速度快,但是恢復的時候,需要按備份時間順序,逐個備份版本進行恢復,恢復時間長。

 

差異備份:在第一次完整備份之后,第二次開始每次都將所有文件與第一次完整備份的文件做比較,把自第一次完整備份以來所有修改過的文件進行備份,且以后每次備份都是和第一次完整備份進行比較(注意是第一次,不是上一次),備份自第一次完整備份以來所有的修改過的文件。因此,差異備份在備份完畢之后不需要清除文件的存檔屬性,因為這些文件和下一次備份沒有什么關系,它僅僅和第一次完整備份的數據進行比較(第一次完整備份之后是清除存檔屬性的)。

(相當於第一次機器人把地板打掃干凈了,你踩過,就會有腳印,機器人就把腳印記錄下來,但不打掃,下次你又有踩臟的,機器人就把你這幾次所有踩臟的地方都記錄下來,始終不打掃,每次都這樣。機器人每次記錄的內容就相當於差異備份的內容)

特點:占用空間比增量備份大,比完整備份小,恢復時僅需要恢復第一個完整版本和最后一次的差異版本,恢復速度介於完整備份和增量備份之間。

 

簡單的講,完整備份就是不管三七二十一,每次都把指定的備份目錄完整的復制一遍,不管目錄下的文件有沒有變化;增量備份就是每次將之前(第一次、第二次、直到前一次)做過備份之后有變化的文件進行備份;差異備份就是每次都將第一次完整備份以來有變化的文件進行備份。

所以一般數據庫備份時間會選擇在訪問量很小的半夜,一星期完全備份一次,每天增量備份一次。這樣既不會損耗太大的服務器性能,又可以確保數據安全,通過腳本定時執行的方法來完成夜間自動備份。

 

做這個之前需要開通vi /etc/my.conf     中添加log-bin日志

 

 

1.首先要在/home/mysql/目錄下建立以下目錄:

mkdir -p /home/mysql/backup/daily

2.然后把路徑 /home/mysql的用戶和組改成mysql,代碼如下:

 

 

 

3.然后在/etc/my.cnf文件中加入以下代碼:

log-bin = "/home/mysql/logbin.log"

binlog-format = ROW

log-bin-index = "/home/mysql/logindex"

binlog_cache_size=32m

max_binlog_cache_size=512m

max_binlog_size=512m

server-id=1

 

4.再使用service mysqld restart命令重啟mysql(server-id=1在原教程中沒有,但是不添加的話會出現這個錯

5.接下來就可以寫腳本了,先是增量備份的代碼,

cd /home/mysql

vi binlogbak.sh

6.然后寫入以下代碼(要改的地方就是:mysqladmin -uroot -proot123 flush-logs;

-u+鏈接數據庫的用戶 -p+密碼 ):

#!/bin/bash

export LANG=en_US.UTF-8

BakDir=/home/mysql/backup/daily

BinDir=/home/mysql

LogFile=/home/mysql/backup/binlog.log

BinFile=/home/mysql/logindex.index

mysqladmin -uroot -proot123 flush-logs

#這個是用於產生新的mysql-bin.00000*文件

Counter=`wc -l $BinFile |awk '{print $1}'`

NextNum=0

#這個for循環用於比對$Counter,$NextNum這兩個值來確定文件是不是存在或最新的。

for file in `cat $BinFile`

do

    base=`basename $file`

#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"` Bakup succ! >> $LogFile

 

 

7.接下來賦予binlogbak.sh執行權限:

chmod a+x /home/mysql/binlogbak.sh

8.再寫全量備份的代碼:

vi databak.sh

9.加入以下代碼(要改的地方就是:mysqldump -uroot -proot123 --all-databases --flush-logs --delete-master-logs --single-transaction > $DumpFile;

-u+鏈接數據庫的用戶 -p+密碼; --all-databases這句是指定完全備份哪個數據庫,基本語法:

):

#!/bin/bash

export LANG=en_US.UTF-8

BakDir=/home/mysql/backup

LogFile=/home/mysql/backup/bak.log

Date=`date +%Y%m%d`

Begin=`date +"%Y年%m月%d日 %H:%M:%S"`

cd $BakDir

DumpFile=$Date.sql

GZDumpFile=$Date.sql.tgz

mysqldump -uroot -proot123 --all-databases --flush-logs --delete-master-logs --single-transaction > $DumpFile

tar -czvf $GZDumpFile $DumpFile

rm $DumpFile

 

count=$(ls -l *.tgz |wc -l)

if [ $count -ge 5 ]

then

file=$(ls -l *.tgz |awk '{print $9}'|awk 'NR==1')

rm -f $file

fi

#只保留過去四周的數據庫內容

 

Last=`date +"%Y年%m月%d日 %H:%M:%S"`

echo 開始:$Begin 結束:$Last $GZDumpFile succ >> $LogFile

cd $BakDir/daily

rm -f *

 

10.賦予databak.sh 執行權限:

chmod a+x /home/mysql/databak.sh

11.開啟定時任務

vi /etc/crontab

12.添加以下內容:

#每個星期日凌晨3:00執行完全備份腳本

0 3 * * 0 /home/mysql/databak.sh >/dev/null 2>&1

#周一到周六凌晨3:00做增量備份

0 3 * * 1-6 /home/mysql/binlogbak.sh >/dev/null 2>&1

 

(注:

crontab文件概要:

用戶所建立的crontab文件中,每一行都代表一項任務,每行的每個字段代表一項設置,它的格式共分為六個字段,前五段是時間設定段,第六段是要執行的命令段,格式如下:

minute hour day month week command

 分  時  日  月   周   命令

其中:

minute: 表示分鍾,可以是從0到59之間的任何整數。(每分鍾可用*或者*/1表示)

hour:表示小時,可以是從0到23之間的任何整數。(0表示0點)

day:表示日期,可以是從1到31之間的任何整數。

month:表示月份,可以是從1到12之間的任何整數。

week:表示星期幾,可以是從0到7之間的任何整數,這里的0或7代表星期日。

command:要執行的命令,可以是系統命令,也可以是自己編寫的腳本文件。

在以上各個字段中,還可以使用以下特殊字符:

星號(*):代表所有可能的值,例如month字段如果是星號,則表示在滿足其它字段的制約條件后每月都執行該命令操作。

逗號(,):可以用逗號隔開的值指定一個列表范圍,例如,“1,2,5,7,8,9”

中杠(-):可以用整數之間的中杠表示一個整數范圍,例如“2-6”表示“2,3,4,5,6”

正斜線(/):可以用正斜線指定時間的間隔頻率,例如“0-23/2”表示每兩小時執行一次。同時正斜線可以和星號一起使用,例如*/10,如果用在minute字段,表示每十分鍾執行一次

 

 

 

crontab 定時執行的日志記錄在/var/spool/mail/root中,可用以下代碼查看日志記錄

vi /var/spool/mail/root

13.使上述定時任務生效

crontab /etc/crontab

14.查看定時任務

crontab -l

到此就完成了Mysql數據庫的定時自動全備份和增量備份的功能了。下面記錄一下運行的過程。

先說這兩個腳本語言運行之前什么樣,運行以后產生了什么結果(以下的Windows系統的mysql文件夾截圖都是為了方便說明,我從linux上拷下來的)。

還沒有運行之前,只是完成對上面的配置文件的修改以及創建目錄,就只有logbin.000001。logbin.00000*的文件是在前面設置/etc/my.cnf時寫了路徑指到這里的,每當mysql有更新操作(刪除、插入、修改)時,mysql都會自動把這些操作記錄下來存到這個logbin.00000*文件里。

 

 

 

然后手動運行一遍增量備份。

 

 

Mysql文件夾下就變成這樣:

 

 

 

 

 

 

 

 

 

 

 

這時就產生了一個logbin.000002文件,logindex.index里面也添加了一條記錄,binlog.log里面也有了記錄,daily文件夾下把logbin.000001做了備份。

然后此時對數據庫隨便進行一個插入操作,你會發現mysql文件夾下的000001文件不再刷新修改日期了,而000002文件會同步刷新,這說明mysql會把數據庫“增刪改”操作記錄到最新的一個00000*文件里,之前的就留着不動了。所以腳本程序做了一個將000001復制一份存到了daily里面的操作,就是000001,也就是第一天的增量備份。

然后再運行一遍增量備份

 

 

 

 

 

 

 

 

 

 

 

會出現一個000003文件,此時再對數據庫進行修改,000001、000002都不會更改了。logindex里也多了一個000003的記錄,binlog.log記錄了000001已存在,000002復制,000003跳過。

daily里已經將000002也保存了一份,這是第二天的增量備份。

然后手動執行完全備份

 

 

mysql文件夾下變成了這樣:

 

 

 

 

 

 

 

 

 

 

 

 

 

可以發現mysql和daily文件夾下000001、000002、000003都刪掉了。mysql文件下留下了一個000004。index里只記錄了000004,binlog.log沒有變化,出現了一個bak.log記錄了這次完全備份,還有一個jar包。

這就是整個過程的變化,下面就容易理解shell腳本語言執行的具體細節了,先把原代碼貼上:

 

 

關於shell一些常見簡單命令可以參考這里:

https://www.cnblogs.com/handongyu/p/7152028.html

第4行:符號#!用來告訴系統它后面的參數是用來執行該文件的程序。在這個例子中我們使用/bin/bash來執行程序。 Linux中有好多種不同的shell,但是通常我們使用bash (bourne again shell) 進行shell編程,因為bash是免費的並且很容易使用。

第6~9行:都是賦值語句,把創建的目錄結構賦給定義的這些變量,后面可以通過$來取這些變量的值。

第10行:這一句就是產生新的00000*文件的句子,在mysql中flush logs操作會生成一個新的binlog文件。參考https://blog.csdn.net/imzoer/article/details/8277797

 

 

第12行:這一行的目的就是統計logindex.index這個文件夾里有多少個文件。

第15~17行:for循環,cat $binfile就是logindex.index里的全部文件,這里就是要把logindex.index里的每一個文件的名字賦給base;

第20~34行:判斷if(NextNum == Counter);就是如果NextNum 等於了logindex.index里的文件數量,那就輸出:logbin.00000* skip 到binlog.log里。不相等就查看當前base代表的文件在/home/mysql/backup/daily里面是否已有備份,如果有就寫logbin.00000* exist!到binlog.log里,如果還沒有那就復制一份到/home/mysql/backup/daily里。

第35行:寫日期時間 Bakup succ! 到binlog.log里。

然后是完全備份:

 

 

第7行:當前的年月日。

第8行:開始備份之前的年月日、時、分、秒。

第9~11行:切換到/home/mysql/backup目錄下,將日期.sql這個sql文件賦給DumpFile,將日期.sql.tgz這個壓縮文件賦給GZDumpFile。

第12行:將所有數據庫備份到DumpFile指向的sql文件。重新生成一個logbin.00000*。並且將之前的刪除,單事務。

 

 

第13~14行:將DumpFile指向的文件壓縮到GZDumpFile指向的壓縮文件中,並且刪掉DumpFile指向的文件。

第16~22行:就是壓縮文件大於等於5個時就刪掉最早的一個。

第24行:結束備份之后的年月日、時、分、秒。

第25行:將開始時間,結束時間,壓縮的文件名備份成功記錄到bak.log中。

第26~27行:刪掉daily里面所有的文件。

到此處備份就全部結束了。相信結合代碼、加運行的截圖過程以及最開始對增量備份、全量備份的描述不難理解了。

 

備份恢復:

首先是完整備份以后有test這么一個數據庫,tb_emp表數據如下:

 

 

然后,插入第10條和11條:

 

 

數據有“增刪改”操作,增量備份會將操作記錄在在logbin.00000*中,然后刪掉test數據庫。

此時先查看logbin.00000*中的記錄,登錄數據庫用如下命令查看:

 

 

可以看到介於802~896 POS點區間的操作就是刪除掉test數據庫的操作,前面兩條是插入記錄,我們要恢復到最后一條插入數據的狀態,有多種方法恢復,可以按時間,按日志區間(POS點)恢復,具體的可以參考這篇文章,講得很詳細https://blog.csdn.net/zxssoft/article/details/80115018

因為備份恢復的時候,mysql也會將恢復時的記錄寫入logbin.000000*,不方便找我們需要的日志,所以先把這個日志記錄截屏保存下來,方便后面使用,或者直接在這個時候把mysql的日志記錄功能關閉,不記錄恢復時的日志

vi /etc/my.cnf

將后面的添加的部分注釋掉

#log-bin = "/home/mysql/logbin.log"

#binlog-format = ROW

#log-bin-index = "/home/mysql/logindex"

#binlog_cache_size=32m

#max_binlog_cache_size=512m

#max_binlog_size=512m

#server-id=1

 

 

再保存退出,重啟mysql服務:

service mysqld restart

此時就可以開始恢復了。先恢復最近一次的完整備份,切換到mysql目錄下,解壓完整備份:

cd /home/mysql/backup/

tar zxvf /home/mysql/backup/20180726.sql.tgz -C /home/mysql/backup

解壓得到一個sql文件,輸入以下命令然后要求輸入數據庫密碼:

mysql -uroot -p -v < 20180726.sql

刷新數據庫會發現test數據庫又回來了,但是還沒有后面插入的那兩條數據。接下來就要恢復增量備份,結合上面的日志記錄,要恢復到最后一條記錄插入並且提交的時候,可以用737這個POS點作為結束點,命令如下:

/usr/bin/mysqlbinlog --stop-position=737 --database=test /home/mysql/logbin.000013 | /usr/bin/mysql -uroot -pmysql123 -v test

刷新數據庫就會發現,數據已經和刪除之前一模一樣了。注意:這里如果使用的是706的話,第11條數據是沒有恢復的。應該是提交以后才算是確認插入這條數據。

其實這個增量備份的恢復。就是把這些“增刪改”操作重新運行一遍,所以如果有多天的增量備份。則需要在恢復最后一次完整的備份之后,按時間順序,依次恢復每一個增量備份的操作,才能得到刪除前的完整數據庫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM