六大日志文件的概述、通用查询日志、错误日志、binlog日志的参数设置与实现数据恢复演示、binlog的删除、binlog的写入机制与两阶段提交、中继日志
# 第17章_其他数据库日志

# 千万不要小看日志。很多看似奇怪的问题,答案往往就藏在日志里。很多情况下,
# 只有通过查看日志才能发现问题的原因,真正解决问题。所以,一定要学会查看日志,养成检查日志的习惯,
# 对提升你的数据库应用开发能力至关重要。

# 1. MySQL支持的日志

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

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

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

# 1.2 日志的弊端
# 日志功能会 降低MySQL数据库的性能 。
# 日志会 占用大量的磁盘空间 。

# 2. 慢查询日志(slow query log)

# 3. 通用查询日志(general query log)

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

# 3.2 查看当前状态

SHOW VARIABLES LIKE '%general%';

# 3.3 启动日志
# 方式1:永久性方式
# 修改my.cnf或者my.ini配置文件来设置。在[mysqld]组下加入log选项,并重启MySQL服务。格式如下:
# [mysqld]
# general_log=ON
# general_log_file=[path[filename]] #日志文件所在目录路径,filename为日志文件名
# 如果不指定目录和文件名,通用查询日志将默认存储在MySQL数据目录中的hostname.log文件中,hostname表示主机名。

# 方式2:临时性方式
# SET GLOBAL general_log=on; # 开启通用查询日志
# SET GLOBAL general_log_file=’path/filename’; # 设置日志文件保存位置
# 对应的,关闭操作SQL命令如下:
# SET GLOBAL general_log=off; # 关闭通用查询日志
# 查看设置后情况:
# SHOW VARIABLES LIKE 'general_log%';

SET GLOBAL general_log = ON;

# 3.4 查看日志
# 通用查询日志是以 文本文件 的形式存储在文件系统中的,可以使用 文本编辑器 直接打开日志文件。
# 每台MySQL服务器的通用查询日志内容是不同的。
# 在Windows操作系统中,使用文本文件查看器;
# 在Linux系统中,可以使用vi工具或者gedit工具查看;
# 在Mac OSX系统中,可以使用文本文件查看器或者vi等工具查看。
# 从 SHOW VARIABLES LIKE 'general_log%'; 结果中可以看到通用查询日志的位置。

SHOW VARIABLES LIKE '%general%';

USE atguigudb3;

SHOW TABLES;

SELECT * FROM student;

DELETE FROM student WHERE id = 20;

# 在通用查询日志里面,我们可以清楚地看到,什么时候开启了新的客户端登陆数据库,登录之后做了什
# 么 SQL 操作,针对的是哪个数据表等信息。

# 3.5 停止日志
# 方式1:永久性方式
# 修改 my.cnf 或者 my.ini 文件,把[mysqld]组下的 general_log 值设置为 OFF 或者把general_log一项注释掉。
# 修改保存后,再 重启MySQL服务 ,即可生效。 举例1:
# [mysqld]
# general_log=OFF
# 举例2:
# [mysqld]
#general_log=ON

# 方式2:临时性方式
# 使用SET语句停止MySQL通用查询日志功能:
# SET GLOBAL general_log=off;
# 查询通用日志功能:
# SHOW VARIABLES LIKE 'general_log%';

SET GLOBAL general_log = OFF;

SELECT * FROM student;

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

# 手动删除文件
# SHOW VARIABLES LIKE 'general_log%';

# 可以看出,通用查询日志的目录默认为MySQL数据目录。在该目录下手动删除通用查询日志atguigu01.log。

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

# mysqladmin -uroot -p flush-logs

#Linux下执行
# mysqladmin -uroot -p flush-logs

# 4. 错误日志(error log)

# 4.1 启动日志
# 在MySQL数据库中,错误日志功能是 默认开启 的。而且,错误日志 无法被禁止 。
# 默认情况下,错误日志存储在MySQL数据库的数据文件夹下,
# 名称默认为 mysqld.log (Linux系统)或hostname.err (mac系统)。
# 如果需要制定文件名,则需要在my.cnf或者my.ini中做如下配置:
# [mysqld]
# log-error=[path/[filename]] #path为日志文件所在的目录路径,filename为日志文件名
# 修改配置项后,需要重启MySQL服务以生效。

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

SHOW VARIABLES LIKE 'log_err%';

# 执行结果中可以看到错误日志文件是mysqld.log,位于MySQL默认的数据目录下。

# 4.3 删除\刷新日志

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

#Linux下执行
# mysqladmin -uroot -p flush-logs

