MySQL进阶-6-数据库的备份与恢复

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

(⾯试题)

  1. 知道MySQL有哪些⽇志吗?

  2. 介绍⼀下MySQL⽇志的作⽤是什么?

  3. ⼆进制⽇志的作⽤是什么?

  4. 如何开启⼆进制⽇志?

  5. ⼆进制⽇志常⻅的配置选项都有哪些?

  6. ⼆进制⽇志的刷盘策略有⼏种?说⼀下它们的区别?

  7. 如何查看⼆进制⽇志?

  8. 了解数据库备份吗?

  9. 数据库备份的分类有哪些?

  10. 什么是逻辑备份和物理备份?

  11. 什么是冷备、热备和温备?

  12. 什么是全量备份和增量备份?

  13. 进⾏数据库备份时应注意什么?

  14. mysqldump⽤过吗?

  15. 介绍⼀下mysqldump的应⽤场景和使⽤⽅法?

  16. 使⽤mysqldump进⾏数据备份时会出现数据⼀致问题吗?如何解决?

  17. 如果让你执⾏数据库备份,说⼀下从开始准备到备份结束的完整流程或者进⾏哪些操作?

  18. MySQL中如何进⾏备份数据导⼊?

  19. 还了解关于MySQL的其他的备份⽅式吗?

  20. Xtrabackup⼯具⽤过吗?介绍下它的特点?

  21. 如何通过Xtrabackup进⾏全量或增量备份和数据恢复?

1. MySQL⽇志

MySQL Server 有以下⼏种⽇志,可以记录服务器正在发⽣的活动

⽇志类型 ⽇志信息

重做⽇志(Redo log) ⽤于事务的提交和崩溃时恢复数据

回滚⽇志(Undo log) ⽤于事务回滚

错误⽇志 (Error log) mysqld在启动、运⾏或停⽌时遇到的问题

⼀般查询⽇志 (General query log) 已建⽴的客⼾端连接和从客⼾端接收到的语句

慢查询⽇志 (Slow query log) 执⾏时间超过 long_query_time 指定秒数的查询

⼆进制⽇志 (Binary log) 更改数据的语句(也⽤于主从复制),就是增删改

中继⽇志 (Relay log) 从源服务器接收到的数据更改,从机把主机二进制日志内容保存到自己的中继日志里面

• 重做⽇志,回滚⽇志可以参考存储引擎专题中的相关内容

• 错误⽇志,⼀般查询⽇志,慢查询⽇志的介绍可以参考服务器配置与管理专题中的⽇志内容

2. 二进制日志

介绍

• MySQL中最重要的⽇志,以"事件"的形式记录了所有DDL和DML语句对数据库的更改,例如:记录表的创建操作或表数据的更改

• ⼆进制⽇志不会记录 SELECT 和 SHOW 操作

• ⼆进制⽇志还包含每个语句更新数据时花费的时间信息,启动⼆进制⽇志,对服务器性能稍微有些影响

• 当数据库重启,执⾏flushlogs,或达到指定⼤⼩时会⽣成新的⽇志⽂件

作⽤

• 主从节点数据复制:从节点服务器读取主节点服务器上的⼆进制⽇志⽂件,并根据⼆进制⽇志中记录的事件在从节点上执⾏相同的操作,保证主从节点服务器上数据⼀致,实现数据复制功能,并于数据复制。

• 数据恢复:重新执⾏记录在⼆进制⽇志中的事件,可以完成任⼀事务之前的数据恢复。

配置

• 默认binlog⾃动开启,可以查看相着系统变量

sql 复制代码
show variables like '%log_bin%';
 # 查看包含log_bin的配置

#是否开启⼆进制⽇志

#⼆进制⽇志的基本⽂件名

#⼆进制⽇志索引⽂件名

#是否可以创建或修改存储函数

#会话级别是否开启⼆进制⽇志

• 选项 --log-bin[=base_name] ⽤于指定⼆进制⽇志⽂件的基本名称,如果不指定 --logbin 选项,默认基本名称为 binlog ,建议为⼆进制⽇志指定⼀个基本名;

• ⼆进制⽇志⽂件和索引⽂件的默认位置是数据⽬录。可以通过配置选项⽂件对默认值进⾏配置,使⽤ --log-bin[=file_name] 选项指定⾃定义路径, file_name 格式 = 绝对路径+基本名。 --log-bin 对应的系统变量是 log_bin_basename

默认的数据目录是/var/lib/mysql#

这里就有了

sql 复制代码
vim /etc/mysql/my.cnf # 编辑选项⽂件

这个是配置文件

