Percona Xtrabackup(简称PXB)是一个用于MySQL的开源热备份工具,通过拷贝服务器本地的数据文件进行备份。

官网地址:https://www.percona.com

注意:命令innobackupex和xtrabackup 的区别

特性 innobackupex xtrabackup
支持的存储引擎 InnoDB、XtraDB、MyISAM InnoDB 和 XtraDB
操作级别 xtrabackup的高级封装,使用方便 低级别操作,需要更复杂配置
适合版本 v56、v57 v80
安装包 percona-xtrabackup-24-2.4.20-1.el7.x86_64.rpm percona-xtrabackup-80-8.0.27-19.2.el7.x86_64.rpm
主程序 innobackupex、xtraback xtrabackup

1、PXB工作原理

01、备份InnoDB表

热备,不锁表

1、备份时,首先触发CKPT,将脏页刷写到磁盘,并记录一个LSN编号
2、拷贝InnoDB表相关的文件
3、将备份过程中产生的redo也备份,并记录LSN编号
4、将二进制日志、Position记录下来
5、恢复时:PXB模拟InnoDB存储引擎的CR过程,将数据和redo的LSN追平,然后进行一致性恢复,直接拷贝回MySQL目录即可

02、备份非InnoDB表

温备,短暂锁表,对业务有一定的影响

1、加全局读锁(FTWRL),而后触发刷写脏页,将已提交的数据页刷写到磁盘,并记录一个LSN编号;
2、拷贝非InnoDB表文件
3、拷贝数据完成后解锁
4、将二进制日志、Position记录下来
5、将所有备份文件统一存放在一个目录下

2、工具:innobackupex

01、安装innobackupex

# 【v56、57】
yum -y install percona-xtrabackup-24-2.4.20-1.el7.x86_64.rpm

【innobackex 常用选项】
--host                      # 数据库服务器IP
--port                      # 数据库服务端口
--socket                    # 套接字文件
--no-timestamp              # 阻止自动创建时间戳的目录
--defaults-files            # 指定其他配置文件,默认是/etc/my.cnf(使用时,必须放在所有参数最前面)
--incremental               # 开启增备
--incremental-basedir       # 基于哪个备份做增量
--incremental-dir           # 恢复时,指定哪个备份整理到全备
--apply-log                 # 应用xtrabackup_logfile,模拟CR,重做(redo)已提交事务,回滚(undo)未提交事务
--redo-only                 # 只做(redo)已提交事务(模拟CR前滚,追平redo的LSN),不做undo回滚
--use-memory                # 在准备阶段,提供内存以加速处理,默认100M
--compact                   # 压缩备份
--stream={tar|xbstream}     # 对备份的数据流式化处理
--copy-back                 # 恢复备份至数据库服务器的数据目录

02、全备和恢复

# 1、全备命令
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp /backup/mysql/pxb/full

# 2、恢复数据
# 1)整理全备文件
innobackupex --apply-log /backup/mysql/pxb/full		# --apply-log手动模拟CR,重做redo,回滚undo

# 2)将备份恢复到MySQL数据目录
/etc/init.d/mysqld stop								# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old							# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 		# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*							# 2)被恢复的目录必须是空的
innobackupex --copy-back /backup/mysql/pxb/full		# 拷贝备份到数据目录
chown -R mysql.mysql /data/mysql/data				# 修改数据权限
/etc/init.d/mysqld start							# 启动服务

03、增备和恢复

增备:基于上次备份做备份,上次备份可能是全备或增备

# 1、全备命令
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp /backup/mysql/pxb/full

# 2、增备命令
# 第1次增备:基于全备做第1次增备
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp \
--incremental --incremental-basedir=/backup/mysql/pxb/full /backup/mysql/pxb/inc1

# 第2次增备:基于第1次增备做第2次增备
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp \
--incremental --incremental-basedir=/backup/mysql/pxb/inc1 /backup/mysql/pxb/inc2

