一、安装xtrabackup工具

安装方法见:xtrabackup安装

# wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.1/binary/tarball/percona-xtrabackup-2.4.1-Linux-x86_64.tar.gz

# mv percona-xtrabackup-2.4.1-Linux-x86_64.tar.gz* percona-xtrabackup-2.4.1-Linux-x86_64.tar.gz

# tar -zxvf percona-xtrabackup-2.4.1-Linux-x86_64.tar.gz

# mv percona-xtrabackup-2.4.1-Linux-x86_64 /usr/bin

# cd /usr/bin

# mv percona-xtrabackup-2.4.1-Linux-x86_64 xtrabackup

# echo 'export PATH=$PATH:/usr/bin/xtrabackup/bin' >> /etc/profile

# source /etc/profile

# yum -y install libaio


二、配置备份脚本

1.拷贝mysql_backup_shell到mysql业务服务器目录,比如:/data/backup_shell/mysql_backup_shell

2.进入拷贝后mysql_backup_shell所在目录, 然后执行chmod 777 mysql_backup.sh

3.修改backup.conf

需要修改的项:

mysql_conf_file=/usr/local/meb/my.cnf.3309  #mysql cnf文件路径

user=root  #mysql连接用户名

port=3309  #端口号

host=127.0.0.1 #mysql ip

password= #密码,可以为空

socket=/data0/mysql/3309/mysql.sock #mysql socket

backup_dir=/root/workspace/mysqlbackup/  #全备份后文件存放目录

full_backup_month_day=29  #全备份在每月哪天进行, 29代表本月29号进行全备份

is_tar_full=1 #取值为0或1,为1表示会压缩全备份目录,并且删除全备份目录,而保留全备份目录压缩后tar.gz文件。 取0不压缩,保留全备份目录。

PS: 除上面这些项,其他项一般不需要修改。


4.利用crontab配置定时任务(每天23:59开始备份)

#crontab -e
59 23 * * * YourPath/mysql_backup_shell/mysql_backup.sh > /tmp/monitor.log 2>&1

YourPath指解压缩后目录存放的路径,比如/data/backup_shell


5.命令行运行脚本

第一种运行方式

> ./mysql_backup.sh

根据backup.conf文件里面full_backup_month_day值, 和当天日期比较, 如果相同执行全备份;如果不相同执行增量备份。


第二种运行方式

mysql_backup.sh提供一个参数-t,方便测试和出错后手动启动备份使用。

  ./mysql_backup.sh -t full #会进行全备份

  ./mysql_backup.sh -t inc  #会进行增量份



说明:

1.每个月执行一次全备份,具体哪天由backup.conf文件里面full_backup_month_day项控制。

2.每天23:59执行增量备份

3.每次全备份前会删除上个月全备份和增量备份的文件, 换句话:只会持续保持一个月的数据内容。

4.增量备份基于上次的增量备份进行, 除全备以后第一次增量备份, 其余都基于上次增量备份目录进行。


三、脚本

# xtrabackup backup shell
# Date   : 2016-03-23
source /etc/profile

work_dir=`dirname $0`
cd $work_dir

#获取配置文件中配置项的值
conf_file=$work_dir/backup.conf

user=`sed '/^user=/!d;s/.*=//' $conf_file`
password=`sed '/^password=/!d;s/.*=//' $conf_file`
mysql_conf_file=`sed '/^mysql_conf_file=/!d;s/.*=//' $conf_file`
port=`sed '/^port=/!d;s/.*=//' $conf_file`
# mysql host
host=`sed '/^host=/!d;s/.*=//' $conf_file`
# mysql socket
mysql_socket=`sed '/^socket=/!d;s/.*=//' $conf_file`
backup_dir=`sed '/^backup_dir=/!d;s/.*=//' $conf_file`

full_backup_month_day=`sed '/^full_backup_month_day=/!d;s/.*=//' $conf_file`
full_backup_prefix=`sed '/^full_backup_prefix=/!d;s/.*=//' $conf_file`
increment_prefix=`sed '/^increment_prefix=/!d;s/.*=//' $conf_file`
mysql_conf_file=`sed '/^mysql_conf_file=/!d;s/.*=//' $conf_file`
error_log_name=`sed '/^error_log=/!d;s/.*=//' $conf_file`
index_file_name=`sed '/^index_file=/!d;s/.*=//' $conf_file`
is_tar_full=`sed '/^is_tar_full=/!d;s/.*=//' $conf_file`


#获取当前时间
backup_date=`date +%F`
backup_time=`date +%H-%M-%S`
backup_month_day=`date +%d`