# [root@atguigu01 log]# mysqladmin -uroot -p flush-logs
# Enter password:
# mysqladmin: refresh failed; error: 'Could not open file '/var/log/mysqld.log' for
# error logging.'

# 补充操作:
# install -omysql -gmysql -m0644 /dev/null /var/log/mysqld.log

# 5. 二进制日志(bin log)

# binlog可以说是MySQL中比较 重要 的日志了,在日常开发及运维过程中,经常会遇到。

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

# binlog主要应用场景:
# 一是用于 数据恢复
# 二是用于 数据复制

# 5.1 查看默认情况

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

SHOW VARIABLES LIKE '%log_bin%';

# 5.2 日志参数设置

# 方式1:永久性方式

# 修改MySQL的 my.cnf 或 my.ini 文件可以设置二进制日志的相关参数:

# [mysqld]
#启用二进制日志
# log-bin=server2-bin
# binlog_expire_logs_seconds=600
# max_binlog_size=100M

# 重新启动MySQL服务,查询二进制日志的信息,执行结果:
SHOW VARIABLES LIKE '%log_bin%';

SET SESSION sql_log_bin = 1;

SHOW VARIABLES LIKE '%log_bin%';

# 设置带文件夹的bin-log日志存放目录

# 如果想改变日志文件的目录和名称,可以对my.cnf或my.ini中的log_bin参数修改如下:
# [mysqld]
# log-bin="/var/lib/mysql/binlog/atguigu-bin"

# 注意:新建的文件夹需要使用mysql用户,使用下面的命令即可。
# chown -R -v mysql:mysql binlog

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

# global 级别
# mysql> set global sql_log_bin=0;
# ERROR 1228 (HY000): Variable 'sql_log_bin' is a SESSION variable and can`t be used
# with SET GLOBAL

# session级别
# mysql> SET sql_log_bin=0;
# Query OK, 0 rows affected (0.01 秒)

# 5.3 查看日志

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

# MySQL服务 重新启动一次 ,以“.000001”为后缀的文件就会增加一个,并且后缀名按1递增。
# 即日志文件的个数与MySQL服务启动的次数相同;如果日志长度超过了 max_binlog_size 的上限(默认是1GB),
# 就会创建一个新的日志文件。

# 查看当前的二进制日志文件列表及大小。指令如下:

SHOW BINARY LOGS;

#开始查看binlog

USE atguigudb3;

SELECT * FROM student;

INSERT INTO student(id, name, class)
VALUES (18,'Jerry','四班');

UPDATE student SET name = 'Tom1'
WHERE id = 17;

SHOW BINARY LOGS;

# mysqlbinlog "/var/lib/mysql/server2-bin.000002"

# 下面命令将行事件以 伪SQL的形式 表现出来

# mysqlbinlog "/var/lib/mysql/server2-bin.000002"

# 前面的命令同时显示binlog格式的语句,使用如下命令不显示它

# mysqlbinlog -v --base64-output=DECODE-ROWS "/var/lib/mysql/server2-bin.000002"

# 关于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点信息,下面介绍一种更为方便的查询命令:

# mysql> 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 :查询总条数(不指定就是所有行)

SHOW BINLOG EVENTS IN 'server2-bin.000002';

SHOW BINLOG EVENTS IN 'server2-bin.000002' FROM 468;

SHOW BINLOG EVENTS IN 'server2-bin.000002' FROM 468 LIMIT 0,2;

SHOW BINLOG EVENTS IN 'server2-bin.000002' FROM 468 LIMIT 1,3;

# 上面我们讲了这么多都是基于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.4 使用日志恢复数据
# mysqlbinlog恢复数据的语法如下:
# mysqlbinlog [option] filename|mysql –uuser -ppass;

# 这个命令可以这样理解:使用mysqlbinlog命令来读取filename中的内容,
# 然后使用mysql命令将这些内容恢复到数据库中。

# filename :是日志文件名。
# option :可选项,比较重要的两对option参数是--start-date、--stop-date 和 --start-position、
# --stop-position。
#     --start-date 和 --stop-date :可以指定恢复数据库的起始时间点和结束时间点。
#     --start-position和--stop-position :可以指定恢复数据的开始位置和结束位置。

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

SHOW VARIABLES LIKE '%log_bin%';

SHOW BINARY LOGS;

USE atguigudb3;

SELECT * FROM student;

INSERT INTO student(id, name, class)
VALUES (20,'aaa','No.1');

INSERT INTO student(id, name, class)
VALUES (21,'aaa','No.1');

INSERT INTO student(id, name, class)
VALUES (22,'aaa','No.1');

SELECT * FROM student;

DELETE FROM student
WHERE id = 20;

SELECT * FROM student;

