2.LVM 备份
LVM(Logical Volume Manager,逻辑卷管理器)是 Linux 环境下强大的存储管理工具,其备份主要基于 快照(Snapshot) 功能实现热备份(在线备份,即系统运行时备份),无需卸载文件系统。
2.1准备新磁盘 & 逻辑卷
不要用我们的系统磁盘,更安全。
在虚拟机去添加一块新磁盘
bash
[root@bogon ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 10G 0 disk #新加的磁盘
sr0 11:0 1 12.7G 0 rom /mnt
nvme0n1 259:0 0 200G 0 disk
├─nvme0n1p1 259:1 0 600M 0 part /boot/efi
├─nvme0n1p2 259:2 0 1G 0 part /boot
└─nvme0n1p3 259:3 0 198.4G 0 part
├─rhel-root 253:0 0 70G 0 lvm /
├─rhel-swap 253:1 0 2G 0 lvm
└─rhel-home 253:2 0 126.4G 0 lvm /home
bash
#创建卷组,物理卷会自动创建
[root@bogon ~]# vgcreate mysql /dev/sda
Volume group "mysql" successfully created
#创建逻辑卷
[root@bogon ~]# lvcreate -n lv_mysql -L 6G mysql
WARNING: xfs signature detected on /dev/mysql/lv_mysql at offset 0. Wipe it? [y/n]: y
Wiping xfs signature on /dev/mysql/lv_mysql.
Logical volume "lv_mysql" created.
#格式化
[root@bogon ~]# mkfs.xfs /dev/mysql/lv_mysql
[root@bogon ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 10G 0 disk
└─mysql-lv_mysql 253:3 0 6G 0 lvm #这里
sr0 11:0 1 12.7G 0 rom /mnt
nvme0n1 259:0 0 200G 0 disk
├─nvme0n1p1 259:1 0 600M 0 part /boot/efi
├─nvme0n1p2 259:2 0 1G 0 part /boot
└─nvme0n1p3 259:3 0 198.4G 0 part
├─rhel-root 253:0 0 70G 0 lvm /
├─rhel-swap 253:1 0 2G 0 lvm
└─rhel-home 253:2 0 126.4G 0 lvm /home
#挂载
2.2数据迁移
bash
[root@bogon ~]# systemctl stop mysqld
[root@bogon ~]# tar -zcf /tmp/mysql.tar.gz /var/lib/mysql/*
[root@bogon ~]# tar -tf /tmp/mysql.tar.gz #可以查看压缩包
[root@bogon ~]# mount /dev/mysql/lv_mysql /var/lib/mysql
[root@bogon ~]#
[root@bogon ~]# tar -zxf /tmp/mysql.tar.gz -C /
[root@bogon ~]# ll -d /var/lib/mysql
drwxr-xr-x. 9 root root 4096 Mar 31 16:13 /var/lib/mysql
[root@bogon ~]# ll /var/lib/mysql
total 90192
-rw-r-----. 1 mysql mysql 56 Mar 28 11:53 auto.cnf
-rw-r-----. 1 mysql mysql 4487 Mar 28 12:01 binlog.000001
-rw-r-----. 1 mysql mysql 181 Mar 28 14:21 binlog.000002
。。。。。。
[root@bogon ~]# chown -R mysql: /var/lib/mysql
[root@bogon ~]# systemctl start mysqld
1.解压那一步不要指定解压到/var/lib/mysql,因为压缩时,这个目录也同样压缩了。否则解压出来是/var/lib/mysql/var/lib/mysql/。。。
2.一定要先压缩再挂载最后解压
- 直接挂载 :新卷覆盖了目录,里面的数据是新卷自带的(可能是空的、旧的、或别的)
- 备份再解压 :先把旧数据打包保存,挂载新卷后,再把旧数据还原进去
3.在压缩前先暂停服务。停服务是为了保证数据一致性,避免备份/迁移过程中数据损坏。
4.关于权限问题,不仅要关注目录里面文件权限,也要关注目录本身的权限
2.3数据备份
大概步骤:
1)锁表 flush table with read lock
2)查看position号并记录,便于后期恢复 show master status
3)创建snapshot快照 create snapshop
4)解表 unlock tables
5)挂载snapshot
6)拷贝snapshot数据,进行备份。备份整个数据库之前,要关闭mysql服务(保护ibdata1文件)
7)卸载
8)移除快照
这里可以用shell脚本来做
bash
[root@bogon ~]# cat bak_mysql.sh
#!/bin/bash
bak_dir=/bak/$(date +%F)
[ -d ${bak_dir} ] || mkdir -p ${bak_dir}
echo "flush tables with read lock; system lvcreate -s -n lv_mysql_s -L 500M /dev/mysql/lv_mysql; unlock tables;" | mysql -uroot -p123456
[ -d /media/mysql/ ] || mkdir -p /media/mysql
mount -t xfs -o nouuid /dev/mysql/lv_mysql_s /media/mysql
#用 rsync 把快照里的数据同步到备份目录
rsync -az /media/mysql/ ${bak_dir}
if [ $? -eq 0 ]; then
umount /media/mysql/ && lvremove -f /dev/mysql/lv_mysql_s &> /dev/null
fi
[root@bogon ~]# bash bak_mysql.sh
[root@bogon ~]# ls /bak/2026-03-31
auto.cnf ca.pem ibdata1 mysql.sock school
binlog.000001 client-cert.pem '#innodb_redo' mysql.sock.lock server-cert.pem
binlog.000002 client-key.pem '#innodb_temp' mysql_upgrade_history server-key.pem
binlog.000003 '#ib_16384_0.dblwr' mydb performance_schema sys
binlog.index '#ib_16384_1.dblwr' mysql private_key.pem undo_001
ca-key.pem ib_buffer_pool mysql.ibd public_key.pem undo_002
rsync -az /media/mysql/ ${bak_dir}
这一步相当于rsync -az /media/mysql/ /bak/2026-03-31
/media/mysql/是/dev/mysql/lv_mysql_s快照中的数据,即逻辑卷的数据,即/var/lib/mysql的数据
用快照而不是直接挂载逻辑卷,主要是为了实现一致性备份。
为什么要弄一个/media/mysql,而不是直接将快照挂载到/bak/2026XXX...???
/bak/2026XXX是文件系统路径,不是挂载点简单类比:就像你要复制光盘里的文件到硬盘,需要先把光盘挂载到某个空目录,复制到目标文件夹,而不是直接把光盘挂载到目标文件夹。
但是我的/bak/2026XXX本来也是空的,专门用一个中转的区别在?这么做优点?
- 防止意外覆盖
如果/bak/2026XXX不小心非空了,直接挂载会隐藏原有文件。用固定空目录挂载,安全。- 脚本简单可靠
挂载点固定(/media/mysql),备份目录可变(/bak/日期)。逻辑解耦,不容易写错路径。- 支持并发备份
可以同时挂载多个快照到不同目录(/media/mysql1、/media/mysql2),同时备份到不同/bak/子目录。
2.4数据还原 & 验证
bash
#模拟数据被破坏
mysql> drop database mydb;
Query OK, 1 row affected (0.01 sec)
#停止mysqld服务
[root@bogon ~]# systemctl stop mysqld
#改数据目录为之前备份的目录
[root@bogon ~]# vim /etc/my.cnf
[root@bogon ~]# cat /etc/my.cnf | grep datadir=
#datadir=/var/lib/mysql
datadir=/bak/2026-03-31
#检查该目录本身及下面文件都是mysql用户
[root@bogon ~]# ll -d /bak/2026-03-31
drwxr-xr-x. 9 mysql mysql 4096 Mar 31 16:41 /bak/2026-03-31
[root@bogon ~]# ll /bak/2026-03-31
total 90204
-rw-r-----. 1 mysql mysql 56 Mar 28 11:53 auto.cnf
-rw-r-----. 1 mysql mysql 4487 Mar 28 12:01 binlog.000001
。。。。。。
#重启
[root@bogon ~]# systemctl restart mysqld
#检验
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |#又回来了
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
流程(原理):
删除数据库后,这个删除的日志记录在/var/lib/mysql下面(/etc/my.cnf中默认的数据路径)
这时候我们要停止服务,进入/etc/my.cnf中,修改datadir为删除前备份的目录
再重启,就相当于是用的删除前的日志,因此数据库恢复(存在)