1.项目任务概述

  • 硬件环境部署:根据架构和分配存储策略搭建3台主机
  • 软件环境部署:部署测试业务系统软件
  • 策略制定:制定备份策略
  • 备份准备:编写备份脚本
  • 备份实施:设置备份定时任务
  • 场景模拟:业务系统录入测试数据
  • 故障模拟:模拟数据库数据磁盘损坏
  • 数据恢复:执行数据还原与数据恢复

2.制定备份策略

  • 按照合同要求采用周备份策略
  • 备份时间选在凌晨2:00业务不忙时
  • 周日进行逻辑全备
  • 非周日进行日志增量备份
  • 备份脚本存放于备份服务器中
  • 备份服务器与数据库服务器配置免密码登录
  • 备份服务器安装规划配置crond定时任务

images-wps6.png

3.编写备份脚本

备份文件命名应符合合同中规定的备份文件命名规范《系统名称+介质编号+备份内容+备份日期》的要求

3.1数据库全备脚本示例

数据库全备脚本(供参考):

#!/bin/bash
# 全备方式
# 一般在备份机使用mysqldump远程备份数据库服务器中的mysql数据库数据
# 适用于小中型mysql数据库

source /etc/profile        #加载系统环境变量
source ~/.bash_profile     #加载用户环境变量
set -o nounset             #引用未初始化变量时退出

# mysqldump命令使用的用户和密码存放于/etc/my.cnf中
# 同时设置/etc/my.cnf权限600,防止普通用户看到
# cat /etc/my.cnf
# [mysqldump]
# user=root
# password=Abc123!!!

# 远程数据库IP和端口号
host="127.0.0.1"
port="3306"

# binlog日志前缀名
binlog_prefix="binlog"

# 产生备份路径、备份文件名、日志路径和日志文件名
backup_path="/backup/mysql/data"

# 如果不存在备份目录就创建
if [ ! -e $backup_path ];then
    	mkdir -p $backup_path/archive
	# 备份数据目录只能root进入
	# 防止备份被普通用户copy
    	chmod 700 $backup_path
fi