sql 复制代码
# MySQL 服务节点
[mysqld]
# 配置⾃定义的⼆进制⽇志的基本⽂件名,可以是绝对路径(⽣产环境),也可以是相对路径(数据⽬录下)
log_bin=/var/lib/mysql/binlog
# 禁⽤⼆进制⽇志,skip-log-bin或disable-log-bin 要配置在log_bin的后⾯
# skip-log-bin
# 或,任选其⼀
# disable-log-bin

临时关闭⼆进制⽇志

sql 复制代码
-- 关闭会话级别是否开启⼆进制⽇志,只有这个会话关闭了
mysql> set session sql_log_bin = 0;
show variables like '%log_bin%';

只能关闭会话级别,不能关闭全局的⼆进制⽇志,如果关闭全局⼆进制⽇志要通过选项⽂件设置

磁盘文件

⼆进制⽇志⽂件名是由基本名+数字扩展名组成的,服务器每次创建⼀个新的⽇志⽂件时,数字扩

展名都会增加,从⽽保证有序的⽂件序列,发⽣以下事件时,服务器都会在创建⼀个新的⽇志⽂件:

◦ 服务器已启动或重新启动

◦ 服务器刷新⽇志

sql 复制代码
-- 刷新所有日志
flush logs;
-- 刷新二进制日志
flush binary logs;

◦ 当前⽇志⽂件的⼤⼩达到 max_binlog_size (单个⽇志⽂件的最⼤字节数,最⼩值 4096 字节,最⼤值和默认值 1GB).

⼆进制⽇志⽂件⼤⼩可能会超出 max_binlog_size 设定的值,因为⼆进制⽇志在记录事务时,会完整的记录整个事务,不存在把⼀个事务拆分的情况,如果遇到⼀个⼤事务时,即使记录整个事务会超过⽇志⼤⼩限制,也会保证事务的完整性

我们看到日志最高是52

sql 复制代码
flush binary logs;

变成53了,说明用了一个新的日志文件来存储了

可以使⽤ RESET MASTER 语句删除所有⼆进制⽇志⽂件,或者使⽤ PURGE binary LOGS 删除⼀部分⼆进制⽇志⽂件,具体演⽰:

sql 复制代码
# 删除指定⽇志⽂件之前的所有⽇志⽂件并更新索引
mysql> PURGE BINARY LOGS TO 'binlog.000010';
# 删除指定时间之前的所有⽇志⽂件并更新索引
mysql> PURGE BINARY LOGS BEFORE '2024-10-02 22:56:26'
# 重置⼆进⾏⽇志⽂件和索引⽂件为初始状态
mysql> RESET MASTER;

/var/lib/mysql/binlog.index这个文件记录的就是日志里面所有日志文件名字

sql 复制代码
PURGE BINARY LOGS TO 'binlog.000046';

发现45就不见了

RESET MASTER;就是从00001开始索引,清除原来的日志

过期时间

在选项⽂件中配置 binlog_expire_logs_seconds 可以设置⼆进制⽇志的过期时间,单位为秒,默认2592000秒,即30天。⼆进制⽇志⽂件过期后,会⾃动删除。

sql 复制代码
vim /etc/mysql/my.cnf # 编辑选项⽂件
sql 复制代码
# MySQL 服务节点
[mysqld]
# 配置⾃定义的⼆进制⽇志的基本⽂件名,可以是绝对路径(⽣产环境),也可以是相对路径(数据⽬录下)
log_bin=/var/lib/mysql/binlog
# 指定⼆进制⽇志的过期时间
binlog_expire_logs_seconds=2592000

然后重启

• 查看系统变量

sql 复制代码
show variables like '%bin%';

反正是动态变化的

日志格式

• 记录⼆进制⽇志时使⽤的格式有以下三种:

格式 说明

STATEMENT 基于 SQL 语句记录⽇志

ROW 基于表中受影响的⾏记录⽇志

MIXED 基于语句格式与⾏格式的混合模式记录⽇志

• 基于语句的⽇志格式,最初MySQL 是基于 SQL 语句复制实现主从节点同步,通过指定选项 --binlog-format=STATEMENT 使⽤此格式 。

• 基于⾏的⽇志格式(默认),主节点将事件写⼊⼆进制⽇志,表⽰各个表中受影响的数据⾏,可以通过指定选项 --binlog-format=ROW 使⽤此格式 。

• 混合⽇志记录格式,默认情况下使⽤基于语句的⽇志记录,如果MySQL认为基于语句的格式不能保证主从复制过程中的数据安全时,会⾃动切换到基于⾏的⽇志格式,⽐如主节点在语句中⽤了UUID() 函数,那么⽇志⽂件中记录的是UUID⽣成的真实值⽽不是直接使⽤原始的SQL语句,使⽤混合⽇志格式可以指定选项 --binlog-format=MIXED 。