#获取日志和错误文件所在目录
log_dir=$work_dir/log
var_dir=$work_dir/var

#日志和错误文件路径
error_log=$log_dir/$error_log_name
index_file=$var_dir/$index_file_name

mkdir -p $backup_dir
mkdir -p $log_dir
mkdir -p $var_dir

#调用xtrabckup进行全量备份
function full_backup() {
  backup_folder=${full_backup_prefix}_${backup_date}_${backup_time}

  echo "backup_folder: $backup_folder"
  mkdir -p $backup_dir/$backup_folder

  echo "xtrabackup --defaults-file=$mysql_conf_file --user=$user --password=$password --port=$port --socket=$mysql_socket --backup --no-lock --target-dir=$backup_dir/$backup_folder > $log_dir/${backup_folder}.log"
  xtrabackup \
  --defaults-file=$mysql_conf_file \
   --user=$user \
   --password=$password \
   --port=$port \
    --socket=$mysql_socket \
    --backup \
    --no-lock \
    --target-dir=$backup_dir/$backup_folder > $log_dir/${backup_folder}.log 2>&1
  return $?
}

#调用xtrabckup进行增量备份
function increment_backup() {
  backup_folder=${increment_prefix}_${backup_date}_${backup_time}
  echo "index_file : $index_file"
  incr_base_folder=`sed -n '$p' $index_file | \
                   awk -F '[, {}]*' '{print $3}' | \
                   awk -F ':' '{print $2}'`
  echo "backup_folder: $backup_folder"
  echo "incr_base_folder: $incr_base_folder"

  mkdir -p $backup_dir/$backup_folder
  echo "xtrabackup --defaults-file=$mysql_conf_file --user=$user --password=$password --port=$port --socket=$mysql_socket --backup --no-lock --target-dir=$backup_dir/$backup_folder --incremental-basedir=$backup_dir/$incr_base_folder > $log_dir/${backup_folder}.log"

  xtrabackup \
    --defaults-file=$mysql_conf_file \
    --user=$user \
    --password=$password \
    --port=$port \
    --socket=$mysql_socket \
    --backup \
    --no-lock \
    --target-dir=$backup_dir/$backup_folder \
    --incremental-basedir=$backup_dir/$incr_base_folder > $log_dir/${backup_folder}.log 2>&1
  return $?
}
#根据索引文件记录的恢复记录, 删除备份目录
function delete_before_backup() {
  if [ ! -n "`cat $index_file`" ]; then
    return
  fi

  cat $index_file | awk -F '[, {}]*' '{print $3}' | \
    awk -v backup_dir=$backup_dir -F ':' '{if($2!=""){printf("rm -rf %s/%s\n", backup_dir, $2)}}' | \
    /bin/bash
  
  cat $index_file | awk -F '[, {}]*' '{print $3}' | \
    awk -v log_dir=$log_dir -F ':' '{if($2!=""){printf("rm -rf %s/%s.log\n", log_dir, $2)}}' | \
    /bin/bash
}

#备份索引文件 
function backup_index_file() {
  cp $index_file ${index_file}_$(date -d "1 day ago" +%F)
}

function send_index_file_to_remote() {
  echo 'send index file ok'
}

#写入索引日志
function append_index_to_file() {
  echo "{week_day:$backup_month_day, \
         dir:${1}_${backup_date}_${backup_time}, \
         type:${1}, \
         date:${backup_date}}" >> $index_file
}

#写入解压日志
function append_tar_index_to_file() {
  echo "{week_day:$backup_month_day, \
         dir:${1}_${backup_date}_${backup_time}.tar.gz, \
         type:${1}, \
         date:${backup_date}}" >> $index_file
}

#记录错误日志
function logging_backup_err() {
  echo "{week_day:$backup_month_day, \
         dir:${1}_${backup_date}_${backup_time}, \
         type:${1}, \
         date:${backup_date}}" >> $error_log
}

#清除索引文件
function purge_index_from_file() {
  > $index_file
}

#清除错误日志
function purge_err_log() {
  > $error_log
}

#压缩全备份目录
function tar_backup_file() {
  tar_file=${1}_${backup_date}_${backup_time}

  tar -C $backup_dir -zcvf $backup_dir/${tar_file}.tar.gz ${tar_file} 
  echo "tar $1 ok"
}

function send_backup_to_remote() {
    
  echo "send $1 remote ok"
}
 #获取恢复的类型,返回类型:0:full, 1:inc
