MySQL:親測備份策略實例(線上真實備份案例)
阿新 • • 發佈:2019-03-01
linux 設置 所有 防止 con action 計劃任務 密碼 新增 小生博客:http://xsboke.blog.51cto.com
如果有疑問,請點擊此處,然後發表評論交流,作者會及時回復(也可以直接在當前文章評論)。
-------謝謝您的參考,如有疑問,歡迎交流
是否為線上庫的備份而煩惱過,這裏提供一個完整的備份從屬數據庫的備份方案,親測可用
說明:
- 備份從庫,按周計,每周進行一次全備
- 每周一的早上六點進行全備,其他時間備份中繼日誌
- 在從庫上啟用rsync服務,用於異地備份
- 在本地服務器使用rsync命令定時同步數據庫的備份
- 此備份可用於為Master添加新的Slave,也可以用於還原Master
一、服務器端配置
1、 Python編寫的備份腳本
root@DBSlave:~# cat /scripts/mysql_slave_backup.py #!/usr/bin/env python #-*- coding:utf-8 -*- import os import datetime,time # 請在linux系統中安裝zip和unzip # 備份策略示例 ‘‘‘ 1. 每周進行一次全備,其他都是備份中繼日誌 2. 每周一淩晨6:00數據庫全備份 3. 周二至周日,每天中午12:00,下午18:00,早上6:00,備份中繼日誌 ‘‘‘ # 規劃備份目錄 # 備份目錄以周為單位進行創建 # "%W":一年中的第幾周,以周一為每星期第一天(00-53) Date_Time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") # %F:年月日 Week_Date = datetime.datetime.now().strftime("%Y-%W") # 年/當前是本年的第幾周 Dir = "/data/backup" Backup_Dir = Dir+ ‘/‘ + Week_Date # -- 創建備份目錄 ,每周生成一個目錄,因為每周做一次全備 if os.path.isdir(Backup_Dir) is False: os.makedirs(Backup_Dir) # 設置數據庫連接信息 #mysqldump選項 # --skip-tz-utc : 保持和表導出前的時區是一樣的 # --master-data=2 : 備份時寫入"change master to"語句並且註釋,等於1時,則不會註釋 # --dump-slave=2 : 備份slave的數據庫,為master新增slave時使用. # --quick : 一次從行中的服務器檢索表的行,作用是加快導出表 # --routines : 導出存儲過程 # --triggers : 導出觸發器 # --set-gtid-purged=OFF : 防止備份數據導入新的實例時與其GTID發生沖突,所以在備份數據時不添加GTID信息 # --single-transaction : 在從服務器轉儲數據之前發出BEGIN SQL語句,盡量保證數據的一致性,但是這個參數只適用於innodb這樣的存儲引擎 # --dump-slave=2 : 備份時寫入從庫連接主庫的change語句並且註釋,等於1時,則不會註釋 # 設置數據庫備份信息 DB = ‘-uroot -p123456‘ # 指定登錄賬號和密碼 ARG = ‘--dump-slave=2 --skip-tz-utc --routines --triggers --quick --default-character-set=utf8 --single-transaction‘ # 指定備份參數 DB_NAME = "dbname" # 數據庫名稱 Back_DBNAME = DB_NAME + ‘_‘ + Date_Time + ‘.sql‘ # 數據庫備份名稱 Logs_File = Backup_Dir + ‘/logs‘ # 指定備份時日誌輸出的文件 Mysql_Bin = "/usr/bin/mysql" # 指定[mysql]命令所在路徑 MysqlDump_Bin = "/usr/bin/mysqldump" # 指定[mysqldump]命令所在路徑 Relay_Log_Dir = "/data/logs/relay_log" #指定中繼日誌 Relay_Log_Info = "/data/logs/relay_log/relay-bin.info" # 用於獲取當前正在使用的中繼日誌 # 定義刪除舊備份 def Del_Old(): ‘‘‘刪除36天前的舊備份‘‘‘ OLD_Files = os.popen("find %s -type f -mtime +36"%(Dir)).readlines() if len(OLD_Files) > 0: for OLD_FIle in OLD_Files: FileName = OLD_FIle.split("\n")[0] os.system("rm -f %s"%(FileName)) # 刪除空目錄 All_Dir = os.popen("find %s -type d"%(Dir + ‘/*‘)).readlines() for Path_Dir in All_Dir: Path_Dir = Path_Dir.split("\n")[0] Terms = os.popen("ls %s | wc -l"%(Path_Dir)).read() if int(Terms) == 0: os.system("rm -rf %s"%(Path_Dir)) # 備份已經同步完成的中繼日誌文件 def ZIP_And_Del_Existed(): ‘‘‘ 壓縮已經同步完成的日誌文件並刪除, 為防止中繼日誌還沒有同步完成,就被刪除,這裏作一個判斷,只壓縮和刪除已經同步過的中繼日誌 ‘‘‘ # 獲取所有的中繼日誌 Relog_List = os.popen("ls %s | grep \"^relay-bin.*\" | grep -v \"relay-bin.in*\"" % (Relay_Log_Dir)).readlines() # 獲取當前正在使用的中繼日誌文件 CurRelay = os.popen("cat %s | head -n 1" % (Relay_Log_Info)).readline().split("\n")[0] CurRelay_MTime = os.path.getmtime(CurRelay) # 獲取當前正在使用的文件的最後修改時間 # 循環所有的中繼日誌文件,通過和中繼日誌的最後修改時間進行對比,得到需要備份的中繼日誌 Need_ZIP_FName = [] # 定義需要壓縮和刪除的文件名 for FileName in Relog_List: ‘‘‘ 將修改時間小於[當前正在使用的中繼日誌]文件的文件,加入到 列表 [Need_ZIP_FName] 中,用於備份/刪除. ‘‘‘ FName = FileName.split("\n")[0] FName_MTime = os.path.getmtime("%s/%s"%(Relay_Log_Dir,FName)) if FName_MTime < CurRelay_MTime: Need_ZIP_FName.append("%s/%s"%(Relay_Log_Dir,FName)) os.system("zip -j %s/Relay_log_%s.zip %s" % (Backup_Dir, Date_Time," ".join(Need_ZIP_FName))) # 獲取已經壓縮的中繼日誌文件,然後刪除 for Relay_Log in Need_ZIP_FName: os.system("rm -f %s"%(Relay_Log)) # 開始執行備份.(判斷,如果今天是星期一則進行全備,不是星期一則增量備份) IF_Week = datetime.datetime.now().strftime(‘%w‘) if int(IF_Week) == 1: # 匹配是否已經存在全備 Test = os.popen(‘ls %s | grep -E \"^%s.*([0-9]{2}-[0-9]{2}-[0-9]{2}).sql.zip\" | wc -l‘%(Backup_Dir,DB_NAME)).readline() if int(Test) == 0: # 如果星期一已經進行全備,則開始增量備份 with open(Logs_File,‘a+‘) as file: file.writelines("####---------- 分界線 ----------####\n") file.writelines("###start >>>全備 datetime : %s\n"%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) file.writelines("### 今天是周%s\n"%(IF_Week)) file.writelines("### stop slave\n") os.system("%s %s -e \"stop slave\""%(Mysql_Bin,DB)) file.writelines("### status slave\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\""%(Mysql_Bin,DB)).readlines() file.writelines(Show_Slave) file.writelines("### backup\n") os.system("%s %s %s %s > %s/%s"%(MysqlDump_Bin,DB,ARG,DB_NAME,Backup_Dir,Back_DBNAME)) file.writelines("### backup done && start slave | datetime : %s\n"%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) os.system("%s %s -e \"start slave;\""%(Mysql_Bin,DB)) time.sleep(5) file.writelines("### slave status\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\"" % (Mysql_Bin, DB)).readlines() file.writelines(Show_Slave) file.writelines("###done >>>全備完成\n") os.system("zip -j %s/%s.zip %s/%s"%(Backup_Dir,Back_DBNAME,Backup_Dir,Back_DBNAME)) os.system("rm %s/%s"%(Backup_Dir,Back_DBNAME)) file.writelines("\n\n\n\n\n") Del_Old() else: with open(Logs_File,‘a+‘) as file: file.writelines("####---------- 分界線 ----------####\n") file.writelines("###start >>>增量備份 datetime : %s\n"%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) file.writelines("### 今天是周%s\n"%(IF_Week)) file.writelines("### stop slave\n") os.system("%s %s -e \"stop slave\""%(Mysql_Bin,DB)) file.writelines("### status slave\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\""%(Mysql_Bin,DB)).readlines() file.writelines(Show_Slave) file.writelines("### backup\n") ZIP_And_Del_Existed() file.writelines("### backup done && start slave | datetime : %s\n"%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) os.system("%s %s -e \"start slave;\""%(Mysql_Bin,DB)) time.sleep(5) file.writelines("### slave status\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\"" % (Mysql_Bin, DB)).readlines() file.writelines(Show_Slave) file.writelines("###done >>>增量備份完成\n") file.writelines("\n\n\n\n\n") Del_Old() else: with open(Logs_File, ‘a+‘) as file: file.writelines("####---------- 分界線 ----------####\n") file.writelines("###start >>>增量備份 datetime : %s\n" % (datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) file.writelines("### 今天是周%s\n" % (IF_Week)) file.writelines("### stop slave\n") os.system("%s %s -e \"stop slave\"" % (Mysql_Bin, DB)) file.writelines("### status slave\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\"" % (Mysql_Bin, DB)).readlines() file.writelines(Show_Slave) file.writelines("### backup\n") ZIP_And_Del_Existed() file.writelines("### backup done && start slave | datetime : %s\n" % (datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) os.system("%s %s -e \"start slave;\"" % (Mysql_Bin, DB)) time.sleep(5) file.writelines("### slave status\n") Show_Slave = os.popen("%s %s -e \"show slave status\G\"" % (Mysql_Bin, DB)).readlines() file.writelines(Show_Slave) file.writelines("###done >>>增量備份完成\n") file.writelines("\n\n\n\n\n") Del_Old()
2、計劃任務
root@DBSlave:~# cat /etc/cron.d/general
#mysql backup
0 6 * * * root python /scripts/mysql_slave_backup.py
0 12 * * * root python /scripts/mysql_slave_backup.py
0 18 * * * root python /scripts/mysql_slave_backup.py
3、rsync配置
root@DBSlave:~# cat /etc/rsyncd.conf uid = 0 gid = 0 use chroot = yes address = "當前主機公網地址" port = 8638 log file = /var/log/rsync.log pid file = /var/run/rsync.pid hosts allow = "只允許某個IP連接" [databases] path = /data/backup/ comment = databases read only = yes dont compress = *.gz *.bz2 *.zip # 只允許remoteuser用戶 auth users = remoteuser secrets file = /etc/rsyncd_users.db
root@DBSlave:~# cat /etc/rsyncd_users.db
# 格式: 用戶名:密碼
remoteuser:password
二、 本地備份主機配置
1、創建rsync密碼文件
root@localhost:~# cat /etc/server.pass
remoteuser:password
2、 同步腳本
root@localhost:~# cat /scripts/backup.sh
#!/bin/bash
SSH=$(which ssh)
Logs_Dir="/Backup/logs.txt"
Rsync=$(which rsync)
Project="databases"
Dest="/Backup/"
IF_DEL_FILE=$(find ${Dest} -type f -mtime +36 -name "*" | wc -l)
DEL_FILE=$(find ${Dest} -type f -mtime +36 -name "*")
# 刪除舊備份
RMOLD(){
if [ "${IF_DEL_FILE}" -gt "0" ]
then
for filename in ${DEL_FILE}
do
rm -f ${filename}
done
rmdir ${Dest}* # 刪除空目錄
fi
}
# 執行同步命令
Backup(){
echo "### ---------- datetime : `date +%F-%H-%M-%S` ---------- ###" >> ${Logs_Dir}
echo "# start rsync" >> ${Logs_Dir}
${Rsync} -azH --password-file=/etc/server.pass --bwlimit=300 --port=8638 remoteuser@數據庫rsync監聽的IP地址::${Project} ${Dest} &>> ${Logs_Dir}
echo "### end rsync ---------- dateime : `date +%F-%H-%M-%S` ---------- ###" >> ${Logs_Dir}
echo -e "\n\n\n\n\n" >> ${Logs_Dir}
RMOLD
}
# 判斷如果當前正在同步則不再執行同步命令
IFProcess(){
ps -ef | grep "${Rsync} -azH --password-file=/etc/server.pass --bwlimit=300 --port=8638 remoteuser@數據庫rsync監聽的IP地址::${Project}" | grep -v "grep" &> /dev/null
if [[ "$?" == 0 ]]
then
exit 0
else
Backup
fi
}
IFProcess
3、計劃任務
root@localhost:~# cat /etc/cron.d/general
01 23 * * * root /bin/sh /scripts/backup.sh
MySQL:親測備份策略實例(線上真實備份案例)