现在通用的mysql主从方案已经很成熟,例如,现在公司做的是一主+两从方案,如果主机宕掉,采用域名方式切换从机,也非常方便。
现在增加一套方案,实现以下功能:
1、方便的备份可刻盘,或者灵活的备份到第三主机。
2、如果出现误删除,可恢复。
第一点是必要的,如出现重大物理灾难,例如整个机房瘫痪,刻盘恢复是很重要的,当然这种情况极低。
设计整体备份图如下:
备份方案
数据库主机是 ***.***.***.245,***.***.***.246, ***.***.***.39。
过程如下:
1、39从机会每周执行一次定时脚本database_dump_senior.sh一次,生成dump出一份备份,举例来说每周日上午10点。每次dump出一份都会记录当天的日期,并将导出的databases_product.sql和binlog_info.txt文件保存到当前日期下,例如 /home/data/mysql_bak/dumps/2013_08_06/ 下。然后rsync同步到245和246的文件夹下。
2、245会有定时脚本每隔十分钟执行一次(可以按需设定),读取dumps文件夹下的从机binlog信息,读取binlog_info.txt里的日期信息生成日期文件夹,读取binlog_info.txt文件找到要备份的binglog日志,cp到binlog文件夹下。如/home/data/mysql_bak/binlog/2013_08_06/下。然后同步一份到246和39
3、39和245都会在每次脚本执行时清除8天未被修改过的数据,这样可以保持每台服务器至少有两个版本的备份。在网络断掉的情况下是有用处的。
目录结构
/home/data/mysql_bak/ 下
------dumps
------2013_08_06
------databases_product.sql
------ binlog_info.txt
------2013_08_13
------databases_product.sql
------ binlog_info.txt
------binlog_info.txt
------binlog
------2013_08_06
------mysql-bin.000385
------mysql-bin.000386
------2013_08_13
------mysql-bin.000386
------mysql-bin.000387
为了避免转储时主机压力过大,采用在从机备份的方式,39从机在stop slave 后开始 dump一份全库的备份,然后记录从机备份的位置,保存在binlog_info.txt里。binlog_info.txt 保存内容如下:
current_date:2013_08_15
Master_Log_File: mysql-bin.000386
Read_Master_Log_Pos: 90835176
Relay_Log_File: netease-test-namenode-relay-bin.000022
Relay_Log_Pos: 253
Relay_Master_Log_File: mysql-bin.000386
Exec_Master_Log_Pos: 90835176
Until_Log_File:
Until_Log_Pos: 0
current_date 是由脚本根据系统时间生成,其余是读取从机变量。
出现风险的状况
1、 从机39坏了,binlog_info.txt未被替换成新的,这时主机会按从原有的binlog_info.txt读取到的位置信息,一直保存最新的binlog。
2、 主机245坏了,由于在246和39备份了binlog,可以将数据恢复精确到到最后十分钟(主机定时任务时间)。
3、 从机 246 坏了,无任何影响。
4、采用binlog在主机备份是保证数据始终与主机一致,更高的可靠性。
5、通过删除脚本,保证无论什么时候都会有两份备份,一份最新的,一份上周的。
这些都要配合从机状态监测。
脚本
从机39上跑的脚本:
#!/bin/sh
current_date=`date +%Y_%m_%d`;
back_path="/home/data/mysql_bak/dumps";
`mkdir -p ${back_path}/${current_date}`;
#停止与主机同步
mysql --socket=/home/mysql/data_product/mysql.sock -e "stop slave";
echo "now, slave stopped!";
#导出所有数据库
echo "dump all databases begin!";
`mysqldump --all-databases --socket=/home/mysql/data_product/mysql.sock > ${back_path}/${current_date}/databases_product.sql`;
echo "dump all databases end!";
#保存当前日期
`echo "current_date:${current_date}" > ${back_path}/${current_date}/binlog_info.txt`;
#保存现在导出时的binlog位置
`mysql --socket=/home/mysql/data_product/mysql.sock -e "show slave status \G"|egrep 'Log_File|Log_Pos' >> ${back_path}/${current_date}/binlog_info.txt`;
#拷贝一份到备份的根目录
`cp ${back_path}/${current_date}/binlog_info.txt ${back_path}/binlog_info.txt`;
#重新开启与主机同步
mysql --socket=/home/mysql/data_product/mysql.sock -e "start slave";
echo "now, slave started!";
#删除8天前备份,这样每次保存最新一份,和最新一份的上一份。
find ${back_path}/ -type f -ctime +8 -exec rm -rf {} \;
#删除空文件夹
find ${back_path}/ -type d -regex ".*/[0-9_]+$"|(while read arg;do if [ `ls $arg |wc -l` -eq 0 ]; then rmdir $arg ; fi; done)
echo "old backups has been deleted!";
#将备份binlog位置信息文件,传送给主库
rsync -avz --delete ${back_path}/ ***.***.***.245::database_bak/dumps/
rsync -avz --delete ${back_path}/ ***.***.***.246::database_bak/dumps/
主机245上跑的脚本
#!/bin/sh save binlogs
#全局变量
back_path="/home/data/mysql_bak";
mysql_path="/home/mysql/data_product";
#判断如果不存在binlog的备份信息文件,则退出
if [ ! -f "${back_path}/dumps/binlog_info.txt" ];then
echo "ERROR,binlog_info.txt not exist,please check your file!";
exit;
fi
cd ${mysql_path};
#读取备份binlog位置以及日期信息
echo "now,get the backup binlog position info!"
current_date=`cat ${back_path}/dumps/binlog_info.txt|grep 'current_date'|sed 's/current_date://g'|tr ' ' '\0'`;
logFile=`cat ${back_path}/dumps/binlog_info.txt |grep 'Relay_Master_Log_File'|sed 's/Relay_Master_Log_File://g'|tr ' ' '\0'`;
echo -e "current date is : ${current_date}\nBinlog file is : ${logFile}\n";
#如果不存在则,创建备份文件夹
`mkdir -p ${back_path}/binlog/${current_date}`;
#备份记录binlog文件之后的剩余binlog文件
cat mysql-bin.index |grep -A100 ${logFile}|sed "s/.\///"|awk -v back_path=${back_path} -v current_date=${current_date} \
'{print "now save:" $0 ;system("cp " $0 " "back_path"/binlog/"current_date"/"$0);}';
echo "backup binlog ended!";
#删除8天前备份,这样每次保存最新一份,和最新一份的上一份。
find /home/data/mysql_bak/binlog/ -type f -ctime +8 -exec rm -rf {} \;
#删除空文件夹
find /home/data/mysql_bak/binlog/ -type d -regex ".*/[0-9_]+$"|(while read arg;do if [ `ls $arg |wc -l` -eq 0 ]; then rmdir $arg ; fi; done)
echo "old backups has been deleted!";
#将备份binlog信息同步到从库
rsync -avz --delete ${back_path}/binlog/ ***.***.***.39::database_bak/binlog/
rsync -avz --delete ${back_path}/binlog/ ***.***.***.246::database_bak/binlog/