完全备份和增量备份

简介

1·完全备份与增量备份的概念
2·使用 mysqldump 完全备份
3·使用 mysqldump 进行表结构备份
4·完全备份恢复的两种方法
5·使用 flush logs 进行增量备份
6·增量备份恢复
7·基于时间点与位子的恢复
8·MySQL 备份思路


完全备份与增量备份的概念

1·MySQL 完全备份:是对整个数据库的备份、数据库结构和文件结构的备份,保存的是备份完成时刻的数据库,它也是增量备份的基础。它的优点:备份与恢复操作简单,缺点是数据存在大量的重复,占用大量的备份空间,备份时间长。
2·MySQL 增量备份:是针对在上次完全备份或增量备份后被修改的文件才会备份。因为完全备份的 缺点会占用很多的资源,所以增量备份与完全备份这中结合就能解决这样的缺点。
3·MySQL 是没有提供直接的增量备份的办法,但是可以通过MySQL的二进制日志间接实现增量备份。二进制日志保存了所有更新或者可能更新数据库的操作,使用flush logs 可以使日志分割开来,这样就可以识别每次更新的操作会在另一个日志文件中。


实验前准备:

因为这里涉及到数据库的表,所以在这之前就创建好了一张表,如下图所示:


img_d22c3a7d8c6c605ad4cf9d850c6ef26d.png
MySQL 完全备份 + 增量备份+完全恢复

mysqldump 完全备份与恢复

1·针对一个库完全备份命令格式:
mysqldump -uroot -p123123 --databases kgc(库名) > /opt/kgc.sql(备份到什么地方)
2·模拟kgc这个库中的表丢失。
mysql> drop tabale school;


img_d0131b9e63493c853e193f799efc08d3.png
MySQL 完全备份 + 增量备份+完全恢复

3·数据库中的表丢失,恢复表的命令格式:
mysql -uroot -p123123 < /opt/kgc.sql ---- (恢复kgc库中的表,重你备份的地方导入即可)
4·验证恢复备份:
mysql> show tables;
mysql> select * from school;


img_1c9eb72aecb43700930a305a2f674210.png
MySQL 完全备份 + 增量备份+完全恢复

5·对数据库所有表进行备份
mysqldump -uroot -p123123 --all-databases > /opt/all.sql ----(对所有库备份加入选项 --all )


6·对库中的一张表的表结构进行备份,注意这里只是备份表结构
mysqldump -uroot -p123123 -d kgc(库名)school(表名) > /opt/desc.sql


MySQL 增量备份

1·增量备份是基于完全备份之后的所修改的数据进行备份,所以这里必须先做完全备份,在做增量备份。上面的实验已经做过了完全备份,现在可以直接做增量分了。
2·要进行MySQL增量备份需要开启二进制日志功能。需要在主配置文件【mysqld】项中加入:log-bin=mysql-bin 如下图:
[[email protected] ~]# vim /etc/my.cnf


img_628792cae253a1f065004fed64660c5c.png
MySQL 完全备份 + 增量备份+完全恢复

3·重启MySQL服务、查看二进制日志文件
[[email protected] ~]# systemctl restart mysqld.service


img_775b66f50cb127896c17f67a7a6ac962.png
MySQL 完全备份 + 增量备份+完全恢复

4·模拟在表中添加数据,然后把只备份添加的数据。
mysql> insert into school (姓名,成绩) values ('成龙',79);


img_e22c67bbb296079342d848ed25962886.png
MySQL 完全备份 + 增量备份+完全恢复

5·模拟故障,因为人员误操作或其他因素,导致表被删除。
使用命令 mysqladmin -uroot -p123123 flush-logs 再次生成一份日志文件,这样接下来对MySQL的记录将会写在新的日志文件中
mysql> drop table school;
mysql> show tables;


img_03d2f0dd231594ac62b11b5636041041.png
MySQL 完全备份 + 增量备份+完全恢复

6·数据恢复。恢复思路
(1)首先需要把完全备份恢复
(2)其次,需要知道我们之前在插入数据的时候的所有操作都会纪律在日志文件中。
(3)最后我们需要重日志文件中恢复之前插入的数据。
(4)这样就能完全恢复之前表中的数据。