# 产生备份序号
last_sn=$(ls -t $backup_path/*.tar.gz 2>/dev/null|head -1|cut -d "_" -f2)

if [ $? -ne 0 ];then
	#如果目录中无全备,序号从0001开始
	last_sn="0001"
else
	#如果目录中有之前全备,新备份序号为当前最大序号加1
	#去掉序号前导0字符
	last_sn=$(echo $last_sn|sed -e 's/^[0]*//')
	#字符转为10进制数后加1
  	let last_sn=$[10#${last_sn}+1]
	#序号前继续加上前导0
  	last_sn=$(printf %04d $last_sn)
fi

# 产生备份时间戳
let begin_timestamp=$(date +%s)
# 时间戳转成年月日时分秒可读格式作为备份起始时间
begin_time=$(date -d @${begin_timestamp} '+%Y_%m_%d_%H_%M_%S')

# 生成备份文件名
backup_name="hr_${last_sn}_dbfull_${begin_time}.sql"
# 设置备份日志路径和日志文件名
backup_log="${backup_path}/backup.log"

# 恢复起始日志附加到备份文件名方便恢复
start_binlog=""

echo "正在备份中......"

# 函数用于备份并压缩
backup_mysql(){
    	# -R备份存储过程,函数,触发器
	# 如有报错信息记录到备份日志中
	mysqldump -h$host -P$port --single-transaction --flush-logs --master-data=2 --all-databases -R>$backup_path/$backup_name 2>>$backup_log   
    	if [ $? -eq 0 ];then
		# 如果备份成功
        	cd $backup_path
		# 获取备份文件中记录的日志编号,即:恢复起始日志
		start_binlog=$(grep "^-- CHANGE MASTER TO MASTER_LOG_FILE=" $backup_name|grep -E -o "$binlog_prefix.[0-9]{6}")
		# 压缩归档同时删除源文件
        	tar zcpf $backup_name.$start_binlog.tar.gz $backup_name --remove-files&>/dev/null
		return 0   
    	else
		# 如果备份失败
        	cd $backup_path
        	rm -f $backup_name
		return 1
    	fi
}


# 调用备份和压缩函数
# 错误输出和标准输出记录到日志中
backup_mysql>>$backup_log 2>&1

if [ $? -eq 0 ];then
	# 如果函数执行成功,显示输出同时用tee将输出附加到日志中
	# 计算备份时长
	let end_timestamp=$(date +%s)
	let backup_interval=$[end_timestamp-begin_timestamp]

	echo "-------------------------------------------------------------------------------------------"|tee -a $backup_log
	echo "全部备份记录请查看: $backup_log"
	echo "备份状态: 成功!"|tee -a $backup_log
	echo "备份序号: $last_sn"|tee -a $backup_log
	echo "备份时间: $(date -d @${begin_timestamp} '+%Y-%m-%d %H:%M:%S')"|tee -a $backup_log
	du -sh $backup_path/$backup_name.$start_binlog.tar.gz | awk '{print "备份文件: " $2 "\n备份大小: " $1}'|tee -a $backup_log
	echo "备份时长: ${backup_interval}秒"|tee -a $backup_log
	echo "起始日志: $start_binlog,注意:从该日志开始恢复"|tee -a $backup_log
	echo -e "-------------------------------------------------------------------------------------------\n\n"|tee -a $backup_log
else
	# 如果函数执行失败,显示输出同时用tee将输出附加到日志中
	echo "----------------------------------------------------------------------"|tee -a $backup_log
	echo "备份结束,详细信息请查看 $backup_log"
	echo "备份时间: $(date -d @${begin_timestamp} '+%Y-%m-%d %H:%M:%S')"|tee -a $backup_log
	echo "备份失败"|tee -a $backup_log
	echo -e "-------------------------------------------------------------------------------------------\n\n"|tee -a $backup_log
	
fi

#设置归档天数
days_to_archive=15
#移动2周前的备份到归档目录
find $backup_path -type f -iname "*.tar.gz" -mtime +$days_to_archive -exec mv {} $backup_path/archive \;>/dev/null 2>&1

3.2备份日志输出格式示例

脚本日志输出格式(备份文件名加入了起始恢复的日志文件编号用于提高恢复效率,供参考)

images-wps8.jpg

4.设置备份定时任务

按照备份策略设定备份计划任务

crontab -e

[root@bakserver ~]# crontab -l 0 2 * * 0 bash /root/mysql_backup_data.sh&>/dev/null 0 2 * * 1 bash /root/mysql_backup_log.sh&>/dev/null 0 2 * * 2 bash /root/mysql_backup_log.sh&>/dev/null 0 2 * * 3 bash /root/mysql_backup_log.sh&>/dev/null 0 2 * * 4 bash /root/mysql_backup_log.sh&>/dev/null 0 2 * * 5 bash /root/mysql_backup_log.sh&>/dev/null 0 2 * * 6 bash /root/mysql_backup_log.sh&>/dev/null

产生备份后的目录结构

images-wps9.png

5.业务系统录入测试数据

  • 录入的测试数据用于检验数据恢复效果
  • 录入数据之前要先在备份服务器运行脚本做数据库全备

6.模拟数据库数据磁盘损坏

6.1常见的硬盘损坏原因

  • 机械硬盘盘片出现坏道导致数据所在扇区不可读
  • 硬盘电路板故障导致无法读取盘片数据
  • 磁盘托架松动导致硬盘与服务器主板接触不良
  • 连接硬盘的RAID卡故障,导致连接RAID卡的一个或多个硬盘无法读取数据

6.2数据文件硬盘损坏表象示例

以上后三种情况会致使硬盘故障灯变成红色:

images-wps10.png

上面第一种情况遇到的情景更加复杂,为了测试方便,可以采用直接删除数据文件的方式,在数据库服务器上执行以下操作:

rm -rf /data/*

直接把数据文件删掉,用不了多久测试业务系统就会报错:

images-wps11.png

6.3故障场景描述示例

  • 小李为外派到甲方办公场所的驻场运维工程师,他在早上9:00时登录业务系统测试,结果一切正常
  • 10:30时有甲方业务人员反映,业务系统页面出现异常
  • 小李发现数据库服务器其中一块硬盘故障灯告警,登录主机后发现操作系统可正常工作,但/data目录中的数据库数据文件不能正常查看
  • 经过检查小李发现日志文件对应硬盘可以正常访问,查看备份主机数据库备份文件完好无损
  • 小李推断数据文件硬盘损坏且符合数据恢复条件
  • 为了能让甲方人员正常使用业务系统,小李需要立刻做数据恢复

6.4架构中故障点示意图

images-wps12.png

7.执行数据还原与数据恢复

由于采用了将数据库数据文件和日志文件分磁盘存储的策略,数据库日志完好无损,而且数据库备份单独保存在备份服务器中同样完整,因此符合做数据恢复的条件,当前要做的数据恢复属于完全恢复,恢复流程可以参考下面流程图:

images-wps13.png

由于不是真实而是以删除数据文件方式的模拟场景,恢复从上图第4步开始:

7.1复制最近一次全备到数据库服务器

scp 192.168.2.12:/backup/xxx.tar.gz /root

7.2生成恢复SQL语句

mysqlbinlog mysql-bin.xxxx{x..y}>/root/recover.sql

7.3断掉连接数据库服务器的网线

恢复过程不允许业务人员通过业务系统连接刚刚初始化的数据库

7.4重新初始化MySQL实例

pkill -9 mysqld (多执行几次,因为默认mysqld服务停止后会马上自启)

rm /data/* -rf

systemctl restart mysqld

grep -i "temporary password" /var/log/mysqld.log (获得临时登录密码)

mysql -uroot -p (使用临时密码登录)

mysql> set password='新密码';

7.5还原数据库数据

mysql> source /路径/备份文件名

7.6检验还原数据

mysql> show databases;

8.执行恢复SQL语句

mysql> source /root/recover.sql

8.1检验恢复数据

mysql> show databases;

mysql> use hr

mysql> show tables;

mysql> select * from emp; (检查新进录入的人员信息是否存在)

images-wps14.png

8.2重新做数据库全备

在备份机直接运行备份脚本即可