基于LVM实现MySQL几乎热备
几乎热备:
对mysql而言,我们如果想实现lvm方式创建快照,在快照创建那一刻,innodb的事物日志内容可能正在往磁盘上写,所以必须保证事物日志和数据文件必须在同一快照上,如果我们分别对问或路径创建快照,很有可能造成数据和时间点的不一致,因此就算备份出来也无法恢复
准备工作
将整个数据导出,以防万一,如果没有放在逻辑卷上,那么则将数据导出备份并删除数据目录,使用lvm方式创建分区并古仔,将数据再覆盖至原先/mydata/data下 最后初始化数据库
创建lvm之前必须将mysql数据全部备份并在创建lvm之后对其恢复
[root@test ~]#mysqldump -uroot --lock-all-tables --all-databases --events > /tmp/alldb.sql
删除数据目录并创建逻辑卷
[root@test ~]#/etc/init.d/mysqld stop
Shutting downMySQL.. SUCCESS!
[root@test ~]# rm-fr /mydata/
首先进行分区,步骤略过
Device Boot Start End Blocks Id System
/dev/sdb1 1 393 3156741 8e Linux LVM
/dev/sdb2 394 786 3156772+ 8e Linux LVM
创建LVM
root@test ~]#pvcreate /dev/sdb
sdb sdb1 sdb2
[root@test ~]#pvcreate /dev/sdb{1,2}
Physical volume "/dev/sdb1"successfully created
Physical volume "/dev/sdb2"successfully created
[root@test ~]#vgcreate myvg /dev/sdb{1,2}
Volume group "myvg" successfullycreated
[root@test ~]#lvcreate -L 3G -n mydata myvg
Logical volume "mydata" created
[root@test ~]#mke2fs -t ext4 -L MYDATA /dev/
将lvm加入至开机启动项
[root@test ~]# echo'LABEL=MYDATA/mydata ext4 defaults0 0' >> /etc/fstab
[root@test ~]#mount -a
[root@test ~]# df-h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 6.3G 4.2G 1.8G 72% /
tmpfs 245M 0 245M 0% /dev/shm
/dev/sda1 194M 28M 156M 16% /boot
/dev/mapper/myvg-mydata
3.0G 69M 2.8G 3% /mydata
创建数据目录并重新赋值
[root@test ~]#mkdir /mydata/data/
[root@test ~]#chown mysql.mysql -R /mydata/
初始化并启动mysql
[root@test ~]# cd/usr/local/mysql
[root@test mysql]#scripts/mysql_install_db --user=mysql --datadir=/mydata/data/
[root@test mysql]#/etc/init.d/mysqld start
Starting MySQL....SUCCESS!
导入数据
首先我们要关闭binlog,使其恢复操作不记录在二进制日志文件里
mysql> setsession sql_log_bin=0;
Query OK, 0 rowsaffected (0.00 sec)
导入数据库
mysql> source/tmp/alldb.sql;
mysql> showdatabases;
+--------------------+
| Database |
+--------------------+
|information_schema |
| mydb |
| mysql |
|performance_schema |
| test |
| wpdb |
+--------------------+
6 rows in set (0.00sec)
此时我们的二进制日志文件可以开启了,因为是当前会话设置,可以直接退出在进入即可
mysql> setsession sql_log_bin=1;
Query OK, 0 rowsaffected (0.00 sec)
实现几乎热备
我们创建快照那一刻起必须保证数据没有被修改,所以想实现lvm备份必须打开一个远程mysql会话将所有表都锁定,并记录二进制的位置;
如果mysql数据库上正在执行一个事物的话,那么这个请求锁可能会等待一段时间,等待多久我们是未知的,有可能等待半个小时到一个小时也未可知,但步骤是不可少的。
一旦发现加锁成功,另启终端,使用lvcreate命令为数据所在的卷创建快照
对mysql而言,我们如果想实现lvm方式创建快照,在快照创建那一刻,innodb的事物日志内容可能正在往磁盘上写,所以必须保证事物日志和数据文件必须在同一快照上,如果我们分别对问或路径创建快照,很有可能造成数据和时间点的不一致,因此就算备份出来也无法恢复
快照大小规划思路
·在备份过程的这段时间,可能数据的变化量远远大于它,这是必然的
·假设我们备份时间需要2个小时,在2个小时之内数据变化量在50MB左右,那则给它200MB即可,如果在备份过程中数据量变化超出快照卷的量会导致快照卷崩溃,那么对于快照备份没有任何意义了
·指定大小必须确保快照卷和原卷要在同一个卷组内
·确保卷组有足够的空间可用
备份数据
[root@test ~]#lvcreate -L 100M -n mydata-snap -p r -s /dev/myvg/mydata
Logical volume "mydata-snap"created
在此瞬间完成之后,我们就可以进行释放表锁了
mysql> unlocktables;
Query OK, 0 rowsaffected (0.00 sec)
备份数据或使用tar/zip 打包
[root@test mydata]#cp -fra data/ /backup/2014-04-02/
注意事项:
一旦将数据恢复到数据目录下去启动数据的时候,那些在事物日志中的某些事物尚未提交或已经提交但尚未同步到磁盘中,那这时innodb存储引擎必须对其做一次从崩溃状态中恢复,会将在事物日志中尚未提交的时候回滚,将未同步至磁盘中的事物则进行同步操作
因为我们锁定所有表之后并不意味着事物日志中的所有数据都同步在磁盘中去了,所以一旦做了快照而有可能导致事物日志中出现以上两种问题,如果我们要对这部分做数据恢复的话,那么一定是会复制这些未同步的数据或未提交的事物,就算后续快照完之后都提交后也不行,类似于mysql服务器崩溃过一次,因此要从崩溃中恢复到正常以后才能恢复数据的,所以在cp或tar进行备份的时候要有一个恢复的过程
有时候我们是以root用户进行复制的,这就意味着我们备份的数据或打包数据后的文件属组是root而不再是mysql用户了
如果某个事物已经提交了,而且已经写入到事物日志里,但尚未同步到磁盘上,那么这时做了快照的话,如果二进制日志文件已经记录下来,如果没有记录事件提交,而等备份恢复以后可能会丢失事物,因此避免这种情况,我们备份的时候要调整几个属性信息:
sync_binlog=1; 任何事物提交立刻将事件同步到二进制日志文件,以避免事物丢失
启动mysql并实现几乎热备
首先必须确认事物日志必须跟数据在同一个lv
连接数据库
施加全局锁,将所有表的请求数据全部刷新至硬盘上,完后对其加全局锁
mysql> flushtables with read lock;
Query OK, 0 rowsaffected (0.00 sec)
过程可能会有很长时间,因为它会处理完请求并等待数据同步至磁盘,加锁之后一定不要退出,如果退出锁会被释放
记下二进制日志位置,对于后面恢复至关重要
[root@testmydata]# mysql -uroot -e 'show master status\G;' >/tmp/snapback_`date +%F`.txt
[root@test mydata]#cat /tmp/snapback_`date +%F`.txt
***************************1. row ***************************
File:mysql-bin.000004
Position: 107
Binlog_Do_DB:
Binlog_Ignore_DB:
创建快照卷
[root@test mydata]#lvcreate -L 100M -s -p r -n mydata_snap /dev/myvg/mydata
Logical volume "mydata_snap"created
查看快照卷
[root@test mydata]#ll /dev/myvg/
total 0
lrwxrwxrwx. 1 rootroot 7 Apr 3 00:22 mydata -> ../dm-0
lrwxrwxrwx. 1 rootroot 7 Apr 3 00:22 mydata_snap -> ../dm-4
创建完成,一创建完成我们就可以释放表锁
mysql> unlocktables;
Query OK, 0 rowsaffected (0.00 sec)
备份数据
可以手动去备份,如果需要的话可以将二进制日志也一起备份,或者二进制日志另外备份也可以
[root@test data]#mkdir -p /backup/snapback_$(date +%F)
[root@test data]#cp -fra * /backup/snapback_2014-04-03/
因为都是二进制文件所以压缩的意义不是非常大
我们对数据库进行简单写操作:
mysql> createtable testtb (id int,name char(20));
Query OK, 0 rowsaffected (0.47 sec)
mysql> insertinto testtb values (1,'xiaohong'),(2,'xiaoming');
Query OK, 2 rowsaffected (0.15 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> usemydb2;
Database changed
mysql> createtable tb1 (id int);
Query OK, 0 rowsaffected (0.07 sec)
mysql> insertinto tb1 values (1);
Query OK, 1 rowaffected (0.05 sec)
进行增量备份
之前备份过二进制日志
[root@test /]# cat/tmp/snapback_`date +%F`.txt
***************************1. row ***************************
File: mysql-bin.000004
Position: 107
Binlog_Do_DB:
Binlog_Ignore_DB:
从位置107开始,因此我们记住这个位置去读取mysql二进制文件并将其备份
[root@test /]# mysqlbinlog--start-position=107 /mydata/data/mysql-bin.000004 >/backup/snapback_incrementa/incrementa_$(date +%F).sql
让其数据库崩溃
删除数据库目录中的所有文件
[root@test mysql]#/etc/init.d/mysqld stop
[root@test data]#rm -fr *
[root@test data]#pwd
/mydata/data
现在数据库中空空如也
恢复快照
[root@test data]#cp -fra /backup/snapback_2014-04-03/* ./
[root@test data]#ll
total 30296
-rw-rw----. 1 mysqlmysql 18874368 Apr 2 23:54 ibdata1
-rw-rw----. 1 mysqlmysql 5242880 Apr 2 23:54 ib_logfile0
-rw-rw----. 1 mysqlmysql 5242880 Apr 2 23:19 ib_logfile1
drwx------. 2 mysqlmysql 4096 Apr 2 23:21 mydb
drwx------. 2 mysqlroot 4096 Apr 2 23:21 mysql
-rw-rw----. 1 mysqlmysql 27668 Apr 2 23:17 mysql-bin.000001
-rw-rw----. 1 mysqlmysql 1061358 Apr 2 23:17 mysql-bin.000002
-rw-rw----. 1 mysqlmysql 532317 Apr 2 23:54 mysql-bin.000003
-rw-rw----. 1 mysqlmysql 107 Apr 2 23:54 mysql-bin.000004
-rw-rw----. 1 mysqlmysql 76 Apr 2 23:54 mysql-bin.index
drwx------. 2 mysqlmysql 4096 Apr 2 23:17 performance_schema
drwx------. 2 mysqlroot 4096 Apr 2 23:16 test
-rw-r-----. 1 mysqlroot 3418 Apr 2 23:54 test.err
-rw-rw----. 1 mysqlmysql 5 Apr 2 23:54 test.pid
drwx------. 2 mysqlmysql 4096 Apr 2 23:21 wpdb
我们看到部分权限的属组还是root用户的,所以还需将其权限改为mysql
[root@test data]#chown -R mysql.mysql ./*
尝试启动mysql
[root@test data]# /etc/init.d/mysqldrestart
mysql> showtables;
+----------------+
| Tables_in_wpdb |
+----------------+
| students |
| tb3 |
+----------------+
2 rows in set (0.00sec)
之前我们创建的testtb表是不存在的,所以这时我们还需要使用增量备份
mysql> source/backup/snapback_incrementa/incrementa_2014-04-03.sql
mysql> showtables;
+----------------+
| Tables_in_wpdb |
+----------------+
| students |
| tb3 |
| testtb |
+----------------+
3 rows in set (0.00sec)
mysql> select *from testtb;
+------+----------+
| id | name |
+------+----------+
| 1 | xiaohong |
| 2 | xiaoming |
+------+----------+
2 rows in set (0.00sec)
数据已经恢复,最后将binlog功能开启
mysql> setsql_log_bin=1;
Query OK, 0 rowsaffected (0.00 sec)
恢复完成
不管是否有备份需求的时候我们一定要备份、记住二进制日志的事件的位置否则后续恢复将无法正常进行,哪怕是滚动后的日志也要将其记录。