MySQL支持的日志

日志类型

MySQL有不同类型的日志文件,用来存储不同类型的日志,分为二进制日志错误日志通用查询日志慢查询日志。MySQL 8.0 又新增两种支持的日志:中继日志数据定义语句日志,使 用这些日志文件,可以查看MySQL内部发生的事情。

日志类型 说明
慢查询日志 记录所有执行时间超过long_query_time的所有查询,方便对查询进行优化
通用查询日志 记录所有连接的起始时间和终止时间,以及连接发送给数据库服务器的所有指令, 对复原操作的实际场景、发现问题,甚至是对数据库操作的审计都有很大的帮助。
错误日志 记录MySQL服务的启动、运行或停止MySQL服务时出现的问题,方便我们了解服务器的 状态,从而对服务器进行维护。
二进制日志 记录所有更改数据的语句,可以用于主从服务器之间的数据同步,以及服务器遇到故 障时数据的无损失恢复
中继日志 用于主从服务器架构中,从服务器用来存放主服务器二进制日志内容的一个中间文件。 从服务器通过读取中继日志的内容,来同步主服务器上的操作。
数据定义语句日志 记录数据定义语句执行的元数据操作。

除二进制日志外,其他日志都是文本文件。默认情况下,所有日志创建于MySQL数据目录中。

日志的弊端

  • 日志功能会降低MySQL数据库的性能。在查询非常频繁的MySQL数据库系统中,如果开启通用查询日志和慢查询日志,MySQL数据库会花费很多时间记录日志。
  • 日志会占用大量的磁盘空间。对于用户量非常大、操作非常频繁的数据库,日志文件需要的存储空间设置比数据库文件需要的存储空间还要大。

慢查询日志(slow query log)

MySQL高级篇-9-性能分析工具的使用 已经详细介绍,这里不再赘述。

通用查询日志(general query log)

通用查询日志用来记录用户的所有操作 ,包括启动和关闭MySQL服务、所有用户的连接开始时间和截止=时间、发给 MySQL 数据库服务器的所有 SQL 指令等。当我们的数据发生异常时,查看通用查询日志, 还原操作时的具体场景,可以帮助我们准确定位问题 。

查看当前状态

1
SHOW VARIABLES LIKE '%general%';

系统变量general_log的值是OFF,即通用查询日志处于关闭状态。在MysQL中,这个参数的默认值是关闭的,可以通过手动修改变量的值,在需要的时候开启日志

一旦开启记录通用查询日志,MySQL会记录所有的连接起止和相关的SQL操作,这样会消耗系统资源并且占用磁盘空间。

启动日志

永久性方式 : 修改my.cnf或者my.ini配置文件来设置。在[mysqld]组下加入log选项,并重启MySQL服务

1
2
3
[mysqld]
general_log=ON
general_log_file=[path[filename]] #日志文件所在目录路径,filename为日志文件名

如果不指定目录和文件名,通用查询日志将默认存储在MySQL数据目录中的hostname.log文件中, hostname表示主机名。

临时性方式

1
2
3
4
5
6
7
8
SET GLOBAL general_log=on; -- 开启通用查询日志

SET GLOBAL general_log_file=’path/filename’; -- 设置日志文件保存位置


SET GLOBAL general_log=off; -- 关闭通用查询日志

SHOW VARIABLES LIKE 'general_log%'; -- 查看设置后情况

查看日志

通用查询日志是以 文本文件 的形式存储在文件系统中的,可以使用 文本编辑器 直接打开日志文件。

1
SHOW VARIABLES LIKE 'general_log%'

停止日志

永久性方式 : 修改my.cnf或者my.ini文件,把[mysqld]组下的general_log值设置为OFF或者把general_log注释。修改保存后,再重启MySQL服务 ,即可生效

1
2
[mysqld]
general_log=OFF

临时性方式

1
2
SET GLOBAL general_log=off; -- 使用SET语句停止MySQL通用查询日志功能
SHOW VARIABLES LIKE 'general_log%'; -- 查询通用日志功能

删除\刷新日志

如果数据的使用非常频繁,那么通用查询日志会占用服务器非常大的磁盘空间。数据管理员可以删除很 长时间之前的查询日志,以保证MySQL服务器上的硬盘空间。

手动删除文件

使用如下命令重新生成查询日志文件,刷新MySQL数据目录,发现创建新的日志文 件,前提一定要开启通用日志。

1
mysqladmin -uroot -p flush-logs

如果希望备份旧的通用查询日志,就必须先将旧的日志文件复制出来或者改名,然后执行上面的mysqladmin命令。正确流程如下:

1
2
cd mysql-data-directory # 输入自己的通用日志文件所在目录
mv mysql.general.log mysql.general.log.old # 指名就的文件名以及新的文件名mysqladmin -uroot -p flush-logs

