轉載:MySQL:親測備份策略實例(線上真實備份案例)

是否爲線上庫的備份而煩惱過,這裏提供一個完整的備份從屬數據庫的備份方案,親測可用python

說明:mysql

  1. 備份從庫,按周計,每週進行一次全備
  2. 每週一的早上六點進行全備,其餘時間備份中繼日誌
  3. 在從庫上啓用rsync服務,用於異地備份
  4. 在本地服務器使用rsync命令定時同步數據庫的備份
  5. 此備份可用於爲Master添加新的Slave,也能夠用於還原Master

1、服務器端配置linux

一、 Python編寫的備份腳本sql

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()

二、計劃任務數據庫

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配置ruby

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

2、 本地備份主機配置bash

一、建立rsync密碼文件服務器

root@localhost:~# cat /etc/server.pass remoteuser:password

二、 同步腳本markdown

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

三、計劃任務app

參考來源:https://blog.51cto.com/xsboke/2356678root@localhost:~# cat /etc/cron.d/general 01 23 * * * root /bin/sh /scripts/backup.sh
相關文章
相關標籤/搜索