以此类推...
【恢复思路】
1)整理全备full
2)合并第1次增备inc1到全备full
3)合并第2次增备inc2到全备full
4)以此类推
5)最后再次整理全备full
6)将全备文件恢复到MySQL数据目录


# 3、恢复数据
# 1)整理全备full,只做redo,不做undo
innobackupex --apply-log --redo-only /backup/mysql/pxb/full
# --apply-log     # 模拟CR,将redo和undo都做一次
# --read-noly     # 只做redo,不做undo回滚;
【在整理全备、合并所有增备到全备(除了最后一次合并增备到全备、最后一次整理full),其他都需要加此参数。这样可以防止"last_lsn"值发生变化。】

# 2)合并第1次增备inc1到全备full
innobackupex --apply-log --redo-only --incremental-dir=/backup/mysql/pxb/inc1 /backup/mysql/pxb/full

# 3)合并第2次增备inc2到全备full
innobackupex --apply-log --incremental-dir=/backup/mysql/pxb/inc2 /backup/mysql/pxb/full

# 4)最后一次整理full
innobackupex --apply-log /backup/mysql/pxb/full

# 5)将备份恢复到MySQL数据目录
/etc/init.d/mysqld stop							# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old						# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 	# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*						# 2)被恢复的目录必须是空的
innobackupex --copy-back /backup/mysql/pxb/full	# 拷贝备份到数据目录
chown -R mysql.mysql /data/mysql/data			# 修改数据权限
/etc/init.d/mysqld start						# 启动服务

binlog截取部分省略...

04、差异备份和恢复

差异备份:每次备份都是基于上次全备做备份,备份上次全备以来发变化的数据

使用增备的命令备份

# 1、全备命令
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp /backup/mysql/pxb/full

# 2、差异备份命令
innobackupex --user=athos --password=123qwe --socket=/tmp/mysql.sock --no-timestamp \
--incremental --incremental-basedir=/backup/mysql/pxb/full /backup/mysql/pxb/add1

# 3、恢复
# 1)整理全备full,只做redo,不做undo
innobackupex --apply-log --redo-only /backup/mysql/pxb/full

# 2)合并差异备份add1到全备full
innobackupex --apply-log --incremental-dir=/backup/mysql/pxb/full /backup/mysql/pxb/full

# 3)最后一次整理full
innobackupex --apply-log /backup/mysql/pxb/full

# 4)将备份恢复到MySQL数据目录
/etc/init.d/mysqld stop							# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old						# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 	# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*						# 2)被恢复的目录必须是空的
innobackupex --copy-back /backup/mysql/pxb/full	# 拷贝备份到数据目录
chown -R mysql.mysql /data/mysql/data			# 修改数据权限
/etc/init.d/mysqld start						# 启动服务

3、PXB备份产生的文件

01、xtrabackup_checkpoints

记录LSN号,用于衔接全备和增备,判断是否备份成功?

上一次备份的to_lsn位置,就是下一次备份的from_lsn

[root@db01 full]# cat xtrabackup_checkpoints 
backup_type = full-backuped		# 备份类型:全备
from_lsn = 0					# 全备的起始点为0
to_lsn = 290009666				# 备份的结束LSN
last_lsn = 291986857			# 备份完成时记录的最后一个LSN(通常与 to_lsn 值相近,但可能稍大,因为备份结束后数据库还在运行。)
compact = 0						# 是否使用压缩备份,0=未启用,1=启用
recover_binlog_info = 0			# 是否记录了恢复所需的二进制日志信息,0=未启用,1=启用
flushed_lsn = 291962248			# 这是已刷新到磁盘的最后一个LSN

02、xtrabackup_binlog_info

记录备份完成时刻的binlog和pos,可以用于截取binlog的起点。

[root@db01 full]# cat xtrabackup_binlog_info 
mysql-bin.000001        85700808

4、工具:xtrabackup

对于v80版本,由于默认存储引擎为InnoDB,淘汰了MyISAM。所以备份工具innobackup遭到了废弃,也只能使用xtrabackup了。

01、安装xtrabackup

