一、MySQL支持的日志
MySQL有不同类型的日志文件,用来存储不同类型的日志,分为
二进制日志
、错误日志
、通用查询日志
和慢查询日志
,这也是常用的4种。MySQL 8又新增两种支持的日志:中继日志
和数据定义语句日志
。使用这些日志文件,可以查看MySQL内部发生的事情
慢查询日志:
记录所有执行时间超过long_query_time
的所有查询,方便我们对查询进行优化。通用查询日志
:记录所有连接的起始时间和终止时间
,以及连接发送给数据库服务器的所有指令,对我们复原操作的实际场景、发现问题,甚至是对数据库操作的审计都有很大的帮助错误日志:
记录MySQL服务的启动、运行或停止MySQL服务时出现的问题,方便我们了解服务器的状态,从而对服务器进行维护二进制日志:
记录所有更改数据的语句,可以用于主从服务器之间的数据同步,以及服务器遇到故障时数据的无损失恢复中继日志:
用于主从服务器架构中,从服务器用来存放主服务器二进制日志内容的一个中间文件。从服务器通过读取中继日志的内容,来同步主服务器上的操作数据定义语句日志:
记录数据定义语句执行的元数据操作小结:
除二进制日志
外,其他日志都是文本文件
。默认情况下,所有日志创建于MySQL数据目录
中。
1.1、日志的弊端
- 日志功能会
降低MySQL数据库的性能
。例如,在查询非常频繁的MySQL数据库系统中,如果开启了通用查询日志
和慢查询日志
,MysQL数据库会花费很多时间记录日志。 - 日志会
占用大量的磁盘空间
。对于用户量非常大、操作非常频繁的数据库,日志文件需要的存储空间设置比数据库文件需要的存储空间还要大。
二、慢查询日志(slow query log)
三、通用查询日志(general query log)
通用查询日志用来
记录用户的所有操作
,包括启动和关闭MysQL服务、所有用户的连接开始时间
和截止时间
、发给 MySQL 数据库服务器的所有 SQL 指令等。当我们的数据发生异常时,查看通用查询日志,还原操作时的具体场景
,可以帮助我们准确定位问题。
3.1问题场景
在电商系统中,购买商品并且使用微信支付完成以后,却发现支付中心的记录并没有新增,此时用户
再次使用支付宝支付
,就会出现重复支付
的问题。但是当去数据库中查询数据的时候,会发现只有一条记录存在。那么此时给到的现象就是只有一条支付记录,但是用户却支付了两次。
我们对系统进行了仔细检查,没有发现数据问题,因为用户编号
和订单编号
以及第三方流水号
都是对的。可是用户确实支付了两次
,这个时候,我们想到了检查通用查询日志
,看看当天到底发生了什么。
查看之后,发现:1月1日下午2点,用户使用微信支付
完以后,但是由于网络故障,支付中心没有及时收到微信支付的回调通知
,导致当时没有写入数据。1月1日下午2点30,用户又使用支付宝支付
,此时记录更新到支付中心。1月1日晚上9点,微信的回调通知过来了
,但是支付中心已经存在了支付宝的记录,所以只能覆盖记录
了。
3.2查看当前状态
SHOW VARIABLES LIKE '%general%';
- 系统变量 general_log 的值是 OFF,即
通用查询日志处于关闭状态
。在MysQL中,这个参数的默认值是关闭的
。因为一旦开启记录通用查询日志,MySQL 会记录所有的连接起止和相关的 SQL操作,这样会消耗系统资源并且占用磁盘空间。我们可以通过手动修改变量的值,在需要的时候开启日志
-
通用查询日志文件
的名称是raven-mysql-0.log
。存储路径是/var/lib/mysql
,默认也是数据路径
。这样我们就知道在哪里可以查看通用查询日志的内容了
3.3 启动日志
3.3.1 永久性启动日志
修改
my.cnf
或者my.ini
配置文件来设置。在[mysqld]组下加入log选项,并重启MySQL服务。如果不指定目录和文件名,通用查询日志将默认存储在MySQL数据目录中的hostname.log文件中,hostname表示主机名
[mysqld]
general_log=ON
# 日志文件所在目录路径,filename为日志文件名
general_log_file=[path[filename]]
3.3.2 临时性启动日志
- 开启通用查询日志
SET GLOBAL general_log=on;
- 设置日志文件保存位置
SET GLOBAL general_log_file=’path/filename’;
- 关闭通用查询日志
SET GLOBAL general_log=off;
- 查看设置后情况
SHOW VARIABLES LIKE 'general_log%';
3.4 查看日志
通用查询日志是以
文本文件
的形式存储在文件系统中的,可以使用文本编辑器
直接打开日志文件。每台MySQL服务器的通用查询日志内容是不同的
- 查看
通用查询日志
路径
SHOW VARIABLES LIKE 'general_log%';
- 查看
通用查询日志
文件命令
cat raven-mysql-0.log
- 查看
通用查询日志
文件内容
usr/sbin/mysqld, Version: 8.0.31 (MySQL Community Server - GPL). started with:
Tcp port: 3306 Unix socket: /var/run/mysqld/mysqld.sock
Time Id Command Argument
2022-12-14T15:17:44.115654Z 16 Query SHOW WARNINGS
2022-12-14T15:17:44.118549Z 16 Query SHOW WARNINGS
2022-12-14T15:17:44.119479Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ select database()
2022-12-14T15:17:44.123749Z 16 Query SHOW WARNINGS
2022-12-14T15:17:44.126374Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:17:47.151800Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:17:47.154022Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ set session transaction read write
2022-12-14T15:17:47.156549Z 16 Query SELECT @@session.transaction_read_only
2022-12-14T15:17:47.158780Z 16 Query SHOW WARNINGS
2022-12-14T15:17:47.160113Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SET net_write_timeout=600
2022-12-14T15:17:47.160770Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SHOW VARIABLES LIKE 'general_log%'
2022-12-14T15:17:47.180542Z 16 Query SHOW WARNINGS
2022-12-14T15:17:47.186542Z 16 Query SHOW WARNINGS
2022-12-14T15:17:47.188044Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ select database()
2022-12-14T15:17:47.191568Z 16 Query SHOW WARNINGS
2022-12-14T15:17:47.193943Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:17:51.753388Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:17:51.754277Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ set session transaction read write
2022-12-14T15:17:51.757078Z 16 Query SELECT @@session.transaction_read_only
2022-12-14T15:17:51.759036Z 16 Query SHOW WARNINGS
2022-12-14T15:17:51.760204Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ select database()
2022-12-14T15:17:51.764532Z 16 Query SHOW WARNINGS
2022-12-14T15:17:51.766647Z 16 Query SHOW WARNINGS
2022-12-14T15:17:51.768083Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SET net_write_timeout=600
2022-12-14T15:17:51.768694Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SET SQL_SELECT_LIMIT=501
2022-12-14T15:17:51.769289Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SELECT *
FROM student
2022-12-14T15:17:51.784761Z 16 Query SHOW WARNINGS
2022-12-14T15:17:51.789334Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:18:56.781345Z 16 Query SELECT @@session.transaction_isolation
2022-12-14T15:18:56.782926Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ set session transaction read write
2022-12-14T15:18:56.785348Z 16 Query SELECT @@session.transaction_read_only
2022-12-14T15:18:56.786850Z 16 Query SHOW WARNINGS
2022-12-14T15:18:56.788342Z 16 Query SELECT @@session.transaction_read_only
2022-12-14T15:18:56.788922Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SET net_write_timeout=600
2022-12-14T15:18:56.789465Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ SET SQL_SELECT_LIMIT=DEFAULT
2022-12-14T15:18:56.790033Z 16 Query /* ApplicationName=DataGrip 2022.3.2 */ INSERT INTO student
VALUES (22, 'Raven-22', '五班'),
(23, 'Raven-23', '五班'),
(24, 'Raven-24', '五班')
3.5、停止日志
3.5.1、永久性停止日志
修改
my.cnf
或者my.ini
文件,把[mysqld]组下的general_log
值设置为OFF
或者把general_log
一项注释掉。修改保存后,再重启MySQL服务
,即可生效
[mysqld]
general_log=OFF
或
[mysqld]
#general_log=ON
3.5.2、临时性停止日志
- 使用SET语句停止MySQL通用查询日志功能
SET GLOBAL general_log=off;
- 查询通用日志功能
SHOW VARIABLES LIKE 'general_log%';
3.6 删除/刷新日志
如果数据的使用非常频繁,那么
通用查询日志
会占用服务器非常大的磁盘空间
。数据管理员可以删除很长时间
之前的查询日志,以保证MySQL服务器上的硬盘空间。
3.6.1 手动删除文件
- 1、
通用查询日志
的目录默认为MySQL数据目录。在该目录下手动删除通用查询日志
文件
# /var/lib/mysql/raven-mysql-0.log
SHOW VARIABLES LIKE 'general_log%';
- 2、重新生成查询日志文件
刷新MySQL数据目录,发现创建了新的日志文
件。前提一定要开启通用日志
mysqladmin -uroot -p flush-logs
- 3、先备份,再重新生产查询日志文件
如果
希望备份旧的通用查询日志
,就必须先将旧的日志文件复制出来或者改名
,然后执行上面的mysqladmin命令。正确流程如下
# 输入自己的通用日志文件所在目录
cd mysql-data-directory
# 指名就的文件名 以及 新的文件名
mv mysql.general.1og mysql.general.1og.old
mysqladmin -uroot -p flush-logs
四、错误日志(error log)
错误日志
记录了 MySQL 服务器启动
、停止
运行的时间,以及系统启动
、运行和停止
过程中的诊断信息
,包括错误
、警告
和提示
等。
通过错误日志
可以查看系统
的运行状态,便于即时发现故障
、修复故障
。如果MySQL服务出现异常
,错误日志是发现问题、解决故障的首选
。
4.1启动日志
在MySQL数据库中,错误日志功能是
默认开启
的。而且,错误日志无法被禁止
。
4.1.1启动日志文件路径配置
默认情况下,
错误日志
存储在MySQL数据库的数据文件夹下,名称默认为mysqld.log
(Linux系统)或hostname.err
(mac系统)。如果需要制定文件名,则需要在my.cnf
或者my.ini
中做如下配置,修改配置项后,需要重启MySQL服务
才能生效
[mysqld]
# path为日志文件所在的目录路径,filename为日志文件名
log-error=[path/[filename]]
4.2查看日志
- 查询错误日志的存储路径
SHOW VARIABLES LIKE 'log_err%';
4.3 删除/刷新日志
对于很久以前的错误日志,数据库管理员查看这些错误日志的可能性不大,可以将这些错误日志删除,以保证MySQL服务器上的
硬盘空间
。MySQL的错误日志是以文本文件的形式存储在文件系统中的,可以直接删除
。
- 第1步(方式1):删除操作
在运行状态下删除
错误日志
文件后,MySQL并不会自动创建日志文件
。
rm -f /var/lib/mysgl/mysqld.1og
- 第1步(方式2):重命名文件
mv /var/log/mysqld.log /var/log/mysqld.log.old
- 第2步:重建日志
mysqladmin -u root -p flush-logs
- 可能会报错或没有重新生成文件
mysqladmin: refresh failed;
error: 'Could not open file '/var/log/mysqld.log'
for error logging.'
-
解决错误解决错误.png
install -omysql -gmysql -m0644 /dev/null /var/log/mysqld.log
-
flush-logs
指令操作- MySQL 5.5.7以前的版本,flush-logs将错误日志文件重命名为filename.err_old,并创建新的日志文件
- 从MysQL 5.5.7开始,flush-logs只是
重新打开日志文件
,并不做日志备份和创建
的操作。 - 如果
日志文件不存在
,MySQL启动或者执行flush-logs时会自动创建新的日志文件。重新创建错误日志,大小为0字节
4.4 MySQL8.0新特性
MySQL8.0里对错误日志的改进。MySQL8.0的错误日志可以理解为一个全新的日志,在这个版本里,接受了来自社区的广泛批评意见,在这些意见和建议的基础上生成了新的日志
4.4.1 来自社区的意见
- 默认情况下内容过于冗长
- 遗漏了有用的信息
- 难以过滤某些信息
- 没有标识错误信息的子系统源
- 没有错误代码,解析消息需要识别错误
- 引导消息可能会丟失
- 固定格式
4.4.2 针对这些意见,MySQL做了如下改变
- 采用
组件架构
,通过不同的组件执行日志的写入和过滤功能 - 写入错误日志的全部信息都具有唯一的错误代码从10000开始
- 增加了一个新的消息分类 《system》用于在错误日志中始终可见的非错误但服务器状态更改事件的消息
- 增加了额外的附加信息,例如关机时的版本信息,谁发起的关机等等
- 两种过滤方式,Internal和Dragnet
- 三种写入形式,经典、JSON和syseventlog
4.4.3 小结
通常情况下,管理员不需要查看错误日志。但是,
MySQL服务器发生异常
时,管理员可以从错误日志
中找到发生异常的时间、原因,然后根据这些信息来解决异常
五、二进制日志(bin log)
binlog
可以说是MySQL中比较重要
的日志了,在日常开发及运维过程中,经常会遇到。
binlog即binary log
,二进制日志文件,也叫作变更日志 (update log)
。它记录了数据库所有执行的DDL
和DML
等数据库更新事件的语句,但是不包含没有修改任何数据的语句 (如数据查询语句select、show等)。
它以事件形式
记录并保存在二进制文件
中。通过这些信息,我们可以再现数据更新操作的全过程。
5.1、binlog主要应用场景
5.1.1、数据恢复
如果MySQL数据库
意外停止
,可以通过二进制日志
文件来查看用户执行了哪些操作
,对数据库服务器文件做了哪些修改,然后根据二进制日志文件中的记录来恢复数据库服务器。
5.1.2、数据复制
由于日志的
延续性
和时效性
,master把它的二进制日志传递给slaves
来达到master-slave数据一致的目的。可以说MySQL数据库的数据备份、主备、主主、主从
都离不开binlog,需要依靠binlog来同步数据,保证数据一致性
5.2、查看默认情况
查看记录
二进制日志
是否开启:在MySQL8中默认情况下,二进制文件是开启的
- 查看SQL
SHOW VARIABLES LIKE '%log_bin%';
-
log_bin_basename :
是binlog日志的基本文件名,后面会追加标识来表示每一个文件 -
log-bin_index:
是binlog文件的索引文件,这个文件管理了所有的binlog文件的目录 -
log_bin_trust_function_creators:
限制存储过程,前面我们已经讲过了,这是因为二进制日志的一个重要功能是用于主从复制
,而存储函数
有可能导致主从的数据不一致。所以当开启二进制日志后,需要限制存储函数的创建、修改、调用 -
log-bin_use_V1_row_events :此只读系统变量已弃用
。ON表示使用版本 1二进制日志行,OFF表示使用版本 2二进制日志行 (MysQL5.6 的默认值为2)
5.3、日志参数设置
5.3.1、永久性方式
修改MySQL的
my.cnf
或my.ini
文件可以设置二进制日志的相关参数,重新启动MySQL服务生效
[mysqld]
# 启用二进制日志
log-bin=atguigu-bin
binlog_expire_logs_seconds=600
max_binlog_size=100M
1、
log-bin=mysql-bin
#打开日志(主机需要打开)),这个mysal-bin
也可以自定义,这里也可以加上路径,如: /home/www/mysqL_bin_log/mysql-bin2、
binlog_expire_logs_seconds:
此参数控制二进制日志文件保留的时长,单位是秒
,默认2592000 3天 --14400 4小时;86400 1天;259200 3天;3、
max_binlog_size:
控制单个二进制日志大小,当前日志文件大小超过此变量时,执行切换动作。此参数的最大和默认值是1GB
,该设置并不能严格控制Binlog的大小
,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,可能不做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束。一般情况下可采取默认值。
5.3.2、设置带文件夹的bin-log日志存放目录
如果想改变日志文件的目录和名称,可以对my.cnf或my.ini中的log_bin参数修改如下
[mysqld]
log-bin="/var/lib/mysql/binlog/atguigu-bin"
5.3.3、新建的文件夹需要使用mysql用户,使用下面的命令即可
chown -R -v mysql:mysql binlog
5.3.4、小结
数据库文件最好不要与日志文件放在同一个磁盘上!
这样,当数据库文件
所在的磁盘发生故障时,可以使用日志文件恢复数据
。
5.3.5、临时性方式
如果不希望通过修改配置文件并重启的方式设置二进制日志的话,还可以使用如下指令,需要注意的是在mysql8中只有
会话级别
的设置,没有了global级别
的设置。
- GLOBAL 级别
# GLOBAL 级别
SET GLOBAL sql_log_bin = 0;
[HY000][1228] Variable 'sql_log_bin' is a SESSION variable and can't be used with SET GLOBAL
- SESSION 级别
# session级别
SET sql_log_bin=0;
5.4 查看日志
当MySQL创建二进制日志文件时,先创建一个以
filename
为名称、以.index
为后缀的文件,再创建一个以filename
为名称、以.000001
为后缀的文件。
MySQL服务重新启动一次
,以.000001
为后缀的文件就会增加一个,并且后缀名按1递增。即日志文件的个数与MySQL服务启动的次数相同;如果日志长度超过了max_binlog_size
的上限(默认是1GB),就会创建一个新的日志文件。
- 查看当前的二进制日志文件列表及大小
SHOW BINARY LOGS;
- 所有对数据库的
修改
都会记录在binglog
中。但binlog是二进制文件
,无法直接查看,想要更直观的观看就需要使用mysq1binlog
命令工具了。指令如下:在查看执行,先执行一条SQL语句
UPDATE student
SET name= '张三back'
WHERE id = 1;
- 开始查看binlog
mysqlbinlog /var/lib/mysql/binlog.000054;
执行结果可以看到,这是一个简单的日志文件,日志中记录了用户的一些操作,这里并没有出现具体的SQL语句,这是因为binlog关键字后面的内容是经过编码后的
二进制日志
-
这里一个update语句包含如下事件
- Query 事件 负责开始一个事务(BEGIN)
- Table_map事件 负责映射需要的表
- Update_rows事件 负责写入数据
- xid事件 负责结束事务
前面的命令同时显示binlog格式的语句,使用如下命令不显示它
mysqlbinlog -v --base64-output=DECODE-ROWS "/var/lib/mysql/binlog.000054"
关于mysqlbinlog工具的使用技巧还有很多,例如只解析对某个库的操作或者某个时间段内的操作等。简单分享几个常用的语句,更多操作可以参考官方文档。
可查看参数帮助
mysqlbinlog --no-defaults --help
- 查看最后100行
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |tail -100
- 根据position查找
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |grep -A
20 '4939002'
- 上面这种办法读取出binlog日志的全文内容比较多,不容易分辨查看到pos点信息,下面介绍一种更为方便的查询命令
show binlog events [IN 'log_name' ] [FROM pos] [LIMIT [offset,] row_count];
-
IN log_name:
指定要查询的binlog文件名(不指定就是第一个binlog文件) -
FROM pos :
指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算) -
LIMIT [offset〕:
偏移量(不指定就是o) -
row-count :
查询总条数(不指定就是所有行)
show binlog events in 'binlog.000054';
- 上面这条语句可以将指定的binlog日志文件,分成有效事件行的方式返回,并可使用limit指定pos点的起始偏移查询条数。
#a、查询第一个最早的binlog日志
show binlog events\G;
#b、指定查询mysql-bin.000054这个文件
show binlog events in 'binlog.000054'\G;
#c、指定查询mysql-bin.000054这个文件,从pos点:391开始查起:
show binlog events in "binlog.000054' from 391\G;
#d、指定查询mysql-bin.000054这个文件,从pos点:391开始查起,查询5条(即5条语句)
show binlog events in 'binlog.000054' from 391 limit 5\G;
#e、指定查询 mysql-bin.000054这个文件,从pos点:391开始查起,偏移2行(即中间跳过2个)查询5条(即5条语句)
show binlog events in 'atguigu-bin.000054' from 391 limit 2,5\G;
- 上面我们讲了这么多都是基于binlog的默认格式,binlog格式查看
show variables like 'binlog_format';
- 除此之外,binlog还有2种格式,分别是
Statement
和Mixed
-
Statement:
每一条会修改数据的sql都会记录在binlog中-
优点:
不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能
-
-
Row:
5.1.5版本的MySQL才开始支持row level 的复制,它不记录sql语句上下文相关信息,仅保存哪条记录被修改。-
优点:
row level 的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
-
Mixed:
从5.1.8版本开始,MySQL提供了Mixed格式,实际上就是Statement与Row的结合
-
5.5 使用日志恢复数据
如果MysQL服务器启用了
二进制日志
,在数据库出现意外丢失数据时,可以使用MySQLbinlog工具从指定的时间点开始(例如,最后一次备份)直到现在或另一个指定的时间点的日志中恢复数据
5.5.1 MySQL-binlog恢复数据的语法
这个命令可以这样理解:使用
mysqlbinlog
命令来读取filename
中的内容,然后使用mysql命令将这些内容恢复到数据库中
mysqlbinlog [option] filename|mysql –uuser -ppass;
-
filename :
是日志文件名 -
option :
可选项,比较重要的两对option参数是--start-date、--stop-date 和 --start-position、-- stop-position-
--start-date 和 --stop-date :
可以指定恢复数据库的起始时间点
和结束时间点
-
--start-position
和--stop-position
:可以指定恢复数据的开始位置
和结束位置
-
注意:使用mysqlbinlog命令进行恢复操作时,必须是编号小的先恢复,例如binlog.000001必须在binlog.000002之前恢复。
5.5.2 实战-数据准备
- 步骤1:插入一批数据
INSERT INTO student
VALUES (22, 'zhang3', '1ban');
INSERT INTO student
VALUES (23, 'li4', '1ban');
INSERT INTO student
VALUES (24, 'wang5', '2ban');
- 步骤2:查询数据
SELECT *
FROM student;
- 步骤3:删除数据
DELETE
FROM student
WHERE id = 23;
- 步骤4:查询数据
SELECT *
FROM student;
5.5.3 实战-场景
上面对 student 表做的
插入,更新和删除
操作。现在不小心删除了所有的新增数据,现在目标就是恢复后面的新增,更新和删除的数据
- 第一步:查看Binlog
SHOW BINARY LOGS ;
所有操作都保存在
binlog.000056
日志中,如果工作中可以先备份
下这个binlog.000056
日志文件,接着执行FLUSH LOGS
刷新日志,重新创建一个binlog.000057
FLUSH LOGS
重新创建一个日志的目的:接下来所有操作的数据都会写入到新的日志中,旧日志中不会再写入任何数据(方便根据旧日志的内容恢复数据,因为旧日志的数据就是备份之后到删除之前的所有操作日志,新建日志不会有过多的数据影响恢复)
FLUSH LOGS ;
5.5.4 实战-恢复数据
- 查看当前数据
SELECT *
FROM student;
- 第一步:查看
binlog.000056
日志
SHOW BINLOG EVENTS IN 'binlog.000056';
- 第二步:恢复插入的数据
从上图可以了解,该日志文件中存在写操作和读、删除操作。而且插入操作在三个事务中并且是连在一起的,所以我们可以直接恢复三个事务。开始pos是
536
,结束pos是1350
/usr/bin/mysqlbinlog --start-position=536 --stop-position=1350 --database=student15
/var/lib/mysql/binlog/binlog.000056|/usr/bin/mysql
-uroot -pabc123
-V student15
- 第三步:恢复更新和删除的数据和恢复插入数据方式一样
5.5.4 实战-使用时间恢复数据
- 命令
/usr/bin/mysqlbinlog --start-datetime="2022-01-0515:39:22"
--stop-datetime="2022-01-05 15:40:19"
--database=student15 /var/lib/mysql/binlog/binlog.000056 | /usr/bin/mysql
uroot -pabc123 -v 123456
5.6 删除二进制日志
MySQL的二进制文件可以配置
自动删除
,同时MySQL也提供了安全的手动删除
二进制文件的方法。PURGE MASTER LOGS
只删除指定部分的二进制日志文件,RESET MASTER
删除所有的二进制日志文件
5.6.1、PURGE MASTER LOGS: 删除指定日志文件
- PURGE MASTER LOGS语法
PURGE {MASTER I BINARY} LOGS TO '指定日志文件名'
PURGE {MASTER | BINARY} LOGS BEFORE '指定日期'
5.6.2、实战-删除创建时间比 binlog.000056
早的所有日志
- 查看当前存在日志
SHOW BINARY LOGS;
- 执行PURGE MASTER LOGS语句删除创建时间比
binlog.000056
早的所有日志
PURGE MASTER LOGS TO 'binlog.000056';
- 再次查看二进制日志文件
SHOW BINARY LOGS;
5.6.3、使用PURGE MASTER LOGS语句删除2022年1月05日前创建的所有日志文件
PURGE MASTER LOGS before "20220105";
5.6.4、RESET MASTER:删除所有二进制日志文件
使用
RESET MASTEA
语句,清空所有的binlog日志。MysQL会重新创建二进制文件,新的日志文件扩展名将重新从000001
开始编号。慎用!
- 查看日志文件列表
SHOW BINARY LOGS;
- 执行RESET MASTER语句,删除所有日志文件
RESET MASTER:
- 执行完该语句后,原来的所有二进制日志已经全部被删除。
5.7、其它场景
二进制日志可以通过数据库的
全量备份
和二进制日志中保存的增量信息
,完成数据库的无损失恢复
。但是,如果遇到数据量大、数据库和数据表很多(比如分库分表的应用)的场景,用二进制日志进行数据恢复,是很有挑战性的,因为起止位置不容易管理。在这种情况下,一个有效的解决办法是
配置主从数据库服务器
,甚至是一主多从
的架构,把二进制日志文件的内容通过中继日志
,同步到从数据库服务器中,这样就可以有效避免数据库故障导致的数据异常等问题。
六、再谈二进制日志(binlog)
6.1、写入机制
binlog的写入时机也非常简单,事务执行过程中,先把日志写到
binlog cache
,事务提交的时候,再把binlog cache
写到binlog文件中
。因为一个事务的binlog不能被拆开
,无论这个事务多大,也要确保一次性写入
,所以系统会给每个线程分配一个块内存作为binlog cache
。
- 可以通过
binlog-cache_size
参数控制单个线程binlog cache
大小,如果存储内容超过了这个参数,就要暂存到磁盘 (Swap)。
6.1.1、binlog日志刷盘流程
-
write
和fsync
的时机,可以由参数sync_binlog
控制,默认是0
。为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的binglog 会丢失
image.png -
为了安全起见,可以设置为
1
,表示每次提交事务都会执行fsync,就如同redo log 刷盘流程一样
。最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsyncimage.png 在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。同样的,如果机器宕机,会丢失最近N个事务的binlog日志
6.2、 binlog与redolog对比
- redo log 它是
物理日志
,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎层产生的。 - 而binlog 是
逻辑日志
,记录内容是语句的原始逻辑,类似于“给1D=2这一行的c字段加工”,属于MySQL Server层。 - 虽然已们都属于持久化的保证,但是则重点不同
- redo log 让 InnoDB 存储引擎拥有了崩溃恢复能力。
- binlog 保证了MySQL集群架构的数据一致性
6.3、两阶段提交
在执行更新语句过程,会记录
redo log
与binlog
两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机
不一样
6.3.1、redo log与binlog两份日志之问的逻辑不一致,会出现什么门题?
- 实例
以update语句为例,假设
id=2
的记录,字段c
值是0
,把字段c值更新成1
,SQL语句为update T set c=1 where id=2
- 假设执行过程中写完
redo log
日志后,binlog日志写期间发生了异常,会出现什么情况呢?image.png
由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。因此,之后用binlog日志恢复数据时,就会少这一次更新,恢复出来的这一行c值是0,而原库因为redo log日志恢复,这一行c值是1,最终数据不一致。
-
为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用
两阶段提交
方案。原理很简单,将redo log的写入拆成了两个步骤prepare和commit, 这就是两阶段提交
image.png -
使用
两阶段提交
后,写入binlog时发生异常也不会有影响
image.png -
另一个场景,redo log设置commit阶段发生异常,那会不会回滚事务呢?image.png
并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据
七、 中继日志(relay log)
7.1、介绍
中继日志只在 主从服务器架构 的从服务器上存在
。从服务器为了与主服务器保持一致,要从主服务器读取二进制日志的内容,并且把读取到的信息写入本地的日志文件
中,这个从服务器本地的日志文件就叫中继日志
。然后,从服务器读取中继日志
,并根据中继日志
的内容对从服务器的数据进行更新,完成主从服务器的数据同步
。
- 搭建好主从服务器之后,中继日志默认会保存在从服务器的数据目录下。
- 文件名的格式是:
从服务器名 -relay-bin.序号
。中继日志
还有一个索引文件:从服务器名 -relay- bin.index
,用来定位当前正在使用的中继日志
7.2、查看中继日志
中继日志
与二进制日志
的格式相同,可以用mysqlbinlog
工具进行查看。下面是中继日志的一个片段
SET TIMESTAMP=1618558728/*!*/;
BEGIN
/*!*/;
# at 950
#210416 15:38:48 server id 1 end_log_pos 832 CRC32 0xcc16d651 Table_map: `atguigu`.`test` mapped to number 91
# at 1000
#210416 15:38:48 server id 1 end_log_pos 872 CRC32 0x07e4047c Delete_rows: table id
91 flags: STMT_END_F -- server id 1 是主服务器,意思是主服务器删了一行数据
BINLOG '
CD95YBMBAAAAMgAAAEADAAAAAFsAAAAAAAEABGRlbW8ABHRlc3QAAQMAAQEBAFHWFsw=
CD95YCABAAAAKAAAAGgDAAAAAFsAAAAAAAEAAgAB/wABAAAAfATkBw==
'/*!*/;
# at 1040
- 这一段的意思是,主服务器(“server id 1”)对表 atguigu.test 进行了 2 步操作:
- 定位到表 atguigu.test 编号是 91 的记录,日志位置是 832
- 删除编号是 91 的记录,日志位置是 872。
7.3、恢复的典型错误
如果从服务器宕机,有的时候为了系统恢复,要重装操作系统,这样就可能会导致你的 服务器名称 与之前
不同
。而中继日志
里是包含从服务器名
的。在这种情况下,就可能导致你恢复从服务器的时候,无法从宕机前的中继日志里读取数据,以为是日志文件损坏了,其实是名称不对了。
解决的方法也很简单,把从服务器的名称改回之前的名称。