Thu Oct 21 13:10:35 CST 2021 —— 记录下高光的删库瞬间,后面给恢复了



1. 什么是数据库备份

备份就是在数据库发生宕机的情况下保证数据不丢失,或者最小程度丢失的解决方法。Mysql 提供了 mysqldump、ibbackup、replication 工具来备份,当然也有第三方工具,如 xtrabacup、LVM快照等


1.1 备份分类

下面的备份分类中,并不是所有都适配了 Mysql 和 Innodb引擎,所以部分是没有真正的方案,也有些是交叉分类的(比如在热备又在逻辑文件中)

按备份类型:

  • 热备:在数据库运行过程中直接备份
  • 冷备:在数据库停止的情况下备份,一般直接复制相关的物理文件即可
  • 温备:在数据库运行过程中备份,但对数据库操作有影响,如加个全局读锁以保证备份数据一致性

按备份文件:

  • 逻辑文件:指备份出的文件可读,一般指 SQL 语句(适用库升级,迁移,但恢复时间较长需要执行 SQL 语句)
  • 物理文件:指复制数据库的物理文件

按备份内容:

  • 日志备份:主要备份 bin-log 日志,然后 replay 来完成 point-in-time
  • 完全备份:对数据库一个完整的备份
  • 增量备份:在上次完全备份的基础上对更改部分进行备份(MySQL 没真正的增量备份,一般通过 bin-log 完成,要借助第三方工具才能实现)



1.2 备份的一致性

数据库备份的一致性要求在备份的时候数据在这一时间点上是一致的,比如银行转账,A 转给 B 现金100 RMB,这个事务过程先扣 A 100元,再去 B 加100元,确保前后数据一致,否则会发生恢复数据后金钱对不上的情况

对于 Innodb 引擎来说,因为其支持 MVCC 功能,所以可以先开启一个事务,然后导出一组相关的表,最后提交来实现一致的备份,当然隔离级别要设置为 REPEATABLE READ

对于 mysqldump 备份工具可以添加 --single-transaction 选项来实现备份一致性(开启事务,设置隔离级别)

下面来说明备份的途径







2. mysqldump

mysqldump 是属于逻辑备份,也是最常见的备份工具了,缺点在于备份和恢复速度不是特别快


2.1 备份

$mysqldump [arguments] > dump.sql

--all-databases:备份所有数据库
--databases:备份指定数据库
--single-transaction:备份一致性
--add-drop-database:添加语句 DROP DATABASE IF EXISTS(默认是 CREATE DATABASE IF NOT EXISTS)
--hex-blob:binary、blog、bit是十六进制不可见,会以十六进制来展示



2.2 恢复

mysqldump 导出的是逻辑文件,即 SQL 语句,可以直接执行

  • source /home/mysql/backup.sql
  • mysql -uroot -p < backup.sql

mysqldump 导出不包括视图,所以得自己手动导出







3. bin-log

bin-log 是 Mysql 的日志文件


3.1 备份

先要在 my.cnf 中增加下面一句话,之后会自动记录,名字按 name.00001 格式来递增滚动

[mysqld]
# 不赋值默认为主机名
log-bin=my-binlog-name



3.2 恢复

使用 Mysql 自带的 mysqlbinlog 命令,其作用将二进制的记录转成可见的文本格式(即 SQL 语句),然后交给 mysql 执行可恢复数据

$mysqlbinlog [option] log_file
--start-position:指定某个偏移量来恢复
--stop-positon:指定某个偏移量来恢复

$mysqlbinlog binlog.000001 > backup.sql
$source backup.sql


在备份binlog之前,先 FLUSH LOGS,会自动滚动文件,备份滚动后的文件即可







4. 冷备

Innodb 冷备是最简单的,通常只需写个脚本来复制 MySQL 的文件,然后将这些文件放到对应数据库的目录下即可实现数据恢复:

  • .frm结构文件
  • .idb独立表空间文件
  • redo重做日志文件
  • 共享表空间文件
  • my.cnf配置文件

缺点是:冷备文件比逻辑文件大,因为存放了很多其他数据,而且不能轻易跨平台(SQL 是标准语句,可跨平台)


4.1 备份

