mysql 系列:日志

摘要

日志的存在,为数据库的很多功能提供了保障。像用于回滚数据的 undo log,用于恢复数据的 redo log, 以及用于主从备份的 binlog。本文将会大致介绍下数据库里的日志类别,以及重点分析下事务日志的相关知识点。

日志分类

在 mysql 里的日志种类有很多,从总体上来讲可以分为 Server 层存储引擎层的(关于 mysql 的总体架构可以看这篇:mysql 系列:总体架构概述)。

Server 层里的日志分类如下:

错误日志

错误日志是 mysql 在启动、运行或停止时出现异常的日志。我们可以通过下面这个命令来查看错误日志的位置:

SHOW VARIABLES LIKE 'log_error';

上面默认查询到的是 stderr,表示标准错误输出,如果有终端存在,则只会在终端打印错误。 当然,我们也可以在 my.cnf 里设置错误日志位置:

[mysqld]
 log-error=错误日志位置

使用场景:像我们在启动 mysql 失败时,一般可以到错误日志里查看。

通用查询日志

通用查询日志记录了用户的所有操作,包括 sql 语句的查询更新。一般情况下是不会开启的,有点类似于我们平时使用 debug 级别的日志。同样的,我们也可以通过下面的语句来查看是否开启及其输出位置:

SHOW VARIABLES LIKE '%general%';

当我们想要开启通用查询日志,以记录所有客户端的 sql 操作时,就可以用下面的语句了:

SET GLOBAL general_log=on;

上面的日志输出是到文件,如果想要使用 sql 语句来查找日志,可以将日志的输出设置为表:

SET GLOBAL log_output='table';

然后就可以使用下面的 sql 语句来查询了:

select * from mysql.general_log;

这样就可以监控到所有客户端的操作情况了,当然,不要忘记使用完后关闭日志,否则将会占用很大的磁盘空间。

DDL 日志

DDL 日志记录了数据库里元数据的变更信息。DDL 即数据定义语句,像 create,drop,alter语句。

DDL 日志是一个二进制文件,不被人为的阅读修改,也没有其他配置项可以配置它。一般存放在数据目录下,ddl_log.log 文件即是。而且在成功启动 mysqld 后会被删除,只有在记录元数据时才会被重新创建。

binlog 二进制日志

binlog 日志记录了数据库对数据的修改记录,包括了 DDL,如表的创建,数据更新等。但并不包括 select 这些查询语句.

binlog 日志是属于逻辑语句的记录,可用于主从数据库的同步。

relay log 中继日志

relay log 用于主从备份恢复使用的。当 master 将 binlog 传送过来后,slave 服务器会有一个 I/O 线程来处理接收到的日志,并且将其维护到 relay log 里。

relay log 有了主服务器的 binlog 逻辑操作语句后,就可以还原数据库了。

relay log 除了包含 binlog 的内容,还会记录当前恢复到哪个位置。如果从服务器断开重连,则可以从上次记录的位置开始恢复。

慢查询日志

慢查询日志用于记录在 mysql 里执行时间超过预期值的耗时语句,主要用于性能瓶颈分析。

一般慢查询记录需要手动设置:

SET GLOBAL slow_query_log=1;

至于其日志的记录位置,可以这么查询:

SHOW VARIABLES LIKE '%slow_query_log%';

而时间阈值的查询则如下:

SHOW VARIABLES LIKE 'long_query_time%';

对应的设置语句:

SET GLOBAL long_query_time=8;

事务日志

事务日志是 InnoDB 存储引擎为了支持事务的持久化而设计的,主要是 redo log 和 undo log。

redo log

redo log 是对加载到内存数据页修改结果的记录,和 binlog 不同的是,binlog 记录的是逻辑操作语句,偏向于过程记录。而 redo log 是一个数据页的修改日志,偏向于结果的记录。

在 mysql 里每当执行一个事务时,并不会时时的将数据修改同步到硬盘上。而是会在内存里维护了一个 buffer pool,在读取更新数据的时候会优先从这里操作,数据不存在则会从磁盘加载后再操作。

而内存里修改的数据也不会一直驻留着,会定时的更新到磁盘上,这就是所谓的脏页刷盘

细心的朋友可能会发现内存数据并不可靠,要是发生断电,导致 buffer pool 里的数据不能落地到磁盘,那岂不是会丢失数据?这个就是 redo log 发挥作用的时候了。

每当有事务执行操作后,会将刚刚对数据页的修改结果先记录到 redo log,然后才提交事务。这种日志先行的做法,保证了即使来不及同步数据也能从日志里恢复。

事实上,在修改了内存数据页并写入 redo log 后,事务此时也只是标记为 prepare 状态而已,并不会标为 commit 状态,只有当 binlog 也写入成功后才会真正的 commit。

之所以要把 binlog 写入成功后才算完整 commit,主要是因为 binlog 用于从数据库的恢复,如果 redo log 写入成功,binlog 没有写入成功,那么就会导致主数据库有此操作结果的数据,而从数据库同步时缺失数据。

这种 2 次提交状态,被 mysql 称为了二阶段提交。除此之外,redo log、binlog 还有个组提交的过程,主要是用于批量的进行事务的提交,日志的写入。

undo log

回滚日志主要用于回滚数据,和 redo log 不一样的是,undo log 是逻辑日志,是一种相反操作的记录,比如在回滚时,如果是 insert 操作时,则会逆向为 delete,delete 操作时,逆向为 insert 操作,更新则恢复到当时的版本数据。

undo 还用于 MVCC 版本链的使用,具体可以看看这篇文章:MVCC

总结

在 mysql 一开始其实没有事务日志,后来有了 InnoDB 存储引擎,需要支持事务持久化的特性,所以有了 redo log,undo log。虽然对于开发而言,可能不会涉及到对 mysql 日志相关的运维,但它的实现原理还是值得学习的,或许以后也能实现属于自己的一个持久化数据库~~~ ㋡㋡㋡

上一篇:redis 系列:持久化机制


下一篇:redis 系列:总结篇