是否为线上库的备份而烦恼过,这里提供一个完整的备份从属数据库的备份方案,亲测可用

说明:

  1. 备份从库,按周计,每周进行一次全备
  2. 每周一的早上六点进行全备,其他时间备份中继日志
  3. 在从库上启用rsync服务,用于异地备份
  4. 在本地服务器使用rsync命令定时同步数据库的备份
  5. 此备份可用于为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
参考来源:
https://blog.51cto.com/xsboke/2356678

转载:MySQL:亲测备份策略实例(线上真实备份案例)的更多相关文章

  1. MySQL 数据库备份策略:全备与增量备份

    一.备份策略1.周日全备份,周一至周六增量备份2.全备份目录/u03/backup/innobackup/full_backup3.增量备份目录/u03/backup/innobackup/incre ...

  2. 转载:APP的上线和推广——线上推广渠道

    本文版权归个人所有,如需转载请注明出处http://www.cnblogs.com/PengLee/p/4637080.html 目录 应用商店 互联网开放平台 软件下载中心 媒体社交平台 刷榜推广 ...

  3. 记一次log4j日志导致线上OOM问题案例

    最近一个服务突然出现 OutOfMemoryError,两台服务因为这个原因挂掉了,一直在full gc.还因为这个问题我们小组吃了一个线上故障.很是纳闷,一直运行的好好的,怎么突然就不行了呢... ...

  4. centos6.5安装mysql(转载,亲测可用)

    如果要在Linux上做j2ee开发,首先得搭建好j2ee的开发环境,包括了jdk.tomcat.eclipse的安装(这个在之前的一篇随笔中已经有详细讲解了Linux学习之CentOS(七)--Cen ...

  5. 【转】从phpMyAdmin批量导入Excel内容到MySQL(亲测非常简洁有效)

    今天做项目遇到需要用phpMyAdmin批量导入Excel内容到MySQL数据库.分析了我的踏坑经历并且总结一最便捷的一套导入数据的方法,非常实用简洁: 1.修改Excel表的数据,使得Excel中的 ...

  6. Linux yum安装MySQL5.7,及远程连接mysql(亲测有效!)

    一.安装配置MySQL的yum源 # 安装MySQL的yum源,下面是RHEL6系列的下载地址 rpm -Uvh http://dev.mysql.com/get/mysql-community-re ...

  7. 在 Windows Server 上搭建 *** 服务端(转载加亲测)

    转载自:https://diveng.io/build-shadowsocks-server-on-windows-server.html 下面的教程建议大家使用第一种方法安装,说是比较简单.我则使用 ...

  8. 从phpMyAdmin批量导入Excel内容到MySQL(亲测非常简洁有效)

    今天做项目遇到需要用phpMyAdmin批量导入Excel内容到MySQL数据库.分析了我的踏坑经历并且总结一最便捷的一套导入数据的方法,非常实用简洁: 1.修改Excel表的数据,使得Excel中的 ...

  9. github 托管代码两分钟教程【转载,亲测可行】

    http://blog.csdn.net/duxinfeng2010/article/details/8654690 出自以上地址 本篇文章介绍的是如何将工程代码托管到上面:如果你还没注册GitHub ...

随机推荐

  1. yii2 rules 验证规则

    yii2  框架定义的约束 public $builtInValidators = [ 'boolean' => 'yii\validators\BooleanValidator', 'capt ...

  2. 前端框架Angular、react、vue在github上的数据统计-2018-05

    2018年5月31日09:15:45 突然想看看几个前端框架的数量,然后就截图了如下数据: 分析: react关注.收藏.Fork都高vue一些, 但相差不大 angular比较奇葩,收藏只有二者一半 ...

  3. Python3.7和数据库MySQL 8.0.12 数据库数据驱动mysql-connector安装(四)

    安装mysql-connector驱动 在系统CMD输入命令: pip install mysql-connector 示例: 创建数据库 # 导入驱动 import mysql.connector ...

  4. Cartographer安装

    安装过程: 官方安装教程: https://google-cartographer-ros.readthedocs.io/en/latest/index.html # Install wstool a ...

  5. chrome中安装.crx后缀的离线插件

    在前端开发中常常需要在chrome中安装一些插件辅助开发,比如最常用的Postman.React Developer Tools.Vue.js devtools等等...今天分享一下不需要“FQ”的插 ...

  6. vue 判断数组是否为空

    为空:array == undefined || array.length <= 0 (顺序不能调换) 不为空: array !==undefined && array.leng ...

  7. memcached命令行、Memcached数据导出和导入、php连接memcache、php的session存储到memcached

    1.memcached命令行 telnet 127.0.0.1 11211set key2 0 30 2abSTOREDget key2VALUE key2 0 2abEND  如: set key3 ...

  8. python的面试问题

    WHAT 1. 什么是Python? Python是一种编程语言,它有对象.模块.线程.异常处理和自动内存管理.可以加入与其他语言的对比.下面是回答这一问题的几个关键点: a. Python是一种解释 ...

  9. 批量镜像locator(比如表情模板)

    #外挂   镜像loc     前缀  lf  镜像给   rt   选中其中一个会镜像另一个 myPrefix='lf_'myMdf='rt_' myselectLoc=mc.ls(sl=1)for ...

  10. 例:三位老师对某次数学竞赛进行了预测,他们的预测如下:   甲:学生A得了第一名,学生B得第三名。   乙:学生C得了第一名,学生D得第四名。   丙:学生D得了第二名,学生A得第三名。 结果表明,他们都说对了一半,说错了一半,并且无并列名次,输出A、B、C和D各自的名次。

    public class demo { public static void main(String[] args) { int a,b,c,d;//代表四个学生 boolean x1,x2,x3;/ ...