首先关闭数据库,然后执行下面的命令

# 1. 查看mysql数据存放的目录
# /var/lib/mysql/data
$show variables like "%datadir%"

# 2. 备份物理文件
$cd /var/lib/mysql/
$tar -zcvf mysqlDataBacku.tar.gz data/



4.2 恢复

# 1. 恢复只需将上面的包解压到对应数据库的数据存放目录下
# 2. 恢复前将原数据备份一下
# 3. 重启mysql即可
$cd /var/lib/mysql/
$mv data/ data_20211027/
$tar -zxvf mysqlDataBacku.tar.gz







5. XtraBackup

Innodb 官方有提供热备工具 ibbackup 的收费软件。不过可以借用 XtraBackup 开源的热备工具,备份和恢复速度比 mysqldump 快,具体的安装过程这里不说明了


5.1 全量备份

# 1. 备份
$innobackupex
--defaults-file=/etc/my.cnf # 有数据存放地址
--user=root
--password="123456"
--databases=test
--backup /mysqlBackup/ # 目录下生成日期命名的目录

# 2. 备份一致性,回滚未提交的事务及同步已经提交的事务至数据文件使数据文件处于一致性
$innobackupex
--apply-log /mysqlBackup/2021-10-27_20-09-29/

# 3. 恢复,要保证原数据目录是空的,因为目录里有binlog日志
$innobackupex
--defaults-file=/etc/my.cnf
--copy-back /mysqlBackup/2021-10-27_20-09-29/



5.2 增量备份

当数据量比较大的时候(10G),每次都全量备份不太实际,可采用周末全量备份,其余时间增量备份的策略

原理:

  • 首先执行完全备份,并记录下此时检查点 LSN
  • 随后的增量备份中,比较表空间每页 LSN 是否大于上次备份的检查点 LSN,是则备份该页并更新当前检查点 LSN


# 1. 先做一次全量备份,不指定数据库
$innobackupex
--defaults-file=/etc/my.cnf
--user=root
--password="123456"
--backup /mysqlBackup/

# 2. 增量备份
$innobackupex
--defaults-file=/etc/my.cnf
--user=root
--password=123456
--incremental /backup/ # 增量备份文件目录
--incremental-basedir=/mysqlBackup/2021-10-27_20-09-29/ # 上次全备或增量备份的目录


# 3. 恢复,保证原数据目录为空
$innobackupex
--apply-log /mysqlBackup/2021-10-27_20-09-29/
--incremental-dir=/mysqlBackup/2021-10-28_20-09-29/







6. LVM

Mysql 本身不知道 LVM 快照功能,而是通过文件系统来实现的。备份的前提是所以数据库文件放入同一个文件分区中,然后通过命令 lvcreate 来创建一个快照,需要恢复时将这个还原到这个快照即可,采用了写时复制的策略

MySQL的数据备份与恢复_增量备份





7. 备份脚本

#!/bin/bash

#保存备份个数,备份31天数据
number=31

#备份保存路径
backup_dir=/root/mysqlbackup

#日期
dd=`date +%Y-%m-%d-%H-%M-%S`

#备份工具
tool=mysqldump

#用户名
username=root

#密码
password=TankB214

#将要备份的数据库
database_name=edoctor

#如果文件夹不存在则创建
if [ ! -d $backup_dir ];
then
mkdir -p $backup_dir;
fi

#简单写法 mysqldump -u root -p123456 users > /root/mysqlbackup/users-$filename.sql
$tool -u $username -p$password $database_name > $backup_dir/$database_name-$dd.sql

#写创建备份日志
echo "create $backup_dir/$database_name-$dd.dupm" >> $backup_dir/log.txt

#找出需要删除的备份
delfile=`ls -l -crt $backup_dir/*.sql | awk '{print $9 }' | head -1`

#判断现在的备份数量是否大于$number
count=`ls -l -crt $backup_dir/*.sql | awk '{print $9 }' | wc -l`

if [ $count -gt $number ]
then
#删除最早生成的备份,只保留number数量的备份
rm $delfile
#写删除文件日志
echo "delete $delfile" >> $backup_dir/log.txt
fi







参考:

《MySQL技术内幕 InnoDB存储引擎》