77-MySQL-日志

MySQL8.0 官网日志地址

一、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%';
查看当前通用查询日志状态.png
  • 系统变量 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%';
image.png

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)。它记录了数据库所有执行的DDLDML等数据库更新事件的语句,但是不包含没有修改任何数据的语句 (如数据查询语句select、show等)。
它以 事件形式 记录并保存在 二进制文件 中。通过这些信息,我们可以再现数据更新操作的全过程。

5.1、binlog主要应用场景

5.1.1、数据恢复

如果MySQL数据库意外停止,可以通过二进制日志文件来查看用户执行了哪些操作,对数据库服务器文件做了哪些修改,然后根据二进制日志文件中的记录来恢复数据库服务器。

5.1.2、数据复制

由于日志的延续性时效性,master把它的二进制日志传递给slaves来达到master-slave数据一致的目的。可以说MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据一致性

image.png

5.2、查看默认情况

查看记录二进制日志是否开启:在MySQL8中默认情况下,二进制文件是开启的

  • 查看SQL
SHOW VARIABLES LIKE '%log_bin%';
image.png
  • 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.cnfmy.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-bin

  • 2、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;
image.png
  • 所有对数据库的修改都会记录在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种格式,分别是StatementMixed
    • 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.png
  • 所有操作都保存在binlog.000056日志中,如果工作中可以先备份下这个binlog.000056日志文件,接着执行 FLUSH LOGS刷新日志,重新创建一个binlog.000057

  • FLUSH LOGS

重新创建一个日志的目的:接下来所有操作的数据都会写入到新的日志中,旧日志中不会再写入任何数据(方便根据旧日志的内容恢复数据,因为旧日志的数据就是备份之后到删除之前的所有操作日志,新建日志不会有过多的数据影响恢复)

FLUSH LOGS ;
image.png
5.5.4 实战-恢复数据
  • 查看当前数据
SELECT *
FROM student;
image.png
  • 第一步:查看binlog.000056日志
SHOW BINLOG EVENTS IN 'binlog.000056';
image.png
  • 第二步:恢复插入的数据

从上图可以了解,该日志文件中存在写操作和读、删除操作。而且插入操作在三个事务中并且是连在一起的,所以我们可以直接恢复三个事务。开始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;
image.png
  • 执行PURGE MASTER LOGS语句删除创建时间比binlog.000056早的所有日志
PURGE MASTER LOGS TO 'binlog.000056';
  • 再次查看二进制日志文件
SHOW BINARY LOGS;
image.png
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日志刷盘流程
image.png
  • writefsync的时机,可以由参数 sync_binlog 控制,默认是 0 。为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的binglog 会丢失

    image.png

  • 为了安全起见,可以设置为 1 ,表示每次提交事务都会执行fsync,就如同redo log 刷盘流程一样。最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsync

    image.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 logbinlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的 写入时机 不一样

image.png
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,最终数据不一致。

image.png
  • 为了解决两份日志之间的逻辑一致问题,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、恢复的典型错误

如果从服务器宕机,有的时候为了系统恢复,要重装操作系统,这样就可能会导致你的 服务器名称 与之前 不同 。而中继日志里是 包含从服务器名 的。在这种情况下,就可能导致你恢复从服务器的时候,无法从宕机前的中继日志里读取数据,以为是日志文件损坏了,其实是名称不对了。
解决的方法也很简单,把从服务器的名称改回之前的名称。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容