MariaDB备份与恢复

MariaDB备份与恢复

[toc]

本文基于马哥的linux运维课程视频, 结合自己在实验的过程中归纳整理所著, 在此致谢马哥!


基础概念

注意点:

  • (1) 做还原测试, 用于测试备份的可用性
  • (2) 还原演练

备份类型: 完全备份, 部分备份

热备份, 温备份, 冷备份:

  • 热备: 读写操作均可执行
  • 温备: 可读不可写
  • 冷备: 读写均不可

innodb支持热备, MyISAM支持温备, 不能热备

物理备份, 逻辑备份:

  • 物理备份: 直接复制数据文件进行备份 (占用更多空间但速度快, 不需要专用工具)
  • 逻辑备份: 从数据库中"导出"数据另存而进行的备份 (需要特定的客户端工具, 会丢失数据精度且可能更占用空间, 但与存储引擎无关)

备份时需要考虑的因素:

  • 持锁多久

  • 备份过程的时长

  • 备份时是否会增加线上负载

  • 恢复过程的时长

备份内容 (注意不要将备份内容和原始数据放在同一块硬盘中, 最好不同主机):

  • 数据
  • 二进制日志 (注意一定要记录正在使用的二进制日志的文件名及事件位置!), InnoDB的事务日志
  • 服务器的配置文件
  • 代码 (存储过程, 存储函数, 触发器, 事件调度器)

设计备份方案:

  • 物理备份还是逻辑备份?
  • 冷备还是热备?
  • 完全备份还是增量备份? 一般使用"完全 + 增量"的方式进行

备份工具:

  • mysqldump: 逻辑备份工具, 适用于所有存储引擎, 支持温备但不支持热备, 支持完全备份和部分备份, 对InnoDB存储引擎支持热备
  • cp, tar等复制归档工具: 物理备份工具, 适用于所有存储引擎, 但只能进行冷备, 支持完全备份和部分备份
  • lvm的快照: 几乎热备 (请求施加一个全局读锁, 待持锁成功后立即拍快照, 然后释放锁, 一般请求迅速时1s - 5s即可), 需要借助文件系统管理工具进行备份
  • mysqlhotcopy: 几乎冷备, 仅适用于MyISAM存储引擎

备份工具的选择:

  • mysqldump + 复制binlog

    • 先通过mysqldump做完全备份, 再复制binlog中指定时间范围的event (增量备份)
    • 时间慢但可远程备份
  • lvm2快照 + 复制binlog

    • 先使用cp或tar等做物理备份 (完全备份), 再复制binlog中指定时间范围的event (增量备份)
  • xtrabackup

    • 开源, 由Percona提供的支持对InnoDB做热备(物理备份)的工具
    • 支持完全备份和增量备份

备份和恢复

1. 逻辑备份工具: mysqldump, mydumper, phpMyAdmin

  • 原理: 将Schema和和数据存储在一起, 导出一个巨大的SQL语句, 是一个巨大的备份文件, 这个文件比较小的时候可直接使用cat等命令查看
  • mysqldump: 客户端命令, 通过mysql协议了解至mysqld服务器
mysqldump [options] [db_name [tbl_name ...]]

shell> mysqldump [options] db_name [tbl_name ...] # 不会自动创建database语句
shell> mysqldump [options] --databases db_name ... # 会自动创建database语句
shell> mysqldump [options] --all-databases # 会自动创建database语句
mysqldump -uroot --databases hellodb mydb > /tmp/alldb_bak.sql

# 特别注意!
# MyISAM: 支持温备, 因此需要先锁定备份库, 然后启动备份操作
# 锁定方法:
    --lock-all-tables, -x # 备份前锁定所有数据库中所有表, 用于备份整个数据库, 使用此选项一定要慎重! 
    --lock-tables, -l # 备份前锁定要备份的那个库的所有表, 用于备份单个数据库
    # 对InnoDB一样生效, 但只能实现温备

# InnoDB: 支持热备
    --single-transaction # 启动一个巨大的事务

# 其它选项:
    -E, --events # 备份与指定数据库相关的所有事件调度器
    --routines, -R # 备份与指定数据库相关的所有存储过程或存储函数
    --triggers # 备份与指定数据库相关的所有触发器, 默认启用
    --master-data[=value] # 值可设定为0/1/2等, 记录正在使用的二进制日志的文件名及事件位置, 当值设为2时, 会保存一个已被注释的CHANGE MASTER TO语句, 此语句记录了开始被备份时事件处于哪个二进制文件的哪个position, 此position之前的内容会被备份
        # 0: 不启用
        # 1: 记录为CHANGE MASTER TO语句, 此语句不被注释
        # 2: 记录为CHANGE MASTER TO语句, 此语句被注释
    # -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=245;
    --flush-logs # 锁定表完成后, 执行FLUSH LOGS命令, 对二进制日志进行日志滚动操作

