zoukankan      html  css  js  c++  java
  • 转载:MySQL:亲测备份策略实例(线上真实备份案例)

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

    说明:

    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("
    ")[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("
    ")[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("
    ")[0]
        CurRelay_MTime = os.path.getmtime(CurRelay)  # 获取当前正在使用的文件的最后修改时间
    
        # 循环所有的中继日志文件,通过和中继日志的最后修改时间进行对比,得到需要备份的中继日志
        Need_ZIP_FName = []  # 定义需要压缩和删除的文件名
        for FileName in Relog_List:
            '''
            将修改时间小于[当前正在使用的中继日志]文件的文件,加入到 列表 [Need_ZIP_FName] 中,用于备份/删除.
            '''
            FName =  FileName.split("
    ")[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("####----------        分界线        ----------####
    ")
                file.writelines("###start    >>>全备    datetime : %s
    "%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")))
                file.writelines("###     今天是周%s
    "%(IF_Week))
                file.writelines("###     stop slave
    ")
                os.system("%s %s -e "stop slave""%(Mysql_Bin,DB))
                file.writelines("###     status slave
    ")
                Show_Slave = os.popen("%s %s -e "show slave statusG""%(Mysql_Bin,DB)).readlines()
                file.writelines(Show_Slave)
                file.writelines("###     backup
    ")
                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
    "%(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
    ")
                Show_Slave = os.popen("%s %s -e "show slave statusG"" % (Mysql_Bin, DB)).readlines()
                file.writelines(Show_Slave)
                file.writelines("###done    >>>全备完成
    ")
                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("
    
    
    
    
    ")
            Del_Old()
        else:
            with open(Logs_File,'a+') as file:
                file.writelines("####----------        分界线        ----------####
    ")
                file.writelines("###start    >>>增量备份    datetime : %s
    "%(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")))
                file.writelines("###     今天是周%s
    "%(IF_Week))
                file.writelines("###     stop slave
    ")
                os.system("%s %s -e "stop slave""%(Mysql_Bin,DB))
                file.writelines("###     status slave
    ")
                Show_Slave = os.popen("%s %s -e "show slave statusG""%(Mysql_Bin,DB)).readlines()
                file.writelines(Show_Slave)
                file.writelines("###     backup
    ")
                ZIP_And_Del_Existed()
                file.writelines("###    backup done && start slave | datetime : %s
    "%(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
    ")
                Show_Slave = os.popen("%s %s -e "show slave statusG"" % (Mysql_Bin, DB)).readlines()
                file.writelines(Show_Slave)
                file.writelines("###done    >>>增量备份完成
    ")
                file.writelines("
    
    
    
    
    ")
            Del_Old()
    else:
        with open(Logs_File, 'a+') as file:
            file.writelines("####----------        分界线        ----------####
    ")
            file.writelines("###start    >>>增量备份    datetime : %s
    " % (datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")))
            file.writelines("###     今天是周%s
    " % (IF_Week))
            file.writelines("###     stop slave
    ")
            os.system("%s %s -e "stop slave"" % (Mysql_Bin, DB))
            file.writelines("###     status slave
    ")
            Show_Slave = os.popen("%s %s -e "show slave statusG"" % (Mysql_Bin, DB)).readlines()
            file.writelines(Show_Slave)
            file.writelines("###     backup
    ")
            ZIP_And_Del_Existed()
            file.writelines("###    backup done && start slave | datetime : %s
    " % (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
    ")
            Show_Slave = os.popen("%s %s -e "show slave statusG"" % (Mysql_Bin, DB)).readlines()
            file.writelines(Show_Slave)
            file.writelines("###done    >>>增量备份完成
    ")
            file.writelines("
    
    
    
    
    ")
        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 "
    
    
    
    
    " >> ${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
  • 相关阅读:
    设计模式-简单工厂模式、工厂模式、抽象工厂模式-(创建型模式)
    设计模式-类间关系
    设计模式-六大基本原则
    设计模式-总起
    [转载]常见的移动端H5页面开发遇到的坑和解决办法
    [转载]Angular4 组件通讯方法大全
    【angular5项目积累总结】文件下载
    【转载】Vue 2.x 实战之后台管理系统开发(二)
    [转载]Vue 2.x 实战之后台管理系统开发(一)
    WordPress翻译中 __()、_e()、_x、_ex 和 _n 的用法及区别
  • 原文地址:https://www.cnblogs.com/EikiXu/p/10726363.html
Copyright © 2011-2022 走看看