错误日志(error log)

错误日志记录MySQL服务器启动、停止运行的时间,以及系统启动、运行和停止过程中的诊断信息,包括错误、警告和提示等。
通过错误日志可以查看系统的运行状态,便于即时发现故障、修复故障。如果MysQL服务出现异常,错误日志是发现问题、解决故障的首选。

启动日志

在MySQL数据库中,错误日志功能是默认开启的。而且,错误日志无法被禁止

默认情况下,错误日志存储在MySQL数据库的数据文件夹下,名称默认为mysqld.log(Linux系统)。如果需要制定文件名,则需要在my.cnf或者my.ini中做如下配置:

1
2
[mysqld]
log-error=[path/[filename]] #path为日志文件所在的目录路径,filename为日志文件名

修改配置项后,需要重启MySQL服务以生效。

查看日志

MySQL错误日志是以文本文件形式存储的,可以使用文本编辑器直接查看。

1
SHOW VARIABLES LIKE 'log_err%';

删除\刷新日志

对于很久以前的错误日志,数据库管理员查看这些错误日志的可能性不大,可以将这些错误日志删除, 以保证MySQL服务器上的 硬盘空间 。MySQL的错误日志是以文本文件的形式存储在文件系统中的,可以 直接删除 。

删除日志

1
2
3
4
rm -f /var/lib/mysql/mysqld.log 

# 或者
mv /var/lib/mysql/mysqld.log /var/lib/mysql/mysqld.log.old

重建日志

1
mysqladmin -uroot -p flush-logs

关键操作

1
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字节

二进制日志(bin log)

binlog即binary log(二进制日志文件),也叫作变更日志(update log),它记录数据库所有执行的DDLDML等数据库更新事件的语句,但是不包含没有修改任何数据的语句(如数据查询语句select、 show等)。

它以事件形式记录并保存在二进制文件中,通过它可以再现数据更新操作的全过程。如果想要记录所有语句,需要使用通用查询日志。

binlog 应用场景

  • 数据恢复:如果MySQL数据库意外停止,可以通过二进制日志文件来查看用户执行的操作,对数据库服务器文件做的修改,然后根据二进制日志文件中的记录来恢复数据库服务器
  • 数据复制:由于日志的延续性和时效性,master把它的二进制日志传递给slaves来达到master-slave数据一致的目的

MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据—致性。

查看默认情况

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

1
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二进制日志行

日志参数设置

永久性方式 :修改MySQL的my.cnfmy.ini 文件可以设置二进制日志的相关参数

1
2
3
4
5
[mysqld]
#启用二进制日志
log-bin=atguigu-bin
binlog_expire_logs_seconds=600
max_binlog_size=100M

重新启动MySQL服务,查询二进制日志的信息

1
SHOW VARIABLES LIKE '%log_bin%';

设置带文件夹的bin-log日志存放目录 , 可以对my.cnfmy.ini中的log_bin参数修改如下:

1
2
[mysqld]
log-bin="/var/lib/mysql/binlog/atguigu-bin"

新建的文件夹需要使用mysql用户

1
chown -R -v mysql:mysql binlog

临时性方式

如果不希望通过修改配置文件并重启的方式设置二进制日志的话,还可以使用如下指令(需要注意的是 在mysql8中只有会话级别的设置,没有global级别的设置)

1
2
3
4
5
--  global 级别
SET GLOBAL sql_log_bin=0;

-- session级别
SET sql_log_bin=0;

查看日志

当MySQL创建二进制日志文件时,先创建一个以“filename”为名称、以“.index”为后缀的文件,再创建一 个以“filename”为名称、以“.000001”为后缀的文件。

MySQL服务重新启动一次,以“.000001”为后缀的文件就会增加一个,并且后缀名按1递增。即日志文件的个数与MySQL服务启动的次数相同

如果日志长度超过max_binlog_size上限(默认是1GB),就 会创建一个新的日志文件

1
2
3
4
5
6
7
8
-- 查看当前的二进制日志文件列表及大小
SHOW BINARY LOGS;

+--------------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+--------------------+-----------+-----------+
| atguigu-bin.000001 | 156 | No |
+--------------------+-----------+-----------+

常用的语句

1
2
3
4
5
6
7
8
9
# 可查看参数帮助
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'
1
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [OFFSET,] ROW_COUNT];
属性 说明
IN ‘log_name’ 指定要查询的binlog文件名 (不指定就是第一个binlog文件)
FROM pos 指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算)
LIMIT [offset] 偏移量(不指定就是0)
row_count 查询总条数(不指定就是所有行)
1
2
-- binlog格式查看
SHOW VARIABLES LIKE 'binlog_format';