1.1 mysql备份与结合二进制日志做时间点还原

注意还原时会产生大量的二进制日志, 而这些日志是我们不需要的, 此时最好关闭二进制日志的记录功能: SET sql_log_bin=OFFSET sql_log_bin=0, 等待还原完成后再开启此功能: SET sql_log_bin=ON

需要的文件:

  • 全量备份后的all.sql文件
  • 所有的二进制日志文件
shell> mysqldump -uroot --master-data=2 --all-databases --lock-all-tables > all.sql # 再次强调, 使用--lock-all-tables选项一定要慎重!
shell > mysql -uroot -p # 先对数据库中某些表进行一些操作后, 假如此时服务器正好宕机, 接下来就需要恢复数据
shell> less all.sql # 查看日志文件从什么位置开始备份, 假如MASTER_LOG_POS=245, 也就是说245之前的内容已经被备份, 而245之后的数据只有二进制日志中有SQL记录, 而需要恢复成宕机前但数据已经过修改的样子, 就需要从二进制日志中导出备份后数据库执行的SQL语句
shell> mysqlbinlog --start-position=245 mysql-bin.000002 > incre.sql
shell> mysql -uroot -p < all.sql # 先还原备份时数据库的数据
shell> mysql -uroot -p < incre.sql # 在还原备份后数据库被修改的数据

生产环境中如果数据量不大, 可以使用mysqldump每周做一次全量备份, 每半天(或者每一天)通过复制二进制文件做一次增量备份(先FLUSH LOGS, 然后将中间的二进制日志文件复制出来), 之后如果数据库宕机, 恢复数据就可以先恢复全量数据, 然后再依次恢复每半天(或者每一天)的增量数据就可以了.

# 实例:

# 0. 连入数据库查看此时使用的二进制日志文件
SHOW BINARY LOGS;
SHOW MASTER STATUS; # 假如此时正在使用的二进制日志文件是mysql-bin.000005

# 1. 先做全量备份
mysqldump -uroot -predhat --master-data=2 --all-databases --lock-all-tables --flush-logs > all.sql
    # 1.1 查看备份的起始position
less all.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=245; 
    # 1.2 连入数据库查看此时使用的二进制日志文件
SHOW MASTER LOGS; # 假如此时正在使用的二进制日志文件是mysql-bin.000006, 此文件恰好就是全量备份后数据库使用的二进制日志文件

# 2. 连入数据库做一些操作, 如插入一条数据, 然后再做增量备份
mysqldump -uroot -p
USE testdb;
INSERT INTO mytbl1 (name,gender) VALUES ('incre1','M'); 
FLUSH LOGS; # 特别注意一定要做滚动日志的操作!
SHOW MASTER STATUS; # 假如日志滚动后正在使用的二进制日志文件由mysql-bin.000006变为mysql-bin.000007, 说明mysql-bin.000006记录的就是第一次增量备份所需要使用的二进制日志文件
\q # 退出数据库并将mysql-bin.000006备份到其他磁盘

# 接下来还原数据
# 3. 还原全量数据
mysql -uroot -predhat < all.sql
# 4. 先将mysql-bin.000006中记录下的SQL语句导出(注意筛选出start-position为245之后的SQL), 然后再还原第一次增量数据
mysqlbinlog --start-position=245 mysql-bin.000006 > incre1.sql
mysql -uroot -predhat < incre1.sql

2. 基于lvm2备份和还原

2.1 备份

# 注意修改/etc/my.cnf的配置文件, 将mysql的datadir目录指向逻辑卷所在目录

# (1) 请求锁定所有表
mysql> FLUSH TABLES WITH READ LOCK; # 将内存中所有表的数据同步到磁盘, 然后施加读锁
    # 此时数据库中有人正在执行大事务, 此事务无法被锁定, 需要等待事务执行完才能施加读锁

# (2) 记录二进制日志文件及事件位置
mysql> FLUSH LOGS;
mysql> SHOW MASTER LOGS;
    # 也可以不登录数据库, 直接要把结果记录下来
