MySQL:親測備份策略實例(線上真實備份案例)python
-------謝謝您的參考,若有疑問,歡迎交流
是否爲線上庫的備份而煩惱過,這裏提供一個完整的備份從屬數據庫的備份方案,親測可用mysql
說明:linux
備份從庫,按周計,每週進行一次全備
每週一的早上六點進行全備,其餘時間備份中繼日誌
在從庫上啓用rsync服務,用於異地備份
在本地服務器使用rsync命令定時同步數據庫的備份
此備份可用於爲Master添加新的Slave,也能夠用於還原Master
1、服務器端配置sql
一、 Python編寫的備份腳本數據庫
root@DBSlave:~# cat /scripts/mysql_slave_backup.pybash
#!/usr/bin/env python
#-- coding:utf-8 --
import os
import datetime,time服務器
'''app
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_Datessh
if os.path.isdir(Backup_Dir) is False:
os.makedirs(Backup_Dir)ide
#mysqldump選項
DB = '-uroot -p123456' # 指定登陸帳號和密碼
ARG = '--dump-slave=2 --skip-tz-utc --routines --triggers --quick --default-character-set=utf8 --single-transaction' # 指定備份參數
DB_NAME = "dbname" # 數據庫名稱
Back_DBNAME = DBNAME + '' + 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()
二、計劃任務
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
三、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
auth users = remoteuser
secrets file = /etc/rsyncd_users.db
root@DBSlave:~# cat /etc/rsyncd_users.db
remoteuser:password
2、 本地備份主機配置
一、建立rsync密碼文件
root@localhost:~# cat /etc/server.pass
remoteuser:password
二、 同步腳本
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
三、計劃任務
root@localhost:~# cat /etc/cron.d/general01 23 * root /bin/sh /scripts/backup.sh