如何安全地删除MySQL的binlog

1. 概述

很多MySQL管理员在配置主备复制时,对binlog的删除策略一般是使用expire_logs_days参数,对这个参数设置一个较大的值,比如30天,但实际上,这不是个很好的解决方法。

  • 如果主库日志量生成很大,那不到30天就可能把binlog所处的文件系统撑满。
  • 如果备库异常停了很长时间未发现,也可能导致主库删了备库需要的日志。

针对这两个问题,自已写了个脚本,考虑备库对主库的binlog读取情况后,再进行删除主库的binlog。

该脚本需要部署在主库机器上,使用该脚本,需要配置主库到备库的ssh信任。配置ssh信任比较简单,方法如下:
在主库上的MySQL用户执行

$ mkdir ~/.ssh
$ ssh-keygen -t rsa
$ ssh-copy-id -i ~/.ssh/id_rsa.pub [slave_ip]

验证:

$ ssh mysql@[slave_ip] date

2. 代码

代码比较简单,就不做过多解释,主要是在主库上通过ssh到备库检查slave状态,计算备库上读取主库binlog位置,再在主库上删除已经被备库读取的binlog,未读取的不删除

#!/bin/bash
####################################################
##
## Clear MySQL Master BinLog
##    Not depend expire_logs_days
##    config ssh trust for master to slave first
##
## Usage:
##
## PeiZhengfeng 2016.12.21
## hthorizion
##
## History :
##
## Platform for Linux
##
####################################################

SAVE_BINLOG_NUM=1
MASTER=192.168.1.10
MASTER_ROOTPWD=123456
MASTER_MYSQL_HOME=/usr/local/mysql
SLAVE[0]=192.168.1.11
SLAVE_ROOTPWD[0]=123456
SLAVE_MYSQL_HOME[0]=/usr/local/mysql
#SLAVE[1]=192.168.1.12
#SLAVE_ROOTPWD[1]=123456
#SLAVE_MYSQL_HOME[1]=/usr/local/mysql

PWD=$(cd "$(dirname "$0")"; pwd)
cd $PWD
mkdir -p tmp

#-----------------------------------
# C H E C K      M A S T E R
#-----------------------------------

mstool="$MASTER_MYSQL_HOME/bin/mysql -uroot -p$MASTER_ROOTPWD"
MASTERFILE="tmp/CheckMaster.$MASTER"

check_master_status()
{
  timeout 30 $mstool -e "show master status\G" 1>$MASTERFILE 2>&1
}

check_master_status

MASTER_FILEPR=`cat $MASTERFILE | grep File | awk '{print $2}' | awk -F'.' '{print $1}'`
MASTER_FILENUM=`cat $MASTERFILE | grep File | awk '{print $2}' | awk -F'.' '{print $2}' | sed 's/^0*//g'`

# Check Master is Life
if [ ! -n "$MASTER_FILEPR" ]; then
  echo "Master is down or log_bin not config"
  exit 2
fi

#-----------------------------------
# C H E C K      S L A V E
#-----------------------------------

check_slave_status()
{
  timeout 30 ssh mysql@$SLAVE "$sltool -e 'show slave status\G'" 1>$SLAVEFILE 2>&1
}

logseq=0

SLAVE_NUM=${#SLAVE[@]}
for((i=0;i<SLAVE_NUM;++i))
do
  SLAVE=${SLAVE[$i]}
  sltool="${SLAVE_MYSQL_HOME[$i]}/bin/mysql -uroot -p${SLAVE_ROOTPWD[$i]}"
  SLAVEFILE="tmp/CheckSlave.${SLAVE[$i]}"

  check_slave_status

  Master_Log_File=`cat $SLAVEFILE | grep "  *Master_Log_File:" | awk '{print $2}'`
  Master_Log_FilePr=`echo $Master_Log_File | awk -F'.' '{print $1}'`
  Master_Log_FileNum=`echo $Master_Log_File | awk -F'.' '{print $2}' | sed 's/^0*//g'`
  Read_Master_Log_Pos=`cat $SLAVEFILE | grep Read_Master_Log_Pos | awk '{print $2}'`

  if [ ! -n "$Master_Log_File" ]; then
    echo "Slave($SLAVE) is down..."
    exit 2
  elif [ "$logseq" = 0 ] || [ "$Master_Log_FileNum" -lt "$logseq" ]; then
    logseq=$Master_Log_FileNum
  fi

done

logseq=` expr $logseq - $SAVE_BINLOG_NUM `

if [ "$MASTER_FILENUM" -lt "$logseq" ]; then
  echo "[ERROR] Master LogNum < Slave Min LogNum"  
  exit 2
fi

#------------------------------------------
# C L E A R    M A S T E R    B I N L O G
#------------------------------------------

PURGE_MASTER_BINFILE="$MASTER_FILEPR.`printf "%06d\n" $logseq`"
echo $PURGE_MASTER_BINFILE

$mstool -e "PURGE BINARY LOGS TO '$PURGE_MASTER_BINFILE';" 1>purge_log.txt 2>&1

3. TODO

可以使用show binary logs显示当前库上所有的binlog,在清理之前可以备份binlog到其它地方,以备其它用途。

关于紫砂壶

感悟技术人生
此条目发表在复制分类目录,贴了标签。将固定链接加入收藏夹。