mysql -e 'FLUSH LOGS'
mysql -e 'SHOW MASTER STATUS' > /PATH/TO/RECORD.FILE # 加入此时正在使用的二进制改为mysql-bin.000004

# (3) 逻辑卷创建快照
# 创建的快照大小根据实际的增量数据大小而定
lvcreate -L 1G --snap-shot -n lv1-snap -p r /dev/vg1/lv1
    # 创建完快照后一定要挂载测试, 因为创建的快照可能有问题! 文件系统为xfs的快照在挂载时可能有问题!
mkdir /mnt/snap
mount /dev/vg1/lv1-snap /mnt/snap/
umount /mnt/snap/

# (4) 拍完快照后记得释放锁, 否则线上业务会受到很大影响!
mysql> UNLOCK TABLES;

# (5) 对数据库做一些操作
mysql> DROP DATABASE testdb;

# (6) 挂载快照并将快照中的数据复制到其他硬盘或其他主机中
mount -r /dev/vg1/lv1 /mnt/
scp /mnt/data 192.168.30.10:/bak_data/

# (7) 备份完成后删除快照
lvremove /dev/vg1/lv1-snap

# (8) 制定好策略, 通过原卷备份二进制日志
scp /var/log/mariadb/mysql-bin.* 192.168.30.10:/bak_data/

2.2 还原

# 1. 把数据文件和二进制文件分别放在my.cnf中二进制文件和数据文件指定的目录下, 注意修改至mysql:mysql权限, 否则mariadb服务无法读取文件中的内容
chown -R mysql:mysql /mnt/mysql
chown -R mysql:mysql /var/log/maraidb/

# 2. 接下来还原
mysqlbinlog mysql-bin.000004 > incre.sql
mysql -uroot < incre.sql

3. xtrabackup

  • 通过mysql协议链接至mysql数据库, 因此必须online备份
  • 仅对InnoDB存储引擎支持热备(完全备份和增量备份), 对MyISAM只支持温备而且不支持增量备份
  • 使用xtrabackup之前必须先在/etc/my.cnf的[mysqld]或[mysqld_safe]配置段开启一个参数: innodb_file_per_table=ON, 如果此参数没有开启, 很多备份的高级功能将无法使用, 开启后可在数据库中查看:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'innodb_file%';
+--------------------------+----------+
| Variable_name            | Value    |
+--------------------------+----------+
| innodb_file_format       | Antelope |
| innodb_file_format_check | ON       |
| innodb_file_format_max   | Antelope |
| innodb_file_per_table    | OFF      | # 此项配置在服务启动前就应该开启!
+--------------------------+----------+

3.1 使用xtrabackup做完全备份与还原

# 1. 安装, 支持windows和linux等平台, 下面以redhat7为例
yum -y install percona-xtrabackup

# 2. 完全备份
innobackup /PATH/TO/BACKUP_DIR

# 3. 整理备份数据
innobackup --apply-log /PATH/TO/BACKUP_DIR
    # --apply-log的作用在于回滚未提交的事务以及同步已提交的事务至数据文件中, 从而保持数据文件的一致性.
    # 不过完全备份中有大事务未完成, 而增量备份中才完成这个大事务时, --apply-log参数不能加!

# 3. 还原
    # 注意: 还原时不能启动mysql服务!
innobackup --copy-back /PATH/TO/BACKUP_DIR
chown -R mysql:mysql /PATH/TO/MYSQL_DATADIR
cat xtrabackup_checkpoints 
backup_type = full-prepared # 说明是做全量备份
from_lsn = 0
to_lsn = 1597945
last_lsn = 1597945
compact = 0
recover_binlog_info = 0
image-20191112152654110.png
MariaDB备份与恢复_第1张图片
image-20191112165542042.png
MariaDB备份与恢复_第2张图片
image-20191112165626031.png

3.2 使用xtrabackup做增量备份与还原

  • 增量备份仅能用于InnoDB或XtraDB表, 对于MyISAM表而言, 增量备份其实是完全备份
  • 增量备份要基于上一次的备份进行
innobackup --incremental /backup --increment-basedir=BASEDIR

cat xtrabackup_checkpoints
backup_type = incremental # 说明是增量备份
from_lsn = 1597945 # 上一次备份结束的日志序列号, 同时也是这一次开始增量备份的日志序列号
to_lsn = 1601588 # 本次结束的日志序列号
last_lsn = 1601588
compact = 0
recover_binlog_info = 0
# 1. 全量备份到/tmp/目录下
innobackup /tmp/ # 假设生成的全量备份目录名为/tmp/2019-11-12_21-56-49/