基于 SQL 语句记录⽇志:如果SQL语句中有now()的话,那么从节点同步数据的时候time就不对的

TIPS: 设置⼆进制⽇志格式

--binlog-format=[STATEMENT|ROW|MIXED]

• ⽣产环境中使⽤ROW格式,因为⼀般我们需要binlog来做更多的操作,⽐如数据同步和⽇志解析;Mixed混合模式⽇志处理有些困难,很多同步⼯具⽆法使⽤

sql 复制代码
vim /etc/mysql/my.cnf # 编辑选项⽂件
sql 复制代码
# MySQL 服务节点
[mysqld]
# 配置⾃定义的⼆进制⽇志的基本⽂件名,可以是绝对路径(⽣产环境),也可以是相对路径(数据⽬
录下)
log_bin=/var/lib/mysql/binlog
# 指定⼆进制⽇志的过期时间
binlog_expire_logs_seconds=2592000
# 指定⼆进制⽇志格式为ROW
binlog_format=ROW
sql 复制代码
show variables like '%bin%';

刷盘策略

⾸先看⼀下MySQL binlog缓存、操作系统缓存和磁盘中⼆进制⽇志⽂件的关系,如图所⽰:

• ⼆进制⽇志的刷盘策略可以通过 sync_binlog 系统变量设置,设置规则如下

◦ sync_binlog=0 :MySQL不控制binlog的刷新,由操作系统控制刷新时机,性能最好,⻛险最⼤,MySQL崩溃则MySQL binlog缓存中所有binlog信息都会丢失;就是说MySQL先把产生的二进制日志写入操作系统的缓存,当操作系统的缓存满了之后在统一刷新到磁盘,但是如果操作系统崩溃或者断电--》没有刷新到磁盘--》数据丢失

◦ sync_binlog=1 :每次提交事务,MySQL刷新binlog完成落盘,最安全但是性能损耗最大,生产环境一般设置为1

◦ sync_binlog=N :可以设置成⼀个⾮0和1的正整数,表⽰每提交N个事务刷新⼀次Binlog,需要根据当前的业务场景经过测试设置⼀个合理的值,这个设置牺牲⼀定的⼀致性,但可以提⾼⼀定的性能。

• 在⽣产环境对数据⼀致要求⾼的场景⾥推荐使⽤每次提交事务都刷新⼆进制⽇志,设置sync_binlog=1

常⽤操作

sql 复制代码
-- 查看binlog是否开启
show variables like '%log_bin%';
select @@log_bin;
-- 查看binlog的路径
select @@log_bin_basename;
-- 查看binlog的格式
select @@binlog_format;
-- 查看是落盘策略
select @@sync_binlog;
-- 刷新所有⽇志
flush logs;
-- 刷新⼆进制⽇志
flush binary logs;
-- 查看当前服务器使⽤的binlog⽂件及⼤⼩
show binary logs;
-- 查看最新的binlog⽂件名和postion
show master status;
-- 查看binlog中的事件
show binlog events [IN 'log_name'] [FROM pos] [LIMIT row_count];
show binlog events in 'binlog.000051' from 676 limit 3;
-- 重置⼆进⾏⽇志⽂件和索引⽂件为初始状态
reset master;
-- 删除指定⽇志⽂件之前的所有⽇志⽂件并更新索引
purge binary logs to 'binlog.000010';
-- 删除指定时间之前的所有⽇志⽂件并更新索引
purge binary logs before '2024-05-02 22:56:26'
-- 查看服务器ID
select @@server_id;

2.1 mysqlbinlog⼯具

简介

作⽤

⽤来解析⼆进制⽇志的实⽤⼯具,可以能过 ls /usr/bin/mysql* 查看

常⽤选项

mysqlbinlog 有如下常⽤选项,可以在命令⾏中指定,也可以在选项⽂件中通过 [mysqlbinlog]和 [client] 组进⾏指定

选项 说明

--base64-output --base64-output=value把BINLOG中的事件⽤base-64进⾏编码,value的取值在之后有特殊说明

--database 只查看指定数据库的⽇志

--no-defaults 不读取选项⽂件

--offset, -o --offset=N,-o N跳过⽇志中的前N条记录

--raw mysqlbinlog以原始⼆进制格式写⼊事件,默认是⽂本格式

--read-from-remote-server, -R --read-from-remote-server=file_name , -R读取远程MySQL服务器的⼆进制⽇志,⽽不是读取本地,要求远程服务器正在运⾏

