前言

  一、错误日志

  二、慢查询日志

  三、查询日志

  四、二进制binlog日志

  五、redo log(InnoDB 引擎日志文件)

binlog 与 redolog的区别

  六、Mysql 执行一条更新操作的整体流程


前言

  对于Myql来说,其所包含的文件有多种,主要有如下几种:

  参数文件:存储了Mysql启动与运行时配置信息相关的属性;如 my.cnf配置文件存储了Mysql 相应的属性。

  日志文件:记录了Mysql在运行时产生的日志信息,可用于对操作日志审计恢复数据等。通常所说的日志文件有:错误日志、二进制日志文件、慢查询日志文件、查询日志文件等。

  pid 文件:Mysql 实例进程的 ID 文件。

  Mysql 表结构文件:用于存放表结构的定义文件。

  存储引擎文件:Mysql的引擎对应的是表,每个引擎都有自己存储数据对应的文件格式。这些引擎文件存储了真正的数据与索引信息。

  本文重点介绍Mysql的日志架构,因此下文着重介绍Mysql的日志文件。

  笔者整理后,主要有以下几种日志文件:binlog 、redolog、error log、show query log、log。如下图所示:

Mysql 之日志架构-LMLPHP


一、错误日志

 存储内容:错误日志文件对MySQL的启动、运行、关闭过程进行了记录。默认为开启。

  •  1. mysql 错误日志存储路径(或者直接查看配置文件my.cnf):
mysql> SHOW VARIABLES LIKE 'log_error';
+---------------+------------+
| Variable_name | Value      |
+---------------+------------+
| log_error     | ./dn02.err |
+---------------+------------+
1 row in set (0.00 sec)

 如上可知:错误日志存储路径为 ./dn02.err,其中dn02为笔者主机映射域名,/usr/local/mysql/data为笔者mysql安装路径,故绝对路径为:/usr/local/mysql/data/dn02.err

  • 2. 查看错误日志内容

  重启Mysql服务器,查看错误日志如下

2019-06-30T06:16:34.170958Z 0 [Warning] [MY-010909] [Server] /usr/local/mysql/bin/mysqld: Forcing close of thread 1715  user: 'root'.
2019-06-30T06:16:35.756124Z 0 [System] [MY-010910] [Server] /usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.11)  MySQL Community Server - GPL.
2019-06-30T06:16:36.363776Z 0 [Warning] [MY-010915] [Server] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.
2019-06-30T06:16:36.363923Z 0 [System] [MY-010116] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.0.11) starting as process 117663
2019-06-30T06:16:36.382442Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/TBL_PERSON.ibd'
2019-06-30T06:16:36.382542Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/TBL_ORG.ibd'
2019-06-30T06:16:36.382566Z 1 [Warning] [MY-012197] [InnoDB] InnoDB: Unable to open './gzdc/EX_GONGSHANG_01V3_KYDJ.ibd'
2019-06-30T06:16:43.610735Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2019-06-30T06:16:43.636304Z 0 [System] [MY-010931] [Server] /usr/local/mysql/bin/mysqld: ready for connections. Version: '8.0.11'  socket: '/tmp/mysql.sock'  port: 3306  MySQL Community Server - GPL.

  由于错误日志记录了Mysql启动相关的信息,因此当mysql出现与启动或配置属性等服务相关的错误时,第一个应该查看的就是这个错误日志。


二、慢查询日志

 存储内容:记录了查询过程中执行比较慢的SQL语句。默认为关闭。

 前面提到可以通过错误日志得到一些关于数据库优化的信息,而慢查询日志 (slow_log)可帮助DBA定位可能存在问题的SQL语句,从而进行SQL语句层面的优化。

  例如,可以在MySQL启动时设一个阈值,将运行时间超过该值的所有SQL语句都记录到慢查询日志文件中。DBA每天或每过一段时间对其进行检查,确认是否有SQL语句需要进行优化。

   该阈值可以通过参数long-query_time来设置,默认值为10,代表 10秒。在默认情况下,MySQL数据库并不启动慢查询日志,用户需要手工将这个参数设为ON。因此该功能主要是在对SQL语句进行调优时再打开。