img_84c45154921b84bb69a1afe414e7314a.png
MySQL 完全备份 + 增量备份+完全恢复

7·验证数据是否恢复成功。


img_e0f48546c134744196a7dc553259bc17.png
MySQL 完全备份 + 增量备份+完全恢复

8·基于时间点与位置的恢复
列如:需要往数据库中插入两条数据,但是由于误操作,两条插入语句中间删除了一条数据,而这条数据是不应该被删除的,这个时候就需要恢复到误操作之前,跳过删除这一条数据这个命令,再恢复后面的正确操作。
(1)再次分割日志:
[[email protected] data]# mysqladmin -uroot -p123123 flush-logs
(2)模拟误操作,添加数据的过程中,误删除一条数据,因为大意没注意删除的数据还需要保留,再次继续写入数据


img_5ed8e2a49c2b275bc2a7598a81800064.png
MySQL 完全备份 + 增量备份+完全恢复

9·这时候发现表数据丢失,需要恢复表中被删除的数据。恢复思路:
(1)再次进行日志分割,是接下来的操作归于另一个二进制日志文件中
(2)查看需要恢复的二进制日志文件,找到需要恢复的时间点或位置点并且记录
(3)如果是基于时间点恢复则使用命令:
--stop-datetime(到这个错误操作的时间点停止)
--start-datetime (再到下一个正确的时间点开始)
(4)如果是基于位置的恢复则使用命令:
--stop-position ---(上一次可以正确执行的位子点)
--start-position ---(下一次可以正确执行的位子点)


10·使用以下命令查看二进制日志文件,查找正确与错的时间和位子点:
[[email protected] data]# mysqlbinlog --no-defaults --base64-output=decode-rows -v mysql-bin.000003
查找的内容如下图:


img_e8929e2c34264dfab5771c7ba47f7529.png
MySQL 完全备份 + 增量备份+完全恢复

11·模拟故障数据库中的表丢失,开始恢复数据,恢复思路:
(1)首先完全备份恢复
(2)其次找到恢复的时间点或者位子点
(3)开始增量备份位子点的恢复(这里我选择位子点恢复)
[[email protected] data]# mysqlbinlog --no-defaults --stop-position='344' /usr/local/mysql/data/mysql-bin.000003 | mysql -uroot -p123123 ---(恢复正确位子点)
[[email protected] data]# mysqlbinlog --no-defaults --start-position='835' /usr/local/mysql/data/mysql-bin.000003 | mysql -uroot -p123123 ---(下一次正确位子点)


总结

1·MySQL 中使用mysqldump 工具备份,它生成的是sql的脚本文件
2·恢复数据使用mysql
3·备份可以针对整库、一些库或表、表结构进行备份。
4·增量备份需要使用分割日志的方式备份
5·增量恢复需要根据日志文件的先后,做个执行
6·使用基于时间和位子的方式恢复,可以更精确的恢复数据
7·大企业应该每周做一次全备,每天做一次增量备份;中小企业应该每天进行一次全备
8·可以结合周期性计划任务进行备份,定时备份。时间主要放在业务需求量较小的时间段。

提供一个sql语句

#!/bin/bash
# full && increment backup and recover
# 说明:事先要创建/data/bak目录,且在执行增量备份时做过至少一次全量备份,否则找不到position文件。
port='3306'
back_src_dir="/data/mysql/${port}/logs/binlog"
back_dir='/data/bak'
DATE=`date +%Y%m%d`
user='root'
pass='cy2009'
bak_db='test1'
mysql_bin='/usr/local/mysql-5.1.48/bin'
socket="/data/mysql/${port}/mysql.sock"

full_bak()
{
cd ${back_dir}
DumpFile=Full_back$DATE.sql
${mysql_bin}/mysqldump --lock-all-tables --flush-logs --master-data=2 -u${user} -p${pass} ${bak_db} > ${DumpFile}
${mysql_bin}/mysql -u${user} -p${pass} --socket=${socket} -e "unlock tables"

#把当前的binlog和position信息存入position文件
cat ${DumpFile} |grep 'MASTER_LOG_FILE'|awk -F"'" '{print $2}' > ${back_dir}/position
cat ${DumpFile} |grep 'MASTER_LOG_FILE'|awk -F"=" '{print $3}' |awk -F";" '{print $1}' >> ${back_dir}/position
}