--require-row-format 基于⾏格式的⼆进制⽇志记录格式。

--result-file, -r --result-file=name, -r name 输出的⽬标⽂件

--server-id 仅显⽰指定服务器ID创建的事件。

--skip-gtids 输出转储⽂件时不包含⼆进制⽇志⽂件中的gtid

--start-datetime --start-datetime=datetime从等于或晚于datetime的第⼀个事件开始读取⽇志,⽀持 DATETIME 和TIMESTAMP 类型

--stop-datetime --stop-datetime=datetime在等于或晚于datetime的第⼀个事件结束,⽀持 DATETIME 和 TIMESTAMP 类型

--start-position, -j --start-position=N , -j N开始读取⽇志的位置, position 等于或⼤于N之后的任何事件。

--stop-position --stop-position=N在⽇志位置N处停⽌解码

--stop-never 保持与服务器的连接

--verbose, -v 重新构建⾏事件并将其显⽰为已注释的SQL语句,并在适⽤的情况下显⽰表分区信息

所有的MySQL工具都在/usr/bin/mysql这里

但是我们的docker里面没有

我们WIndows安装的MySQL是具有的,而且环境变量也配置好了

binlog内容的格式

mysqlbinlog 可以使⽤以下语法

sql 复制代码
mysqlbinlog [options] log_file ...

例如要显⽰名为 binlog.000010 ⼆进制⽇志⽂件的内容,可以使⽤以下命令:

sql 复制代码
mysqlbinlog --no-defaults binlog.000046

但是有一个要注意的就是,

mysqlbinlog 执行命令的binlog.000046这个文件必须和此时的工作目录相同,所以我把容器里面的binlog.000046移动到D:\soft\mysql-8.0.45-winx64\bin就可以了

end of表示结束

#at表示一个事件的开始,后面的数字表示偏移量

• postion: # at 3470 每条⽇志都以 # at 开始,后⾯的数字表⽰该条⽇志记录的事件在⽂件

中的偏移量,当前⽰例表⽰该事件从⽇志⽂件的第3470个字节开始

• timestamp: 事件发⽣的时间戳,即第⼆⾏开头记录的( 241021 16:38:31 )

• server id: 服务器标识(1)

• end_log_pos: 下⼀个事件在⽂件中的偏移量(3547,当前事件结束偏移+1)

• Type: 事件类型(Query)

• thread_id: 执⾏事件的线程Id(8)

• exec_time: 事件执⾏花费的时间(0.00 表⽰10毫秒以内)

• error_code: 错误码(0 表⽰没有错误)

查看日志

先重启服务,创建一个新的日志文件

准备数据

sql 复制代码
-- 建库
drop database if exists testdb;
create database testdb character set utf8mb4 collate utf8mb4_0900_ai_ci;
use testdb

-- 建表
create table t1 (
  id bigint not null,
  name varchar(20) not null
);

-- 写入
insert into t1 (id, name) values (101, 'user101');
insert into t1 (id, name) values (102, 'user102');
insert into t1 (id, name) values (103, 'user103');
insert into t1 (id, name) values (104, 'user104');
insert into t1 (id, name) values (105, 'user105');
insert into t1 (id, name) values (106, 'user106');

-- 更新
update t1 set name = 'bit101' where id = 101;
update t1 set name = 'bit102' where id = 102;
update t1 set name = 'bit103' where id = 103;

-- 删除
delete from t1 where id = 104;
delete from t1 where id = 105;
delete from t1 where id = 106;
sql 复制代码
mysqlbinlog --no-defaults --database=testdb binlog.000061

可以看到我妈妈使用的一些SQL语句

但是有些内容是加密的,我们看不懂

可以通过加⼊ --base64-output=decode-rows 不显⽰加密内容,配合 --v 选项,显⽰事件的SQL语句

sql 复制代码
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v binlog.000061

查看指定时间之后的⽇志

sql 复制代码
# 读取binlog.000103中 2024-10-21 16:38:33 之后的所有⽇志
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v --start-datetime='2024-10-21 16:38:33' binlog.000103
sql 复制代码
# -v 可以替换成-vv 可以更详细的显⽰SQL中的数据信息
# 读取binlog.000103中2024-10-21 16:38:31 2024-10-21 19:38:33之间的⽇志
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v --start-datetime='2024-10-21 16:38:33' --stop-datetime='2024-10-21 19:38:33' binlog.000103

查看指定位置之后的⽇志

