18.12 基于LVM快照的MySQL数据库备份
MySQL数据库是现在网站中流行采用的后台数据库,在Web 2.0时代,网站的核心是数据库——几乎所有网站的内容都存放在数据库中,如果数据库不工作了那就意味着整个网站都无法访问了。
传统备份MySQL数据库的方式是在网站业务低谷时间段(一般是凌晨1~5点),使用mysqldump或mysqlhotcopy进行备份,这种方式往往会造成数据备份不一致的问题。比如说在数据库中存在表A和表B,它们之间存在某种一致性的依赖关系。在备份过程中,当备份工具完成了备份表A的备份之后,在备份表B时,可能A表记录已经发生了变化,这样的备份文件实际上是无法用于数据库恢复的。解决这个问题的方法是在整个备份过程中锁定表,直至备份结束,但这会影响网站的可用性,因为在数据库备份过程中由于数据库长时间被锁定而无法写入任何数据。
LVM的快照(snapshot)功能可以很好地解决这个问题。在对一个LV创建snapshot时,仅会复制其中的元数据,而不会有任何真实数据的复制,所以创建过程几乎是实时的。当原LV有写操作时,数据会写到快照中而不是原LV中(写时复制机制,Copy On Write,CoW),从而保证了原LV中数据的一致性。为了确保数据的一致(这里特指MySQL数据),在对其做快照之前也需要对数据库进行锁定操作,做完快照后再解除锁。由于快照的过程极为迅速,所以短时间的数据库锁定并不会对前台应用造成影响。
使用LVM的snapshot功能时特别需要注意的一点是,快照创建的大小必须考虑备份期间数据的变化量,如果数据变化量大于快照的大小则会造成快照损坏。所以建议在对特别重要的数据进行快照备份时,要让快照的大小必须至少等于原LV的大小。
图18-5 给虚拟机添加磁盘
当然,以上所述都是基于LVM的,使用这个功能的前提是MySQL数据库的数据文件必须存储在LV上,所以本实验需要先准备满足条件需求的环境。如果读者使用的是虚拟机环境,给虚拟机添加一块磁盘并启动(实验时可采用较小的5GB空间)。启动后使用fdisk查看到新添加的磁盘,将其所有空间创建成一个新的VG,并划出其中1GB作为MySQL数据库的新数据目录,如图18-5所示。
请读者参考以下步骤,使用LV替换默认的MySQL数据目录——这是使用快照备份数据库的前提,所以在生产环境规划中如果希望使用LVM的快照功能实现对MySQL的备份,也需要满足MySQL的数据目录是使用的逻辑卷。
#
发现新设备devsdb
[root@localhost ~]# fdisk -l Disk devsda: 5368 MB, 5368709120 bytes 255 heads, 63 sectors/track, 652 cylinders Units = cylinders of 16065 512 = 8225280 bytes Device Boot Start End Blocks Id System devsda1 1 13 104391 83 Linux devsda2 14 652 5132767+ 8e Linux LVM
Disk devsdb: 5368 MB, 5368709120 bytes 255 heads, 63 sectors/track, 652 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System #
创建PV
[root@localhost ~]# pvcreate MySQL_PV devsdb Device MySQL_PV not found (or ignored by filtering) Physical volume "devsdb" successfully created #
创建VG
[root@localhost ~]# vgcreate MySQL_VG devsdb Volume group "MySQL_VG" successfully created #
创建LV
[root@localhost ~]# lvcreate -L 1024M -n MySQL_LV MySQL_VG
Logical volume "MySQL_LV" created #
格式化挂载
[root@localhost ~]# mkfs.ext3 devMySQL_VG/MySQL_LV
mke2fs 1.39 (29-May-2006) Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2) 131072 inodes, 262144 blocks 13107 blocks (5.00%) reserved for the super user First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group 16384 inodes per group
Superblock backups stored on blocks: 32768, 98304, 163840, 229376
Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 20 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.
#
挂载LV
[root@localhost ~]# mount devMySQL_VG/MySQL_LV /mnt #
关闭MySQL
服务,将varlib/mysql/
中的数据全部复制到新创建的LV
中
[root@localhost ~]# service mysqld stop Stopping mysqld: [ OK ]
[root@localhost ~]# cp -a varlib/mysql/* /mnt #
将devMySQL_VG/MySQL_LV
重新mount
到varlib/mysql
,并启动MySQL
[root@localhost ~]# umount devMySQL_VG/MySQL_LV
[root@localhost ~]# mount devMySQL_VG/MySQL_LV varlib/mysql/
[root@localhost ~]# service mysqld start Starting mysqld: [ OK ]
#
最后不要忘了写/etc/fstab
文件,开机自动挂载该LV
到varlib/mysql
在给MySQL_LV做快照之前,先使用FLUSH TABLES和FLUSH TABLES WITH READ LOCK强行将所有OS的缓冲数据写入磁盘(类似于操作系统的sync命令),同时将数据库置为全局只读。快照完成之后,再使用UNLOCK TABLES解锁。然后只需要将快照进行挂载,复制其中的数据,在复制完成后删除该快照即可。示例如下:
- [root@localhost ~]# cat mysql_lvm01.sh #!/bin/bash
TIMESTAMP=`date +%Y%m%d%H%M%S`
HOSTNAME="localhost"
USERNAME="root"
PASSWORD="root"
MOUNT=/bin/mount
UMOUNT=/bin/umount
LVCREATE=/usr/sbin/lvcreate LVREMOVE=/usr/sbin/lvremove MYSQL=/usr/bin/mysql
TAR=/bin/tar
SNAP_SIZE=1024m
SNAP_MYSQL=SNAP_MySQL_LV
MOUNT_POINT=/mnt
EXEC_MySQL="
FLUSH TABLES;
FLUSH TABLES WITH READ LOCK; FLUSH LOGS;
\! $LVCREATE --snapshot --size=$SNAP_SIZE --name $SNAP_MYSQL devMySQL_VG/MySQL_LV
UNLOCK TABLES;"
echo "$EXEC_MySQL" | $MYSQL -u$USERNAME -p$PASSWORD -h$HOSTNAME
$MOUNT devMySQL_VG/$SNAP_MYSQL $MOUNT_POINT
cd /root
$TAR -zcvf ${TIMESTAMP}.tgz $MOUNT_POINT
$UMOUNT $MOUNT_POINT
$LVREMOVE -f devMySQL_VG/$SNAP_MYSQL