MySQL:亲测备份策略实例(线上真实备份案例)
【摘要】 是否为线上库的备份而烦恼过,这里提供一个完整的备份从属数据库的备份方案,亲测可用
小生博客: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 backup0 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.confuid = 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.passremoteuser:password
2、 同步脚本
root@localhost:~# cat /scripts/backup.sh#!/bin/bashSSH=$(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/general01 23 * * * root /bin/sh /scripts/backup.sh
-------------------------------
本文转自小生博客51CTO博客
如需转载,请联系作者授权
原文链接:https://blog.51cto.com/xsboke/2356678
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)