# 2. 基于全量备份进行第一次增量备份
innobackup --incremental /tmp/ --increment-basedir=/tmp/2019-11-12_21-56-49/ # 假设生成的第一次增量备份目录名为/tmp/2019-11-12_21-56-49/

# 增量备份的整理过程与全量备份的整理过程不同
# 3. 先基于全量备份做整理
innobackupex --apply-log --redo-only /tmp/2019-11-12_21-56-49/ --incremental-dir=/tmp/

# 4. 再基于第一次增量备份做整理
innobackupex --apply-log --redo-only /tmp/2019-11-12_21-56-49/ --incremental-dir=/tmp/2019-11-12_22-10-24/

# 可以看到整理后2019-11-12_21-56-49/xtrabackup_checkpoints文件中备份类型的值变为log-applied
cat 2019-11-12_21-56-49/xtrabackup_checkpoints
backup_type = log-applied
from_lsn = 0
to_lsn = 1601588
last_lsn = 1601588
compact = 0
recover_binlog_info = 0

# 5. 此时可以基于合并后的全量备份的进行还原
innobackup --copy-back /tmp/2019-11-12_21-56-49/
MariaDB备份与恢复_第3张图片
image-20191112165730297.png
MariaDB备份与恢复_第4张图片
image-20191112165828431.png

3.3 使用xtrabackup导入或导出单张表

前提条件:

  1. 需要"导出"表在创建之前, mysql服务器就启用了innodb_file_per_table选项
  2. "导入"表的服务器同时启用了innodb_file_per_tableinnodb_expand_import选项

MySQL 5.6 Innodb新特性之export/import 表文件

选项innodb_expand_import在某些新版的mysql中已改为innodb_import_table_from_xtrabackup, 关于innodb_expand_import以及导出单张表的percona官方详细说明: Expand Table Import

导入单张表的percona官方详细说明: Restoring Individual Tables

MariaDB备份与恢复_第5张图片
image-20191112165902354.png
# 1. 先做完全备份, 需要确保这次完全备份没有apply-log过
innobackup /tmp/ # 假如生成的完全备份目录名为/tmp/2019-11-13_00-11-49/

# 2. 在完全备份的基础上apply-log并export出每个innodb表的数据文件
innobackup --apply-log --export /tmp/2019-11-13_00-11-49/
# 此时去查看完全备份的每个数据库目录下, 会发现多了以.exp和.cfg结尾的文件
ll /tmp/2019-11-13_00-11-49/hellodb/
total 132
-rw-r-----. 1 root root    65 Nov 13 00:11 db.opt
-rw-r--r--. 1 root root   396 Nov 13 00:29 test.cfg
-rw-r--r--. 1 root root 16384 Nov 13 00:29 test.exp
-rw-r-----. 1 root root  8586 Nov 13 00:11 test.frm
-rw-r-----. 1 root root 98304 Nov 13 00:11 test.ibd

# 3. 将.exp和.ibd结尾的文件拷贝到需要恢复的数据库服务器上, 创建与原表结构相同的新表
mysql> CREATE TABLE hellodb.test (...) ENGINE=InnoDB;

# 4. 将此表的表空间删除
mysql> ALTER TABLE hellodb.test DISCARD TABLESPACE;

# 5. 将对应表的.ibd和.exp文件复制到新服务器的数据目录(注意修改权限), 然后导入
mysql> ALTER TABLE hellodb.test IMPORT TABLESPACE;

导入时报错: "ERROR 1030 (HY000): Got error -1 from storage engine", 在xtrabackup的man帮助里有关于这个问题及解决方法的详细说明:

Importing the Table
On the destination server running Percona Server with XtraDB and
innodb_import_table_from_xtrabackup option enabled, or MySQL 5.6, create
a table with the same structure, and then perform the following steps:

· Execute ALTER TABLE test.export_test DISCARD TABLESPACE;

· If you see the following message, then you must enable inn‐
odb_file_per_table and create the table again: ERROR 1030 (HY000):
Got error -1 from storage engine

· Copy the exported files to the test/ subdirectory of the destination
server's data directory

· Execute ALTER TABLE test.export_test IMPORT TABLESPACE;

The table should now be imported, and you should be able to SELECT from
it and see the imported data.

从man帮助中可以看出, 需要开启innodb_file_per_table选项并重新创建表, 然后复制导出的文件到指定的数据文件目录中, 重新导入表空间, 实测确实有效!

你可能感兴趣的:(MariaDB备份与恢复)