sql 复制代码
# 从⽇志位置为3985开始读取⽇志直到⽇志⽂件结尾
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v --start-position=3793 binlog.000001 
# 从⽇志位置3985开始读取到⽇志位置15896结束
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v --start-position=3793 --stop-position=4090 binlog.000001

我们看到删除的偏移量是at 9046,第一个delete是8369

sql 复制代码
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v --start-position=8369 binlog.000061

简单数据恢复

删除testdb

sql 复制代码
-- 删除数据库
drop database testdb;

我们看到删库这个事件操作的偏移量是9123

如果要恢复数据,只需要把之前的日志重新执行一遍就可以了,确定从哪开始到哪结束

上一个操作的偏移量是9046,就是最后delete后面的commit的偏移量

就是这个位置

创建库的位置是4

通过⽇志⽂件恢复

sql 复制代码
# ⽅法⼀:找到恢复的起始位置,直接通过⼆进制⽇志进⾏恢复
mysqlbinlog --no-defaults --skip-gtids=true --start-position=4 --stop-position=9046 binlog.000061 | mysql -uroot -p123456 -h127.0.0.1 -P3306
# ⽅法⼆:导出⼆进制⽇志到.sql⽂件
mysqlbinlog --no-defaults --skip-gtids=true --start-position=4 --stop-position=9046 binlog.000061 > testdb.sql
# 在MySQL客⼾端导⼊.sql⽂件
source /var/lib/mysql/testdb.sql


这样就恢复成功了

sql 复制代码
mysqlbinlog --no-defaults --skip-gtids=true --start-position=4 --stop-position=9046 binlog.000061 > testdb.sql

然后执行这个

远程备份binlog⽇志(了解)

• 应⽤场景:本地磁盘的⼆进制⽇志有丢失的⻛险,在⽣产环境中通过把后成的binlog⽇志压缩后传输到远程服务器。

• 功能描述:Mysql5.6开始mysqlbinlog⽀持将远程服务器上的binlog实时复制到本地服务器上,⽐如在备份机上运⾏mysqlbinlog复制主库的⽇志

• 实现机制:通过MySQLReplication API实时获取⼆进制事件。远程服务器相当于主服务器,备份服务器相当于MySQL从服务器

⽰例:

◦ 在主服务器上创建账号

sql 复制代码
-- 创建⼀个⽤于复制⽇志的⽤⼾
CREATE USER 'binlogrep'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 为⽤⼾赋予复制权限
grant REPLICATION SLAVE on *.* to 'binlogrep'@'%';
-- 刷新权限
flush privileges;
-- 测试登录
mysql -ubinlogrep -p123456

'binlogrep'@'%'中%表示所有主机都可以用·这个账户来登录

从服务器运⾏备份

sql 复制代码
mysqlbinlog --read-from-remote-server --raw --host=127.0.0.1 --port=3306 --user=binlogrep --password=123456 --stop-never binlog.000061 --result-file=d:/logs/bak-

--stop-never是实时监控,一直读取,动态的读取变化,而不是只是读取一次就完事了

--result-file=d:/logs/bak-是指定本地保存日志,bak是保存日志的前缀

result-file=/log/1373306/bak- 这种⽅式指定本地备份⽇志⽂件,可以为⽇志⽂件前加缀,如果只指定备份⽬录⼀定以 / 结尾,⽐如 result-file=/log/1373306/ 此时备份的⽇志⽂件使⽤主服务器的⽂件名

sql 复制代码
mysqlbinlog --read-from-remote-server --raw --host=127.0.0.1 --port=3306 --user=root --password=123456 --stop-never binlog.000061 --result-file=d:/bak-

总结

相关推荐
谢怜822 小时前
数据库系统概论第四章数据库安全性
数据库·oracle
砚边数影2 小时前
工业级时序数据管理:如何破解海量写入与实时查询的性能瓶颈?
数据库·时序数据库·kingbase·数据库平替用金仓·金仓数据库
Elastic 中国社区官方博客2 小时前
从向量到关键词:在 LangChain 中的 Elasticsearch 混合搜索
大数据·开发语言·数据库·elasticsearch·搜索引擎·ai·langchain
山岚的运维笔记2 小时前
SQL Server笔记 -- 第34章:cross apply
服务器·前端·数据库·笔记·sql·microsoft·sqlserver
落花流水 丶2 小时前
MongoDB 完全指南
数据库·mongodb
文档搬运工2 小时前
OS的load average很高
数据库
爬山算法2 小时前
MongoDB(3)什么是文档(Document)?
数据库·mongodb
爬山算法2 小时前
MongoDB(9)什么是MongoDB的副本集(Replica Set)?
数据库·mongodb
thginWalker2 小时前
实战篇 & 结束篇
数据库