格式 说明
Row 它不记录sql语句上下文相关信息,仅保存被修改的记录
Statement 每一条会修改数据的sql都会记录在binlog中
Mixed Statement与Row的结合

使用日志恢复数据

如果MySQL服务器启用了二进制日志,在数据库出现意外丢失数据时,可以使用MysQLbinlog工具从指定的时间点开始直到现在或另一个指定的时间点的日志中恢复数据

1
mysqlbinlog [option] filename|mysql –uuser -ppass;
参数 说明
filename 日志文件名
option —start-date、—stop-date 和 —start-position、— stop-position
option选项 说明
—start-date、—stop-date 指定恢复数据库的起始时间点和结束时间点
—start-position、— stop-position 指定恢复数据的开始位置和结束位置

使用mysqlbinlog命令进行恢复操作时,必须是编号小的先恢复,例如atguigu-bin.000001必 须在atguigu-bin.000002之前恢复

删除二进制日志

MySQL的二进制文件可以配置自动删除,同时MySQL提供了安全的手动删除二进制文件的方法

  • PURGE MASTER LOGS:只删除指定部分的二进制日志文件
  • RESET MASTER: 删除所有的二进制日志文 件

PURGE MASTER LOGS: 删除指定日志文件

1
2
PURGE {MASTER | BINARY} LOGS TO ‘指定日志文件名’
PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期’

RESET MASTER:删除所有日志文件

使用RESET MASTER语句,清空所有的binlog日志。MySQL会重新创建二进制文件,新的日志文件扩展名将重新从o00001开始编号。慎用!

二进制日志 写入机制

事务执行过程中先把日志写到binlog cache,事务提交时再 把binlog cache写到binlog文件。一个事务的binlog不能被拆开,无论这个事务多大,也要确保一 次性写入,所以系统会给每个线程分配一个块内存作为binlog cache

可以通过binlog_cache_size参数控制单个线程binlog cache大小,如果存储内容超过这个参数,就要暂存到磁盘(Swap)

binlog日志刷盘流程如下:

write:将日志写入文件系统的page cache,并没有把数据持久化到磁盘,速度比较快

fsync:酱数据持久化到磁盘

write和fsync的时机可以由参数sync_binlog控制,默认是0。为0时表示每次提交事务都只 write,由系统自行判断执行fsync的时机。虽然性能得到提升,但是机器宕机,page cache里面的 binglog 会丢失。如下图:

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

在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。同样的,如果机器宕 机,会丢失最近N个事务的binlog日志。

binlog与redolog对比

  • redo log:它是物理日志,记录内容是“在某个数据页上做的修改”,由InnoDB 存储引擎层产生 。redo log让lnnoDB存储引擎拥有崩溃恢复能力
  • binlog:它是逻辑日志,记录内容是语句的原始逻辑,属于 MySQL Server 层 。binlog保证MySQL集群架构的数据一致性

两阶段提交

在执行更新语句过程会记录redo logbinlog日志,以基本的事务为单位,redo log在事务执行过程 中可以不断写入,而binlog只有在提交事务时才写入,所以redo logbinlog的 写入时机 不一样。

redo logbinlog两份日志之间的逻辑不一致的话:

以update语句为例,假设id=2的记录,字段c值是0,把字段c值更新成1

1
UPDATE T SET c=1 WHERE id=2;

假设执行过程中写完redo log日志后,binlog日志写期间发生异常,会出现什么情况呢?

由于binlog没写完就异常,这时binlog里面没有对应的修改记录。因此之后用binlog日志恢复数据时就会少这一次更新,恢复出来的这一行c值是0,而原库因redo log日志恢复,这一行c值是1,最终数据不一致。

为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案,即将redo log写入拆成preparecommit(两阶段提交)

使用两阶段提交后,写入binlog时发生异常也不会有影响,因为MySQL根据redo log日志恢复数据时,发现redo log还处于prepare阶段,并且没有对应binlog日志,就会回滚该事务。

redo log设置commit阶段发生异常并不会回滚事务 :

它会执行上图框住的逻辑,虽然redo log处于prepare阶段,但是能通过事务id找到对 应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据

中继日志(relay log)

中继日志只在主从服务器架构的从服务器上存在服务器为与服务器保持一致,要从服务器读取二进制日志,并且把读取到的信息写入本地的日志文件,该服务器本地的日志文件就叫中继日志

然后,服务器读取中继日志,并根据中继日志服务器的数据进行更新,完成主从服务器的数据同步

搭建好主从服务器后,中继日志默认会保存在服务器的数据目录下,文件名的格式是: 从服务器名 -relay-bin.序号中继日志还有一个索引文件:从服务器名 -relaybin.index,用来定位当前正在使用的中继日志。

查看中继日志

中继日志与二进制日志的格式相同,可以用mysqlbinlog工具进行查看

恢复的典型错误

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