UPDATE student SET name = 'bbb'
WHERE id = 21;

SELECT * FROM student;

DELETE FROM student
WHERE id > 20;

SELECT * FROM student;

SHOW BINARY LOGS;

FLUSH LOGS;

SHOW BINARY LOGS;

SHOW BINLOG EVENTS IN 'server2-bin.000002';

#使用position恢复

#恢复增加的数据
# /usr/bin/mysqlbinlog --start-position=884 --stop-position=1729 --database=atguigudb3 /var/lib/mysql/server2-bin.000002 | /usr/bin/mysql -uroot -p123456 -v atguigudb3

SELECT * FROM student;

#恢复删除的数据
# /usr/bin/mysqlbinlog --start-position=1808 --stop-position=2037 --database=atguigudb3 /var/lib/mysql/server2-bin.000002 | /usr/bin/mysql -uroot -p123456 -v atguigudb3

SELECT * FROM student;

#恢复更改的数据
# /usr/bin/mysqlbinlog --start-position=2116 --stop-position=2369 --database=atguigudb3 /var/lib/mysql/server2-bin.000002 | /usr/bin/mysql -uroot -p123456 -v atguigudb3

SELECT * FROM student;

#使用日期恢复

# mysqlbinlog '/var/lib/mysql/server2-bin.000002';

# 5.5 删除二进制日志

# MySQL的二进制文件可以配置自动删除,同时MySQL也提供了安全的手动删除二进制文件的方法。
# PURGE MASTER LOGS 只删除指定部分的二进制日志文件, RESET MASTER 删除所有的二进制日志文件。具体如下:

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

# PURGE MASTER LOGS语法如下:
# PURGE {MASTER | BINARY} LOGS TO ‘指定日志文件名’
# PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期’

SHOW BINARY LOGS;

FLUSH LOGS;

FLUSH LOGS;

FLUSH LOGS;

FLUSH LOGS;

SHOW BINARY LOGS;

PURGE MASTER LOGS TO 'server2-bin.000003';

PURGE MASTER LOGS BEFORE '20220105';

# 2. RESET MASTER:删除所有二进制日志文件

RESET MASTER;

SHOW BINARY LOGS;

# 5.6 其它场景

# 二进制日志可以通过数据库的 全量备份 和二进制日志中保存的 增量信息 ,完成数据库的 无损失恢复 。
# 但是,如果遇到数据量大、数据库和数据表很多(比如分库分表的应用)的场景,用二进制日志进行数据恢复,
# 是很有挑战性的,因为起止位置不容易管理。

# 在这种情况下,一个有效的解决办法是 配置主从数据库服务器 ,甚至是 一主多从 的架构,
# 把二进制日志文件的内容通过中继日志,同步到从数据库服务器中,
# 这样就可以有效避免数据库故障导致的数据异常等问题。

# 6. 再谈二进制日志(binlog)

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

# 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日志。

# 6.2 binlog与redolog对比
# redo log 它是 物理日志 ,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎层产生的。

# 而 binlog 是 逻辑日志 ,记录内容是语句的原始逻辑,类似于“给 ID=2 这一行的 c 字段加 1”,
# 属于MySQL Server 层。

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

# 7. 中继日志(relay log)

# 7.1 介绍
# 中继日志只在主从服务器架构的从服务器上存在。从服务器为了与主服务器保持一致,
# 要从主服务器读取二进制日志的内容,并且把读取到的信息写入 本地的日志文件 中,
# 这个从服务器本地的日志文件就叫中继日志 。然后,从服务器读取中继日志,
# 并根据中继日志的内容对从服务器的数据进行更新,完成主从服务器的 数据同步 。

# 搭建好主从服务器之后,中继日志默认会保存在从服务器的数据目录下。

# 文件名的格式是: 从服务器名 -relay-bin.序号 。中继日志还有一个索引文件: 从服务器名 -relay-bin.index ,
# 用来定位当前正在使用的中继日志。

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

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

# 解决的方法也很简单,把从服务器的名称改回之前的名称。


6. 再谈二进制日志(binlog)

6.1 写入机制

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

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日志。

6.2 binlog与redolog对比

redo log 它是 物理日志 ,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎层产生
的。
而 binlog 是 逻辑日志 ,记录内容是语句的原始逻辑,类似于“给 ID=2 这一行的 c 字段加 1”,属于
MySQL Server 层。

6.3 两阶段提交

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

redo log与binlog两份日志之间的逻辑不一致,会出现什么问题?

由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。

为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。

使用两阶段提交后,写入binlog时发生异常也不会有影响

另一个场景,redo log设置commit阶段发生异常,那会不会回滚事务呢?

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

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