# 0:full, 1:incr
function get_backup_type() {
  full_backup_month_day=`sed '/^full_backup_month_day=/!d;s/.*=//' $conf_file`
  backup_type=0
  if [ "${full_backup_month_day}_x" == "${backup_month_day}_x" ]; then
    backup_type=0
  else
    backup_type=1
  fi
  if [ ! -n "`cat $index_file`" ]; then
    backup_type=0
  fi
  return $backup_type
}

#检测配置文件各项数据合法性
function test_conf_file() {
  if [ ! -n "$user" ]; then echo 'fail: configure file user not set'; exit 2; fi
  #if [ ! -n "$password" ]; then echo 'fail: configure file password not set'; exit 2; fi
  #if [ ! -n "$host" ]; then echo 'fail: configure file host not set'; exit 2; fi
  if [ ! -n "$mysql_socket" ]; then echo 'fail: configure file mysql_socket not set'; exit 2; fi
  #if [ ! -n "$port" ]; then echo 'fail: configure file port not set'; exit 2; fi
  if [ ! -n "$backup_dir" ]; then echo 'fail: configure file backup_dir not set'; exit 2; fi
  if [ ! -n "$full_backup_month_day" ]; then echo 'fail: configure file full_backup_month_day not set'; exit 2; fi
  if [ ! -n "$full_backup_prefix" ]; then echo 'fail: configure file full_backup_prefix not set'; exit 2; fi
  if [ ! -n "$increment_prefix" ]; then echo 'fail: configure file increment_prefix not set'; exit 2; fi
  if [ ! -n "$mysql_conf_file" ]; then echo 'fail: configure file mysql_conf_file not set'; exit 2; fi
  if [ ! -n "$error_log" ]; then echo 'fail: configure file error_log not set'; exit 2; fi
  if [ ! -n "$index_file" ]; then echo 'fail: configure file index_file not set'; exit 2; fi
  if [ ! -n "$is_tar_full" ]; then echo 'fail: configure file is_tar_full not set'; exit 2; fi
}

#运行主函数
function run() {
  test_conf_file
  backup_type=-1
  #解析命令行参数
  while getopts "t:" arg
  do
    case $arg in
        t)
            if [ "$OPTARG" = "$full_backup_prefix" ]; then
                backup_type=0
            elif [ "$OPTARG" = "$increment_prefix" ]; then
                backup_type=1
            fi
            ;;
        ?)
            echo "unkonw argument"
        exit 1
        ;;
        esac
  done
  if [ "$backup_type" -eq -1 ]; then
    get_backup_type
    backup_type=$?    
  fi
  echo "backup_type: $backup_type"

  case $backup_type in
    0)#全量备份
      echo '----------------------full backup start----------------'
      echo 'delete_before_backup start'
      delete_before_backup
      echo 'call xtrabackup to full backup start'
      full_backup 

      backup_ok=$?
      if [ 0 -eq "$backup_ok" ]; then

        if [ 1 -eq "$is_tar_full" ]; then
          tar_backup_file $full_backup_prefix
        fi

        #send_backup_to_remote $full_backup_prefix
        echo 'backup_index_file start'
        backup_index_file

        # send_index_file_to_remote
        echo 'purge_index_from_file start'
        purge_index_from_file
        
        echo 'append_index_to_file start'
        if [ 1 -eq "$is_tar_full" ]; then
          append_tar_index_to_file $full_backup_prefix
        fi

        append_index_to_file $full_backup_prefix

        echo 'call xtrabackup to increment backup start'
        increment_backup
        backup_ok=$?
        if [ 0 -eq "$backup_ok" ]; then
          # tar_backup_file $increment_prefix
          # send_backup_to_remote $increment_prefix
          echo 'append_index_to_file start'
          append_index_to_file $increment_prefix
          rm -rf ${backup_dir}/${full_backup_prefix}_${backup_date}_${backup_time}
        else
          rm -rf ${backup_dir}/${increment_prefix}_${backup_date}_${backup_time}
          logging_backup_err $increment_prefix
        fi
      else
        rm -rf ${backup_dir}/${full_backup_prefix}_${backup_date}_${backup_time}
        logging_backup_err $full_backup_prefix
      fi
      ;;
    1)#增量备份
      echo '----------------------incr backup start----------------'
      
      echo 'call xtrabackup to increment backup start'
      increment_backup
      backup_ok=$?
      if [ 0 -eq "$backup_ok" ]; then
        # tar_backup_file $increment_prefix

        # send_backup_to_remote $increment_prefix
        echo 'append_index_to_file start'
        append_index_to_file $increment_prefix
      else
        rm -rf ${backup_dir}/${increment_prefix}_${backup_date}_${backup_time}

        logging_backup_err $increment_prefix
      fi
      ;;
  esac
}

run $@