数据库物理备份就是拷贝数据库数据文件,但是需要考虑的问题也有:
需要确保数据文件的时间一致性?
1.冷备:停止数据库,实现物理备份;
但是一个真正生产数据库不能实现离线操作,那我们就可以通过数据库的主从复制实现;
主数据库服务器的数据同步到从服务器,而我们在主从复制中从服务器停止数据库是不会影响业务的,就能够实现物理备份;备份完成从服务器上线后会自动从主服务器同步数据;这是一种理想的备份方案;
2.第二种方法是基于LVM2的快照实现数据库的备份,可以实现几乎热备,
前提数据库数据必须放置在物理卷上;
下面我们就做基于LVM2的快照实现数据库备份的实现的实验
一.准备工作:
1.备份所有数据库。
[root@node1 ~]# mysqldump -A --lock-all-tables > /backup/all.sql
停止mysqld服务器:
[root@node1 ~]# service mysqld stop Shutting down MySQL.. [ OK ]
2.LVM逻辑卷构建
格式化磁盘:
[root@node1 ~]# echo -n -e "n\np\n3\n\n+10G\nt\n3\n8e\n\nw\n" |fdisk /dev/sda [root@node1 ~]# partx -a /dev/sda BLKPG: Device or resource busy error adding partition 1 BLKPG: Device or resource busy error adding partition 2 BLKPG: Device or resource busy error adding partition 3
物理卷创建: [root@node1 ~]# pvcreate /dev/sda3 Physical volume "/dev/sda3" successfully created 卷组创建: [root@node1 ~]# vgcreate myvg /dev/sda3 Volume group "myvg" successfully created 逻辑卷创建: [root@node1 ~]# lvcreate -L 5G -n mylv myvg Logical volume "mylv" created [root@node1 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert mylv myvg -wi-a----- 5.00g root vg0 -wi-ao---- 20.00g swap vg0 -wi-ao---- 2.00g usr vg0 -wi-ao---- 10.00g var vg0 -wi-ao---- 20.00g
格式化逻辑卷为ext4文件系统:
[root@node1 ~]# mke2fs -t ext4 /dev/myvg/mylv
挂载逻辑卷到数据库数据目录:
[root@node1 ~]# mount /dev/myvg/mylv /mydata/data/
mysql访问此目录需要权限,属主属组更改为mysql:
[root@node1 ~]# chown -R mysql.mysql /mydata/data/
3.初始化mysql
由于我们挂载在/mydata/data上了,原来的mysql数据文件都被隐藏了,我们需要初始化mysql;
[root@node1 root]# cd /usr/local/mysql [root@node1 mysql]# scripts/mysql_install_db --user=mysql --datadir=/mydata/data
启动mysqld服务器:
[root@node1 mysql]# service mysqld start Starting MySQL. [ OK ]
恢复我们刚才备份的数据库:
[root@node1 mysql]# mysql -u root -p < /backup/all.sql Enter password: [root@node1 mysql]# 是空密码;
登录数据库是拒绝的:
[root@node1 mysql]# mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
初始化安装后我们root目录下.my.cnf中定义的数据库root用户的密码无法生效了,我们需要使用空密码登录数据库,执行权限刷新操作,如下命令:
[root@node1 mysql]# mysql -uroot -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 7 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> flush privileges; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> \q Bye
下面我们就能登录数据库了,我们查看恢复的情况:
[root@node1 mysql]# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> use hellodb; Database changed MariaDB [hellodb]> select * from tb1; +------+ | id | +------+ | 1 | | 2 | | 22 | | 9 | | 20 | +------+ 5 rows in set (0.00 sec) MariaDB [hellodb]> \q Bye
跟上篇博客的数据是一致的,前提准备完成;
二.实现阶段
假设现在数据库是线上数据库服务器,有许多用户连接到数据库执行读写操作,我们备份操作需要考虑的方面:
1.如果是备份单个库,那么要确定这个库的引擎是InnoDB,且必须是每表的存放都是单个表空间的(innodb_file_per_table);否则,备份必须执行全库备份。
MariaDB [(none)]> show global variables like 'innodb_file_per%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_file_per_table | ON | +-----------------------+-------+ 1 row in set (0.00 sec)
我们可以查看hellodb数据库中的文件:
[root@node1 ~]# ls /mydata/data/hellodb/ classes.frm coc.frm courses.frm db.opt myisam_table.MYD scores.frm students.frm tb1.frm teachers.frm toc.frm v1.frm classes.ibd coc.ibd courses.ibd myisam_table.frm myisam_table.MYI scores.ibd students.ibd tb1.ibd teachers.ibd toc.ibd
我们备份hellodb这个数据库就只需要复制这个目录里的所有表文件即可,但是可能会出问题,大部分环境是可以的。
2.备份之前需要锁定表;
在生产环境中你加这个锁可能耗时很长,因为生产环境中有很多用户在访问数据库进行读写操作,必须等用户操作完成后才能加上锁;
[root@node1 ~]# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 10 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. #请求锁定表, MariaDB [(none)]> flush tables with read lock; Query OK, 0 rows affected (0.00 sec) #滚动二进制日志 MariaDB [(none)]> flush logs; Query OK, 0 rows affected (0.25 sec) #查看现在使用的哪个二进制文件的哪个位置;我们可以将这个信息保存下来,以后做增量备份时就需要充这个二进制日志文件的这个位置进行。 MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000009 | 365 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec) #查看二进制日志 MariaDB [(none)]> show master logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000001 | 67334 | | mysql-bin.000002 | 977605 | | mysql-bin.000003 | 345 | | mysql-bin.000004 | 345 | | mysql-bin.000005 | 345 | | mysql-bin.000006 | 345 | | mysql-bin.000007 | 345 | | mysql-bin.000008 | 542426 | | mysql-bin.000009 | 365 | +------------------+-----------+ 9 rows in set (0.00 sec)
不要退出,不然就释放了。
3.进行LVM2快照创建
实际环境中创建快照时我们需要考虑这段时间内数据的变化量大小;
我们重新开启一个进程进行快照的创建:
[root@node1 mysql]# lvcreate -L 200M -n mydata-snap /dev/myvg/mylv -s -p r Logical volume "mydata-snap" created
4.创建完成快照后立即解锁
接上面锁表的操作: #进行解锁; MariaDB [(none)]> unlock tables; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> \q Bye
至此,用户又可以读写操作数据库了;
5.现在我们就能备份了
创建目录: [root@node1 ~]# mkdir /snap 挂载快照卷到此目录: [root@node1 ~]# mount /dev/myvg/mydata-snap /snap/ mount: block device /dev/mapper/myvg-mydata--snap is write-protected, mounting read-only 挂载完成后查看目录里的文件: [root@node1 ~]# ls /snap/ aria_log.00000001 mysql mysql-bin.000007 aria_log_control mysql-bin.000001 mysql-bin.000008 hellodb mysql-bin.000002 mysql-bin.000009 ibdata1 mysql-bin.000003 mysql-bin.index ib_logfile0 mysql-bin.000004 node1.stu31.com.pid ib_logfile1 mysql-bin.000005 performance_schema multi-master.info mysql-bin.000006 test
所有的数据库都在这里了。
下面我们就能实现将备份好的文件同步推送到其他节点的服务器上或者同步到其他目录:
我这里为了演示就只推送到/backup目录下了,并且我只推送了一个数据库hellodb:
[root@node1 ~]# cd /snap/ [root@node1 snap]# ls aria_log.00000001 mysql mysql-bin.000007 aria_log_control mysql-bin.000001 mysql-bin.000008 hellodb mysql-bin.000002 mysql-bin.000009 ibdata1 mysql-bin.000003 mysql-bin.index ib_logfile0 mysql-bin.000004 node1.stu31.com.pid ib_logfile1 mysql-bin.000005 performance_schema multi-master.info mysql-bin.000006 test [root@node1 snap]# rm -rf /backup/hellodb-2015-01-22-19-34-04/ [root@node1 snap]# rsync -a hellodb /backup/hellodb-`date +%F-%H-%M-%S` [root@node1 snap]# ls /backup/hellodb-2015-01-22-20-21-48/ hellodb [root@node1 snap]# ls /backup/hellodb-2015-01-22-20-21-48/hellodb/ classes.frm courses.ibd scores.frm tb1.ibd v1.frm classes.ibd db.opt scores.ibd teachers.frm coc.frm myisam_table.frm students.frm teachers.ibd coc.ibd myisam_table.MYD students.ibd toc.frm courses.frm myisam_table.MYI tb1.frm toc.ibd
备份完成了。
考虑一个问题:
如果我们备份的只是单个数据库,而且基于二进制日志文件去做增量备份会出现将所有库的事件都记录下来了,我们需要使用文本分析工具对备份的二进制文件进行筛选,筛选出属于那个指定数据库的事件进行导入。
6.我们进行删除操作;
[root@node1 mysql]# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 11 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> use hellodb Database changed MariaDB [hellodb]> show tables; +-------------------+ | Tables_in_hellodb | +-------------------+ | classes | | coc | | courses | | myisam_table | | scores | | students | | tb1 | | teachers | | toc | | v1 | +-------------------+ 10 rows in set (0.00 sec) #我们删除其中一个表;删除后我们的快照空间的文件还是包含有此表的文件。 MariaDB [hellodb]> drop table myisam_table; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> \q Bye
对比查看数据库和快照卷的文件可以发现:
[root@node1 mysql]# ls /mydata/data/hellodb/ classes.frm courses.frm scores.ibd tb1.ibd toc.ibd classes.ibd courses.ibd students.frm teachers.frm v1.frm coc.frm db.opt students.ibd teachers.ibd coc.ibd scores.frm tb1.frm toc.frm [root@node1 mysql]# ls /snap/hellodb/ classes.frm courses.ibd scores.frm tb1.ibd v1.frm classes.ibd db.opt scores.ibd teachers.frm coc.frm myisam_table.frm students.frm teachers.ibd coc.ibd myisam_table.MYD students.ibd toc.frm courses.frm myisam_table.MYI tb1.frm toc.ibd
快照卷还包含有myisam_table这个表的数据文件。
7.我们将快照中的文件拷贝到/backup目录中:
[root@node1 mysql]# cp -a /snap /backup [root@node1 mysql]# ls /backup/ 20150122.sql.tgz daily increment-2015-01-22.sql all.sql hellodb-2015-01-22-20-21-48 snap bak.log hellodb-2015-01-22.sql [root@node1 mysql]# ls /backup/snap/ aria_log.00000001 mysql mysql-bin.000007 aria_log_control mysql-bin.000001 mysql-bin.000008 hellodb mysql-bin.000002 mysql-bin.000009 ibdata1 mysql-bin.000003 mysql-bin.index ib_logfile0 mysql-bin.000004 node1.stu31.com.pid ib_logfile1 mysql-bin.000005 performance_schema multi-master.info mysql-bin.000006 test
所有数据库的文件都在这里了,包含二进制文件;
8.假如我们继续操作将数据库hellodb误删除。
[root@node1 snap]# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 12 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. #删除hellodb数据库 MariaDB [(none)]> drop database hellodb; Query OK, 9 rows affected (1.83 sec) MariaDB [(none)]> \q Bye
9.备份数据库的二进制日志文件
由于我们备份快照后,其后的修改操作我们并没有备份,我们需要读取二进制日志文件,找出drop数据库的时间点,导出删除数据库之前的所有二进制日志。
[root@node1 ~]# mysqlbinlog /mydata/data/mysql-bin.000009 略… # at 558 #150122 20:29:08 server id 1 end_log_pos 645 Query thread_id=12 exec_time=2 error_code=0 SET TIMESTAMP=1421929748/*!*/; drop database hellodb /*!*/; DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
可以发现时间点是558,我们将时间点为558之前的所有操作日志都导出到一个文件中:
[root@node1 ~]# mysqlbinlog --stop-position=558 /mydata/data/mysql-bin.000009 >/tmp/b.sql [root@node1 ~]# ls /tmp all1.sql.xz hotbackup.sql mysql.sock a.sql ks-script-t3nzeD warmbackup.sql b.sql ks-script-t3nzeD.log yum.log
10.全库恢复操作
假如生产环境中遇到重大故障后,我们需要赶快停止数据库,进行数据库全库恢复操作。
停止数据库服务器:
[root@node1 ~]# service mysqld stop Shutting down MySQL.. [ OK ] 删除损坏的数据库数据文件: [root@node1 ~]# rm -rf /mydata/data/* 将快照的备份文件导入数据库数据目录: [root@node1 ~]# cp -a /backup/snap/* /mydata/data/ 必须保证恢复回来的数据的属主属组无改变: [root@node1 ~]# ls -l /mydata/data/ total 112216 -rw-rw---- 1 mysql mysql 16384 Jan 22 20:14 aria_log.00000001 -rw-rw---- 1 mysql mysql 52 Jan 22 20:14 aria_log_control drwx------ 2 mysql mysql 4096 Jan 22 20:16 hellodb -rw-rw---- 1 mysql mysql 12582912 Jan 22 20:16 ibdata1 -rw-rw---- 1 mysql mysql 50331648 Jan 22 20:16 ib_logfile0 -rw-rw---- 1 mysql mysql 50331648 Jan 22 20:13 ib_logfile1 -rw-rw---- 1 mysql mysql 0 Jan 22 20:14 multi-master.info drwx------ 2 mysql root 4096 Jan 22 20:16 mysql -rw-rw---- 1 mysql mysql 67334 Jan 22 20:13 mysql-bin.000001 -rw-rw---- 1 mysql mysql 977605 Jan 22 20:13 mysql-bin.000002 -rw-rw---- 1 mysql mysql 345 Jan 22 20:13 mysql-bin.000003 -rw-rw---- 1 mysql mysql 345 Jan 22 20:13 mysql-bin.000004 -rw-rw---- 1 mysql mysql 345 Jan 22 20:13 mysql-bin.000005 -rw-rw---- 1 mysql mysql 345 Jan 22 20:13 mysql-bin.000006 -rw-rw---- 1 mysql mysql 345 Jan 22 20:14 mysql-bin.000007 -rw-rw---- 1 mysql mysql 542426 Jan 22 20:17 mysql-bin.000008 -rw-rw---- 1 mysql mysql 365 Jan 22 20:17 mysql-bin.000009 -rw-rw---- 1 mysql mysql 171 Jan 22 20:17 mysql-bin.index -rw-rw---- 1 mysql mysql 5 Jan 22 20:14 node1.stu31.com.pid drwx------ 2 mysql mysql 4096 Jan 22 20:13 performance_schema drwx------ 2 mysql root 4096 Jan 22 20:16 test 恢复完成后启动mysqld数据库服务: [root@node1 ~]# service mysqld start Starting MySQL. [ OK ] [root@node1 ~]#
我们连入mysql将后续修改的数据导入进数据库:
注意:
mysqldump做的备份,数据还原时,会产生二进制日志,如果针对大数据量的数据库,这种二进制日志文件是无用的,可以不记录,我们就需要在导入文件是临时关闭二进制日志记录。
[root@node1 ~]# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 4 Server version: 10.0.13-MariaDB-log Source distribution Copyright (c) 2000, 2014, Oracle, SkySQL Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> use hellodb; Database changed #我们原来是删除了myisam_table 表的。 MariaDB [hellodb]> show tables; +-------------------+ | Tables_in_hellodb | +-------------------+ | classes | | coc | | courses | | myisam_table | | scores | | students | | tb1 | | teachers | | toc | | v1 | +-------------------+ 10 rows in set (0.00 sec) #临时关闭记录二进制日志文件, MariaDB [hellodb]> set session sql_log_bin=0; Query OK, 0 rows affected (0.00 sec) #恢复从备份快照后到删除hellodb数据库之间的操作; MariaDB [hellodb]> source /tmp/b.sql; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Database changed Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Charset changed Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) #开启二进制记录文件; MariaDB [hellodb]> set session sql_log_bin=1; Query OK, 0 rows affected (0.00 sec) #可以发现myisqm_table表被删除了,还原成功; MariaDB [hellodb]> show tables; +-------------------+ | Tables_in_hellodb | +-------------------+ | classes | | coc | | courses | | scores | | students | | tb1 | | teachers | | toc | | v1 | +-------------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> \q Bye
至此,通过LVM逻辑卷进行数据库备份恢复的实验就完成了。