查看慢查询日志默认阈值如下:

mysql> SHOW VARIABLES LIKE 'long_query_time'\G;
*************************** 1. row ***************************
Variable_name: long_query_time
        Value: 10.000000
1 row in set (0.00 sec)

慢查询日志启动:

mysql> SET GLOBAL slow_query_log='on';
Query OK, 0 rows affected (0.00 sec)

Mysql 5.1后,如开启了慢查询日志可支持将对应的日志记录于slow_log表中,表结构如下图所示:

mysql> SHOW CREATE TABLE mysql.slow_log\G;
*************************** 1. row ***************************
       Table: slow_log
Create Table: CREATE TABLE `slow_log` (
  `start_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  `user_host` mediumtext NOT NULL,
  `query_time` time(6) NOT NULL,
  `lock_time` time(6) NOT NULL,
  `rows_sent` int(11) NOT NULL,
  `rows_examined` int(11) NOT NULL,
  `db` varchar(512) NOT NULL,
  `last_insert_id` int(11) NOT NULL,
  `insert_id` int(11) NOT NULL,
  `server_id` int(10) unsigned NOT NULL,
  `sql_text` mediumblob NOT NULL,
  `thread_id` bigint(21) unsigned NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'
1 row in set (0.25 sec)

 但是,慢查询默认的日志还是记录于文件中,如下所示:

mysql> SHOW VARIABLES LIKE 'log_output'\G;
*************************** 1. row ***************************
Variable_name: log_output
        Value: FILE
1 row in set (0.00 sec)

修改成存储到表:

mysql> SET GLOBAL log_output='TABLE';

测试:

mysql> select sleep (11)\G;
*************************** 1. row ***************************
sleep (11): 0
1 row in set (11.00 sec)

  这条查询语句执行时间超过10秒,按理来说会被记录到slow_log 慢查询日志中。

  验证:

mysql> SELECT * FROM mysql.slow_log\G;
*************************** 1. row ***************************
    start_time: 2019-06-30 15:19:50.519724
     user_host: root[root] @ localhost []
    query_time: 00:00:11.000336
     lock_time: 00:00:00.000000
     rows_sent: 1
 rows_examined: 0
            db:
last_insert_id: 0
     insert_id: 0
     server_id: 1
      sql_text: select sleep (11)
     thread_id: 14
1 row in set (0.00 sec)

三、查询日志

存储内容:记录了所有对数据库的请求,无论执行请求是否得到正确结果。默认为关闭。

 也可跟慢查询日志一样将记录信息记录到表中。

  • 1. 查询是否开启查询日志功能:
mysql> SHOW VARIABLES LIKE '%general_log%'\G;
*************************** 1. row ***************************
Variable_name: general_log
        Value: OFF
*************************** 2. row ***************************
Variable_name: general_log_file
        Value: /usr/local/mysql/data/dn02.log
2 rows in set (0.01 sec)
  • 2. 开启查询日志
SET GLOBAL general_log='on';

 注:因为在前面设置了log存储到表中,因此所有的日志便直接输出到对应的表中了;

开启后没过几分钟便记录下几百条数据,部分样例如下:

*************************** 231. row ***************************
  event_time: 2019-06-30 15:42:20.242534
   user_host: smartbi[smartbi] @ dn02.bmsoft.com.cn [10.194.186.118]
   thread_id: 8
   server_id: 1
command_type: Query
    argument: SET autocommit=1
*************************** 232. row ***************************
  event_time: 2019-06-30 15:42:20.945496
   user_host: root[root] @ localhost []
   thread_id: 14
   server_id: 1
command_type: Query
    argument: select * from general_log
232 rows in set (0.01 sec)

测试完,为了减小数据频繁操作,还是乖乖把它关了为好。

mysql> SET GLOBAL general_log='off';
Query OK, 0 rows affected (0.00 sec)

四、二进制binlog日志

  存储内容:该日志记录了对Mysql执行更新的所有操作,例如 update/delete等,有一点需要注意的是,该记录原则是执行了更新语句便会进入记录,如里执行update操作,但实际没有发生数据的更新也一样会被记录进来。

此外,二进制日志还包括了执行数据库更改操作的时间等其他额外信息。总的来说,二进制日志主要有以下几种作用。

  1. 恢复(recovery):某些数据的恢复需要二进制日志,例如,在一个数据库全备文件恢复后,用户可以通过二进制日志进行point-in-time的恢复。
  2. 复制(replication):其原理与恢复类似,通过复制和执行二进制日志使一台远程的MySQL数据库(一般称为slave或standby) 与一台MySQL数据库 (一般称为master或primary) 进行实时同步。
  3. 审计 (audit):用户可以通过二进制日志中的信息来进行审计,判断是否有对数据库进行注入的攻击。

   在默认情况下,二进制日志并不是在每次写的时候同步到磁盘(用户可以理解成缓冲写)。

   因此,当数据库所在操作系统发生宕机时,可能会有最后一部分数据没有写入二进制日志文件中,这会给恢复和复制带来问题。解决这一点可以引入redolog日志。

  • 1. 可以通过例子感性地认识该日志
mysql> update test.user_t set name='Hadoop' where id=1;
Query OK, 1 row affected (0.08 sec)

  由上述运行结果可知,其实并没有数据发生更新;查看目前该更新操作记录的binlog文件名

mysql> show master status\G;
*************************** 1. row ***************************
             File: binlog.000017
         Position: 485
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

 binlog日志记录于 binlog.000017;其中485为文件大小为

-rw-r----- 1 mysql mysql      485 Jun 30 16:51 binlog.000016

 注:binlog.index 中记录了这些归档日志对应的索引名(简单理解为文件名);

  • 2. 查看具体日志:

 发生的修改后的日志文件如下:

mysql> SHOW BINLOG EVENTS IN 'binlog.000017' \G ;
*************************** 1. row ***************************
   Log_name: binlog.000017
        Pos: 4
 Event_type: Format_desc
  Server_id: 1
End_log_pos: 124
       Info: Server ver: 8.0.11, Binlog ver: 4
*************************** 2. row ***************************
   Log_name: binlog.000017
        Pos: 124
 Event_type: Previous_gtids
  Server_id: 1
End_log_pos: 155
       Info:
*************************** 3. row ***************************
   Log_name: binlog.000017
        Pos: 155
 Event_type: Anonymous_Gtid
  Server_id: 1
End_log_pos: 230
       Info: SET @@SESSION.GTID_NEXT= 'ANONYMOUS'
*************************** 4. row ***************************
   Log_name: binlog.000017
        Pos: 230
 Event_type: Query
  Server_id: 1
End_log_pos: 310
       Info: BEGIN
*************************** 5. row ***************************
   Log_name: binlog.000017
        Pos: 310
 Event_type: Table_map
  Server_id: 1
End_log_pos: 375
       Info: table_id: 62 (test.user_t)
*************************** 6. row ***************************
   Log_name: binlog.000017
        Pos: 375
 Event_type: Update_rows
  Server_id: 1
End_log_pos: 456
       Info: table_id: 62 flags: STMT_END_F
*************************** 7. row ***************************
   Log_name: binlog.000017
        Pos: 456
 Event_type: Xid
  Server_id: 1
End_log_pos: 487
       Info: COMMIT /* xid=8 */
7 rows in set (0.00 sec)
  • 3. 因为是二进制文件,没方法通过cat、more/less 等查看文本文件的方式进行查看,因此用如下方式:
[root@dn02 data]# mysqlbinlog --start-position=1 binlog.000017
...
#190630 17:02:44 server id 1  end_log_pos 375 CRC32 0xf88cd5eb  Table_map: `test`.`user_t` mapped to number 62
# at 375
#190630 17:02:44 server id 1  end_log_pos 456 CRC32 0x13626f55  Update_rows: table id 62 flags: STMT_END_F
....
[root@dn02 data]# 
  • 4. 在Mysql 中查看有关binlog相关的配置属性,会发现特别多,如下所示:
mysql> SHOW VARIABLES LIKE '%binlog%';
+--------------------------------------------+----------------------+
| Variable_name                              | Value                |
+--------------------------------------------+----------------------+
| binlog_cache_size                          | 32768                |
| binlog_checksum                            | CRC32                |
| binlog_direct_non_transactional_updates    | OFF                  |
| binlog_error_action                        | ABORT_SERVER         |
| binlog_expire_logs_seconds                 | 2592000              |
| binlog_format                              | ROW                  |
| binlog_group_commit_sync_delay             | 0                    |
| binlog_group_commit_sync_no_delay_count    | 0                    |
| binlog_gtid_simple_recovery                | ON                   |
| binlog_max_flush_queue_time                | 0                    |
| binlog_order_commits                       | ON                   |
| binlog_row_image                           | FULL                 |
| binlog_row_metadata                        | MINIMAL              |
| binlog_row_value_options                   |                      |
| binlog_rows_query_log_events               | OFF                  |
| binlog_stmt_cache_size                     | 32768                |
| binlog_transaction_dependency_history_size | 25000                |
| binlog_transaction_dependency_tracking     | COMMIT_ORDER         |
| innodb_api_enable_binlog                   | OFF                  |
| log_statements_unsafe_for_binlog           | ON                   |
| max_binlog_cache_size                      | 18446744073709547520 |
| max_binlog_size                            | 1073741824           |
| max_binlog_stmt_cache_size                 | 18446744073709547520 |
| sync_binlog                                | 1                    |
+--------------------------------------------+----------------------+
24 rows in set (0.01 sec)

 如:binlog_expire_logs_seconds                 | 2592000  这个设置意思是binlog.xxx日志保存一个月的记录,也就是说可以通过其恢复一个月内任何时间内对数据所做的处理,包含删除修改等更新操作。


五、redo log(InnoDB 引擎日志文件)

存储内容:记录了 Mysql 中实际被修改的数据。其主要有以下特点:

  • 1. InnoDB特有的,可用于解决Mysql 的 crash-safe 问题;注:数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。
  • 2. 在对数据进行操作时,为了减少磁盘IO开销,数据不会立马写入数据存储对应的磁盘中,而是先写入日志中。MySQL里面有一种叫做WAL(Write-Ahead Logging),就是先写日志在写磁盘。就是当有一条记录需要更新的时候,InnoDB 会先写redo log 里面,并更新内存,这个时候更新的操作就算完成了。之后,MySQL会在合适的时候将操作记录 flush 到磁盘上面。当然 flush 的条件可能是系统比较空闲,或者是 redo log 空间不足时。
  • 3. redo log 文件的大小是固定的,其通过循环写的方式往redolog中写入数据,当空间不足时则flush。如下图所示:

binlog 与 redolog的区别

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log是物理日志,记录的是"在某个数据页上做了什么修改" ; binlog是逻辑日志,记录的是这个语句的原始逻辑,比如"给ID-2这一行的c字段加1"。
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。"追加写"是指binlog写到一定大小后会切换到下一个,并不会覆盖以前的日志。

Mysql 之日志架构-LMLPHP


六、Mysql 执行一条更新操作的整体流程

  • 执行的语句如下:
mysql> update T set c=c+1 where ID=2;

在上一篇文章中,我们知道Mysql中执行一条查询语句,其执行流程图如下图:

Mysql 之日志架构-LMLPHP

  • 同理,在执行更新操作也基本与查询一样,主要的不同之处是更新的操作会涉及对binlog、redolog日志进行更新。
  • 其更新过程如下图所示:图中浅色框表示是在InnoDB内部执行的,深色框表示是在执行器中执行的。

Mysql 之日志架构-LMLPHP

  通过上图可看出,对于redolog日志是先写入然后进入prepare阶段,然后再写入binlog,两个都写成功后再进行一起提交,对于redolog从专业术语上来说,这就是redolog的两阶段提交。 

  两阶段提交主要是为了后期当通过binlog对数据进行恢复时,能确保binlog与redolog对应的数据是一致的。

  详细学习redolog与binlog 推荐阅读极客时间《Mysql常见的6个日志问题》一文


注:参考极客时间《日志系统:一条SQL更新语句是如何执行的?

Mysql技术内幕InnoDB存储引擎

07-13 05:53