# 【v80】
yum -y install percona-xtrabackup-80-8.0.27-19.2.el7.x86_64.rpm

【常用选项】
--backup 				# 备份命令
--compress				# 压缩
--decompress 			# 解压,需要安装单独程序进行解压(qpress)
--copy-back 			# 恢复备份
--target-dir			# 指定备份目录
--incremental-dir		# 指定增量备份
--prepare				# 整理数据

02、全备和恢复

mkdir -p /backup/mysql/pxb/full

# 1、全备命令
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/full

# 2、恢复数据
# 1)整理数据
xtrabackup --prepare --target-dir=/backup/mysql/pxb/full

# 2)清理mysql数据目录
/etc/init.d/mysqld stop							# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old						# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 	# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*						# 2)被恢复的目录必须是空的

# 3)恢复数据到MySQL数据目录
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --copy-back --target-dir=/backup/mysql/pxb/full

# 4)修改权限、重启服务
chown -R mysql.mysql /data/mysql/data
/etc/init.d/mysqld start

02、增备和恢复

mkdir -p /backup/mysql/pxb/full

# 1、全备命令
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/full

# 2、增备命令
# 第1次增备:基于全备做第1次增备
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/inc1 --incremental-basedir=/backup/mysql/pxb/full

# 第1次增备:基于全备做第1次增备
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/inc2 --incremental-basedir=/backup/mysql/pxb/inc1

以此类推...
【恢复思路】
1)整理全备full
2)合并第1次增备inc1到全备full
3)合并第2次增备inc2到全备full
4)以此类推
5)将全备文件恢复到MySQL数据目录
6)重启服务

# 1、整理full
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/pxb/full

# 2、整理合并第1次增备inc1到全备full
xtrabackup --prepare --apply-log-only --incremental-dir=/backup/mysql/pxb/inc1 --target-dir=/backup/mysql/pxb/full 

# 3、整理合并第2次增备inc2到全备full
xtrabackup --prepare --incremental-dir=/backup/mysql/pxb/inc2 --target-dir=/backup/mysql/pxb/full


# 4、清理mysql数据目录
/etc/init.d/mysqld stop							# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old						# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 	# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*						# 2)被恢复的目录必须是空的

# 5、恢复数据到MySQL数据目录
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --copy-back --target-dir=/backup/mysql/pxb/full

# 6、修改权限、重启服务
chown -R mysql.mysql /data/mysql/data
/etc/init.d/mysqld start

03、差异备份和恢复

# 1、全备命令
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/full

# 2、差异备份命令
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --socket=/tmp/mysql.sock \
--backup --target-dir=/backup/mysql/pxb/add1 --incremental-basedir=/backup/mysql/pxb/full

# 3、恢复命令
# 1)整理全备
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/pxb/full

# 2)整理合并差异备份add1到全备full
xtrabackup --prepare --incremental-dir=/backup/mysql/pxb/add1 --target-dir=/backup/mysql/pxb/full 

