考虑到数据的一致性,以及为恢复增量二进制日志或用作从库建立,备份时可改用锁全表的参数,锁表备份参数建议在从库上或闲时启用,本实例采取不锁表的策略,一般可在主库上运行。
实现的功能和需求:
- 自动备份所有数据库,包括后期新增的数据库(以免遗漏),可排除指定不备份的数据库,例如information_schema performance_schema;
- 同类脚本可并发执行,互不干扰,只需保证其脚本名称不一样即可;
- 结合mutt可发中文邮件通知,可发钉钉通知,为备份自动任务增加高度的可靠性,可满足审计要求;
- 敏感口令保存在单独的文件,增强安全性,可满足审计要求;
- 自动上传到异地,并采用curl规避NAT网络的诸多问题,(异地FTP只可写不可读和下载),可满足审计要求;
- 自动清理本地早期的备份,避免磁盘被占满,可满足审计要求;
- 脚本运行日志输出,结合系统日志logrotate服务的配置,可保留指定时间,比如半年,可满足审计要求;
- 可整合运维cmdb,助力流程化、自动化;
使用说明:
- 考虑到数据的一致性,以及为恢复增量二进制日志或用作从库建立,备份时可改用锁全表的参数,锁表备份参数建议在从库上或闲时启用;
- 本实例采取不锁表的策略,一般可在主库上运行。
脚本内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
#!/bin/bash ################################### # function 备份大量小数据库,按库创建备份。 # # 参考脚本创建: touch /root/sh/backup_mysql_mysqldump_multi.sh; chmod 700 /root/sh/backup_mysql_mysqldump_multi.sh # /etc/crontab: # 30 2 * * * root /root/sh/backup_mysql_mysqldump_multi.sh default >> /root/sh/log/backup_mysql_mysqldump_multi.log 2>&1 # # Change History: # date author note # 2013/01/25 mail#zhaoyanan.cn create # 2016/03/25 mail#zhaoyanan.cn 改进,增加多存储引擎和数据类型的备份 # 2018/08/16 mail#zhaoyanan.cn 为适应监管要求,基于20180814版backup.sh脚本,整合运维cmdb改编 # 2020/05/03 mail#zhaoyanan.cn 禁用ftp上传正常日志的输出,简化日志。新增mysqldump告警和邮件通知和钉钉通知,检查dump过程和ftp上传,满足审计和内控要求。 ################################### ###### 配置开始 ###### # 环境变量,应该放在最前面,不然有的命令用不了 export LANG=C #export LC_ALL=C export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin export datetime=$(date +%Y%m%d–%H%M) export HOME=/root ###### 配置开始 ###### # 脚本名称,临时文件或邮件中可能用到,避免同类脚本的变量的冲突,下面直接取脚本名 export project_name=`echo ${0##*/} | cut -d’.’ -f 1` # 本机IP,如果获取不准,可改为手动填写。 export local_primary_ip=`ip addr show dev eth0 | grep “inet” | awk –F ‘ ‘ ‘{print $2}’ | cut –d‘/’ –f 1 | head –n 1 2> /dev/null` #export local_primary_ip= export backup_dir=/opt/data_bak/mysql_bak/mysqldump # 工作目录 export work_dir=/root/sh # 临时文件目录 export tmp_dir=${work_dir}/tmp # /tmp danger # 日志目录 export log_dir=${work_dir}/log # 数据目录 export var_dir=${work_dir}/var # 告警标题头 export alert_sub=“某网数据库” # 钉钉告警 on or off。因为新ECS大多不允许连接邮件服25端口了(smtps仍然可以),如果不方便,所以改用钉钉告警 export alert_dingding_sw=off # 钉钉机器,请到钉钉群创建,并把信息源服务器IP加入其白名单 export alert_dingding_robot=“https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxxxxx” # 邮件配置,默认发件人 export mailfromadd=“sender@domain.com” # 邮件配置,默认收件人 export mailtoadd=“user01@domain.com” #export mailtoadd=”user02@domain.com” # 发邮件方式,装了mutt是的可以填mailto_advanced,(注意尽量配置msmtp通过smtps发件,因为25端口被管控很严)。后者支持中文,被判断为垃圾邮件的概率也较小 # 值为no,就是关闭发邮件 export mailto=mailto_advanced #export mailto=no # 目录创建 cd $work_dir test –d $tmp_dir || mkdir –p $tmp_dir test –d $log_dir || mkdir –p $log_dir test –d $var_dir || mkdir –p $var_dir test –d $backup_dir || mkdir –p $backup_dir ### cmdb查询开始 ### # 使用cmdb控制备份包名信息,有助于提升备份多个方面的自动化,其中包括统一管理保留时间,半自动化恢复校验,跨地域多重备份等,收获效率,减少遗漏,在众多任务堆积时,备份工作的优先级通常是最低的,所以备份自动化的意义深远。 # vpc网络要根据lanip字段去cmdb查询,其它项目需根据ip字段去查 curl —connect–timeout 7 –sSd “sql=select project,subproject,en_name,ip,retain_days from server where status=0 and lanip=\”${local_primary_ip}\”” http://op.domain.com:81/cmdb > ${tmp_dir}/${project_name}_ipdata_tmp.txt i=`grep “[0-9]” –c ${tmp_dir}/${project_name}_ipdata_tmp.txt` if (( “$i” == 1 ));then /bin/cp –ap ${tmp_dir}/${project_name}_ipdata_tmp.txt ${tmp_dir}/${project_name}_ipdata.txt echo “从cmdb成功获取到数据,开始应用” else echo “从cmdb获取到的数据有问题,仍使用老数据” fi # 注意: ${tmp_dir}/${project_name}_ipdata.txt的数据由cmdb中自动获取,一般情况下不应该人为去修改,除非cmdb暂时不好用了 while read line do export cmdb_project_value=`echo $line | awk ‘{ print $1; }’` export cmdb_subproject_value=`echo $line | awk ‘{ print $2; }’` export cmdb_en_name_value=`echo $line | awk ‘{ print $3; }’` export cmdb_ip_value=`echo $line | awk ‘{ print $4; }’` #export cmdb_ip_value=$local_primary_ip export cmdb_retain_days=`echo $line | awk ‘{ print $5; }’` done < ${tmp_dir}/${project_name}_ipdata.txt export cmdb_project_name=${cmdb_project_value}_${cmdb_subproject_value}_${cmdb_en_name_value}_${cmdb_ip_value} export retain_days=$cmdb_retain_days ### cmdb查询结束 ### # mysql程序路径 本次采用了系统自带的 export mysql_base_dir=“/opt/mysql56” export mysql_bin_path=“${mysql_base_dir}/bin” # 实例配置 export mysql_client_conf=“/root/.mysql/conn_db.conf” # 需要排除的库名 export ex_dbname_list=“information_schema performance_schema” # 跨机备份,FTP信息 export ftpip=‘backup.domain.com’ export ftpport=’21’ export ftpuser=‘user’ export ftppw=‘pass’ export ftpsw=“yes” # To turn on or off the FTP upload if [ “$cmdb_ip_value” == “” ];then echo “ip不存在,灾备可能会上传Null目录,或灾备父根目录” elif [ “$cmdb_en_name_value” == “” ] || [ “$cmdb_en_name_value” == “Null” ] || [ “$cmdb_ip_value” == “Null” ];then export ftpdir=${cmdb_project_value}/${cmdb_ip_value} else export ftpdir=${cmdb_project_value}/${cmdb_en_name_value}_${cmdb_ip_value} fi # 时间变量,一般无需修改 export datetime=$(date +%Y%m%d–%H%M) export parameter1=$1 # 打印mysql版本 ${mysql_bin_path}/mysql –V ############# PROC ################# # 记录开始时间 start_time=$(date +%s) # 帮助信息 function help_msg() { cat <<EOF HELP: /root/sh/backup_mysql_mysqldump_multi.sh default EOF } # 标准发件函数 function mailto_advanced() { # mail echo “$msg” | /opt/mutt/bin/mutt \ –e ‘set content_type=”text/html”‘ \ –s “[backup] $sub” \ –e ‘my_hdr from:’“$mailfromadd” \ –c “$mailccadd” \ “$mailtoadd” — } function get_dbname_list() { echo “`date +”%Y–%m–%d %H:%M:%S“` 获取库名列表…” cat /dev/null > ${tmp_dir}/${project_name}_dbname_list.txt ${mysql_bin_path}/mysql —defaults–extra–file=${mysql_client_conf} –s —column–names –e “show databases;” | grep –v “Database” > ${tmp_dir}/${project_name}_dbname_list.txt dbname_array=($(cat ${tmp_dir}/${project_name}_dbname_list.txt)) echo “`date +”%Y–%m–%d %H:%M:%S“` 获取到库名列表:${dbname_array[*]}” } function backup_db() { echo “`date +”%Y–%m–%d %H:%M:%S“` 清理${retain_days}天前的数据…” find “$backup_dir” –maxdepth 1 –name “*.sql.gz” –mtime +“$retain_days” –exec rm –f {} \; cat /dev/null > ${tmp_dir}/${project_name}_backup_list.txt cat /dev/null > ${log_dir}/${project_name}_mysqldump_error.log echo “`date +”%Y–%m–%d %H:%M:%S“` 备份开始…” export db_count=0 for dbname in ${dbname_array[*]} do echo “备份${dbname}…” # 注意,–skip-opt和–lock-tables=false等参数禁用了锁库锁表,减少对线上业务的影响,如需一致性备份,比如创建数据快照用于主从复制,需要另行修改mysqldump参数 ${mysql_bin_path}/mysqldump —defaults–extra–file=${mysql_client_conf} —default–character–set=utf8 —skip–opt —routines —triggers —events —lock–tables=false —add–drop–table —create–options —quick —extended–insert —set–charset —disable–keys —log–error=${log_dir}/${project_name}_mysqldump_error.log ${dbname} | gzip > ${backup_dir}/${cmdb_project_name}_${dbname}_${datetime}.sql.gz echo ${cmdb_project_name}_${dbname}_${datetime}.sql.gz >> ${tmp_dir}/${project_name}_backup_list.txt export db_count=$((${db_count}+1)) done } function up_bak() { cd $backup_dir cat /dev/null > ${log_dir}/${project_name}_curl_error.log if [ “$ftpsw” == ‘yes’ ]; then for filename in `cat ${tmp_dir}/${project_name}_backup_list.txt` do # 注意,在被动模式用不了时,可关闭被动模式,命令是passive # ftp -v -n -i <<END # open $ftpip $ftpport # user $ftpuser $ftppw # bin # passive # cd $ftpdir # put ${filename} # close # bye # END curl –sS —stderr ${log_dir}/${project_name}_curl_error.log ftp://${ftpip}:${ftpport}/${ftpdir}/ –u “${ftpuser}:${ftppw}” –T “${filename}” # 如果ftp客户端也位于NAT后,就改用curl吧 done else echo “`date +”%Y–%m–%d %H:%M:%S“` 没有开启异地灾备。” fi cd $work_dir } function alert_func() { # 判断是否有问题 alert_flag_mysqldump=`wc –l ${log_dir}/${project_name}_mysqldump_error.log | awk ‘{ print $1; }’` alert_flag_upload=`wc –l ${log_dir}/${project_name}_curl_error.log | awk ‘{ print $1; }’` if [ “${alert_flag_mysqldump}” –gt 0 ];then alert_flag_mysqldump_msg=“mysqldump备份有问题” else alert_flag_mysqldump_msg=“mysqldump备份未发现问题” fi if [ “${alert_flag_upload}” –gt 0 ];then alert_flag_ftp_msg=“ftp上传有问题” else alert_flag_ftp_msg=“ftp上传未发现问题” fi if [ “${alert_flag_mysqldump}” –gt 0 ] || [ “${alert_flag_upload}” –gt 0 ];then export sub=“${alert_sub}备份故障,需要人工介入排查。” export msg=“${alert_flag_mysqldump_msg},${alert_flag_ftp_msg},信息来源:${local_primary_ip}” echo “${sub} ${msg}” else export sub=“${alert_sub}备份完成。” export msg=“${alert_flag_mysqldump_msg},${alert_flag_ftp_msg},信息来源:${local_primary_ip}” echo “${sub} ${msg}” fi # 钉钉通知报告 if [ “${alert_dingding_sw}” == “on” ];then curl ”“${alert_dingding_robot}”” \ –H ‘Content-Type: application/json’ \ –d ‘{“msgtype”: “text”, “text”: { “content”: “‘”${sub} ${msg}“‘” } }‘ echo “已发出钉钉告警” elif [ “${alert_dingding_sw}” != “on” ];then echo “没有开启钉钉告警” fi # 邮件通知报告 if [ “$mailto” == “mailto_advanced” ];then mailto_advanced echo “已发出邮件通知。” elif [ “$mailto” == “no” ];then echo “no mailto.” else echo “error, no mailto.” fi } if [ “$parameter1” == “default” ]; then get_dbname_list for ex_dbname in ${ex_dbname_list} do sed –i “/^${ex_dbname}$/d” ${tmp_dir}/${project_name}_dbname_list.txt done export dbname_array=($(cat ${tmp_dir}/${project_name}_dbname_list.txt)) echo “`date +”%Y–%m–%d %H:%M:%S“` 本次脚本运行实际征对下列平台备份:${dbname_array[*]}” backup_db echo “`date +”%Y–%m–%d %H:%M:%S“` done,本次共备份了${db_count}个数据库.” up_bak alert_func else help_msg echo “`date +”%Y–%m–%d %H:%M:%S“` error, exit.” exit fi echo “” stop_time=$(date +%s) echo “`date +”%Y–%m–%d %H:%M:%S“` 运行结束” echo “本次脚本运行了$((${stop_time}-${start_time}))秒。” |
发表回复