incre_bak()
{
#锁定表,刷新log
${mysql_bin}/mysql -u${user} -p${pass} --socket=${socket} -e "flush tables with read lock"
${mysql_bin}/mysqladmin -u${user} -p${pass} --socket=${socket} flush-logs
#获取上次备份完成时的binlog和position
cd ${back_dir}
start_binlog=`sed -n '1p' position`
start_pos=`sed -n '2p' position`

#获取目前的binlog和position
mysql -u${user} -p${pass} --socket=${socket} -e "show master status\G" | awk '{print $2}'| sed -n '2,3p' > now_position
stop_binlog=`sed -n '1p' now_position`
stop_pos=`sed -n '2p' now_position`

#如果在同一个binlog中
if [ "${start_binlog}" == "${stop_binlog}" ]; then
${mysql_bin}/mysqlbinlog --start-position=${start_pos} --stop-position=${stop_pos} ${back_src_dir}/${start_binlog} >> Incr_back$DATE.sql 
#跨binlog备份
else
startline=`awk "/${start_binlog}/{print NR}" ${back_src_dir}/mysql-bin.index`
stopline=`wc -l ${back_src_dir}/mysql-bin.index |awk '{print $1}'`
for i in `seq ${startline} ${stopline}`
do
binlog=`sed -n "$i"p ${back_src_dir}/mysql-bin.index |sed 's/.*\///g'`
case "${binlog}" in
"${start_binlog}")
${mysql_bin}/mysqlbinlog --start-position=${start_pos} ${back_src_dir}/${binlog} >> Incr_back$DATE.sql
;;
"${stop_binlog}")
${mysql_bin}/mysqlbinlog --stop-position=${stop_pos} ${back_src_dir}/${binlog} >> Incr_back$DATE.sql
;;
*)
${mysql_bin}/mysqlbinlog ${back_src_dir}/${binlog} >> Incr_back$DATE.sql
;; 
esac
done
fi
#解除表锁定,并保存目前的binlog和position信息到position文件。
${mysql_bin}/mysql -u${user} -p${pass} --socket=${socket} -e "unlock tables"
cp now_position position
}

full_recov()
{
cd ${back_dir}
recov_file1=`ls | grep 'Full_back'`
${mysql_bin}/mysql -u${user} -p${pass} --socket=${socket} -e "use ${bak_db}; source ${back_dir}/${recov_file1};"
}

incre_recov()
{ 
cd ${back_dir}
recov_file2=`ls |grep 'Incr_back'` 
${mysql_bin}/mysql -u${user} -p${pass} --socket=${socket} -e "use ${bak_db}; source ${back_dir}/${recov_file2};"
}

while true
do
echo -e "\t\t**************************************"
echo
echo -e "\t\t\tWelcome to backup program!"
echo
echo -e "\t\t\t(1) Full Backup For MySQL"
echo -e "\t\t\t(2) Increment Backup For MySQL"
echo -e "\t\t\t(3) Recover From The Full Backup File"
echo -e "\t\t\t(4) Recover From The Increment Backup File"
echo -e "\t\t\t(5) Exit The Program!"
echo 
echo -e "\t\t**************************************"

read -p "Enter your choice:" choice
case $choice in
1)
echo "now! let's backup the data by full method......."
full_bak
echo "succeed!"
sleep 2
;;
2)
echo "now! let's backup the data by increment method......"
incre_bak
echo "succeed"
sleep 2
;;
3)
echo "now! let's recover from the full back file"
full_recov
echo "successful"
sleep 2
;;
4)
echo "now! let's recover from the increment backup file"
incre_recov
echo "successful"
sleep 2
;;
5)
break
;;
*)
echo "Wrong Option! try again!"
sleep 2
continue
;;
esac
done

作者:致远1988
链接:https://www.jianshu.com/p/6e723f86017d
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。