# 3)清理mysql数据目录
/etc/init.d/mysqld stop							# 1)停数据库服务,必须是停止状态
mkdir -p /data/mysql/old						# 创建目录用于存放数据目录下的文件
\cp -ra /data/mysql/data/* /data/mysql/old/ 	# 备份数据目录下文件(防止二次破坏)
rm -rf /data/mysql/data/*						# 2)被恢复的目录必须是空的

# 4)恢复数据到MySQL数据目录
xtrabackup --defaults-file=/etc/my.cnf --user=athos --password=123qwe --copy-back --target-dir=/backup/mysql/pxb/full

# 5)修改权限、重启服务
chown -R mysql.mysql /data/mysql/data
/etc/init.d/mysqld start

备份和恢复案例:v57备份和恢复案例

# 背景:备份时间全部都是每天凌晨的02:00
2023-11-16 周天:全备
2023-11-17 周一:增备
2023-11-18 周二:增备
2023-11-19 周三:增备		上午10:30误删库

# 1)模拟初始数据:
create database db01;
use db01;
create table tb01 (id int, name varchar(20));
insert into tb01 values (1,'athos');
insert into tb01 values (2,'masiu');

# 2)周天 2023-11-16 全备
innobackupex --defauls-file=/etc/my.cnf --user=root --password=123qwe --port=3306 --socket=/tmp/mysql.sock --no-timestamp /data/backup/pxb/full_`date +%F`

# 模拟插入数据
insert into db01.tb01 values (3,'alice');

# 3)周一 2023-11-17 增备
innobackupex --incremental --user=root --password=123qwe --socket=/tmp/mysql.sock --no-timestamp --incremental-basedir=/data/backup/pxb/full_2023-11-16 /data/backup/pxb/inc1_`date +%F`

# 模拟插入数据
insert into db01.tb01 values (4,'bob'); 

# 4)周二 2023-11-18 增备
innobackupex --incremental --user=root --password=123qwe --socket=/tmp/mysql.sock --no-timestamp --incremental-basedir=/data/backup/pxb/inc1_2023-11-17 /data/backup/pxb/inc2_`date +%F`

# 模拟插入数据
insert into db01.tb01 values (5,'nike');  

# 5)周三2023-11-19:增备
innobackupex --incremental --user=root --password=123qwe --port=3306 --socket=/tmp/mysql.sock --no-timestamp --incremental-basedir=/data/backup/pxb/inc2_2023-11-18 /data/backup/pxb/inc3_`date +%F`

# 模拟插入数据
insert into db01.tb01 values (6.'dany');

# 模拟删库
drop database db01;



## 恢复思路:
1)停业务,挂维护页。
2)整理恢复所有备份:全备 + 所有增备
3)截取binlog:
    - 起点:最近一次增备中xtrabackup_binlog_info中的位置
    - 终点:截止删库前的操作
4)恢复binlog
5)启服务,撤维护页。



处理步骤:
# 1)整理全备
innobackupex --apply-log --redo-only /data/backup/pxb/full_2023-11-16

# 2)合并增备到全备
innobackupex --apply-log --redo-only --incremental-dir=/data/backup/pxb/inc1_2023-11-17 /data/backup/pxb/full_2023-11-16
innobackupex --apply-log --redo-only --incremental-dir=/data/backup/pxb/inc2_2023-11-18 /data/backup/pxb/full_2023-11-16
innobackupex --apply-log --incremental-dir=/data/backup/pxb/inc3_2023-11-19 /data/backup/pxb/full_2023-11-16

# 3)最后一次整理全备
innobackupex --apply-log /data/backup/pxb/full_2023-11-16

# 4)恢复数据
cp -rf /data/backup/pxb/full_2023-11-16 /data/mysql/data/
chown -R mysql.mysql /data/mysql/data


# 5) 截取binlog
# 确定起点:
cat /data/backup/pxb/inc3_2023-11-19/xtrabackup_binlog_info
mysql-bin.000007        2639

# 确定终点:
mysqlbinlog /data/mysql3306/logs/mysql-bin.000007 | grep -a3 'drop database' 
#231116 11:03:02 server id 1  end_log_pos 2959 CRC32 0xd3162bb2         Anonymous_GTID  last_committed=12       sequence_number=13      rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 2959
#231116 11:03:02 server id 1  end_log_pos 3051 CRC32 0x7ade3584         Query   thread_id=17    exec_time=0     error_code=0
SET TIMESTAMP=1700150582/*!*/;
drop database db01
/*!*/;
# at 3051
#231116 11:32:05 server id 1  end_log_pos 3074 CRC32 0x3aa4a537         Stop
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;

# 截取binlog
mysqlbinlog --start-position=2639 --stop-position=2959 /data/mysql3306/logs/mysql-bin.000007 > /data/backup/pxb/bin.sql

# 导入数据
/etc/init.d/mysqld start 
mysql -uroot -p 
mysql> set sql_log_bin=0;
mysql> source /data/backup/pxb/bin.sql
mysql> set sql_log_bin=1;

# 检查数据,启业务