天天看点

MySQL的日志类型

重做日志(redo log)

作用

重做日志用来实现事务的持久性,即事务ACID中的D。其由两部分组成:一是内存中的重做日志缓冲(redo log buffer),其是易失的;二是重做日志文件(redo log file),其是持久的。

原理

InnoDB是事务的存储引擎,其通过Force Log at Commit机制实现事务的持久性,即当事务提交(COMMIT)时,必须先将该事务的所有日志写入到日志文件进行持久化,待事务的COMMIT操作完成才算完成。这里的日志是指redo log和undo log。redo log用来保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能。redo log基本上都是顺序写的,在数据库运行时不需要对redo log的文件进行读取操作。而undo log是需要进行随机读写的。

参数​

​innodb_flush_log_at_trx_commit​

​用来控制重做日志刷新到磁盘的策略:

  • ​0​

    ​:表示每次事务提交时不进行fsync操作,这个操作仅在master thread中完成,而在master thread中每1秒会进行一次重做日志文件的fsync操作,当系统挂掉会丢失一秒的数据。
  • ​1​

    ​:表示每次事务提交时必须调用一次fsync操作,默认值是1,不会丢失数据,性能最差。
  • ​2​

    ​:表示事务提交时仅写入文件系统的缓存中,不进行fsync操作,也就是只将文件从用户态转换成系统态,这样只要操作系统不挂掉,数据就不会丢失。

插入50万行记录,不同日志刷新策略的速度如下:

innodb_flush_log_at_trx_commit 执行时间
13.9秒
1 113.11秒
2 23.37秒

我们现在线上,金融类的服务设置的是1,其他服务设置的是2。

内容

是物理格式日志,其记录的是对于每个页的修改。

存储方式

在InnoDB存储引擎中,重做日志都是以512字节进行存储的。这意味着重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,称之为重做日志块(redo log block),每块的大小为512字节。

重做日志格式:

redo_log_type space page_no redo log body
  • ​redo_log_type​

    ​:重做日志的类型。
  • ​space​

    ​:表空间的ID。
  • ​page_no​

    ​:页的偏移量。
  • ​redo log body​

    ​:文件类容

文件位置

通过命令​

​show variables like '%innodb_log_group_home_dir%';​

​我们可以查询到文件位置:

mysql> show variables like '%innodb_log_group_home_dir%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_group_home_dir | .\    |
+---------------------------+-------+
1 row in set      

​.\​

​​表示数据库​

​Data​

​目录。

什么时候产生

在事务进行过程中不断的被写入,一个事务可能会有多条日志。

什么时候释放

当对应事务的脏页写入到磁盘之后,redo log的就会被清除,重做日志占用的空间就可以被重用。

重做日志是幂等的。

回滚日志(undo log)

作用

回滚日志主要用来解决事务的回滚和MVCC。

原理

undo也需要Force Log at Commit机制来保证undo log刷入磁盘。

内容

undo是逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。

存储方式

InnoDB存储引擎对undo的管理同样采用段的方式,首先InnoDB存储引擎有rollback segment,每个回滚段种记录了1024个undo log segment,而在每个undo log segment段中进行undo页的申请。

文件位置

通过命令​

​show variables like '%innodb_undo_directory%';​

​我们可以查询到文件位置:

mysql> show variables like '%innodb_undo_directory%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_undo_directory | .\    |
+-----------------------+-------+
1 row in set      

​.\​

​​表示数据库​

​Data​

​目录,这个参数还可以修改。

什么时候产生

在数据被修改之前,undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。

什么时候释放

事务提交后并不能马上删除undo log及undo log所在的页,而只是将undo log 放入一个链表中,最终是否删除由purge线程来判断。

purge用于最终完成delete和update操作。这样设计是因为InnoDB存储引擎支持MVCC,所以记录不能在事务提交时立即进行处理。这时其他事物可能正在引用这行,故InnoDB存储引擎需要保存记录之前的版本。而是否可以删除该条记录通过purge来进行判断。若该行记录已不被任何其他事务引用,那么就可以进行真正的delete操作。

二进制日志(binlog)

作用

二进制日志主要用来进行POINT-IN-TIME(PIT 基于时间点的还原)的恢复及主从复制(Replication)环境的建立。

原理

重做日志是在InnoDB存储引擎层产生,而二进制日志是在MySQL数据库的上层产生的,并且二进制日志不仅仅针对于InnoDB存储引擎,MySQL数据库中的任何存储引擎对于数据库的更改都会产生二进制日志。

内容

二进制日志是一种逻辑日志,有三种格式,分别为:

  1. ​Statement​

    ​:基于 SQL语句级别的Binlog,每条修改数据的SQL都会保存到Binlog里。
  2. ​Row​

    ​​:基于行级别,将每行数据的变化都记录到 Binlog 里面,并不记录原始 SQL; 在复制的时候, 并不会因为存储过程或触发器造成主从库数据不一致的问通, 但是记录的日志量比​

    ​Statement​

    ​格式要大得多 。
  3. ​Mixed​

    ​​:混合​

    ​Statement​

    ​​和​

    ​Row​

    ​​模式,默认情况下采用​

    ​Statement​

    ​​模式记录,某些情况下会切换到​

    ​Row​

    ​模式。

文件位置

通过命令​

​show variables like '%log_bin_basename%';​

​我们可以查询到文件位置:

mysql> show variables like '%log_bin_basename%';
+------------------+-------------------------------+
| Variable_name    | Value                         |
+------------------+-------------------------------+
| log_bin_basename | /data2/mysql/xxx/mysql-bin |
+------------------+-------------------------------+
1 row in set      

什么时候产生

二进制日志只在事务提交完成后释放锁之前,进行一次写入,一个事务只有一条日志,如果事务比较大,提交事务可能较慢。

什么时候释放

binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除:

mysql> show variables like '%expire_logs_days%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| expire_logs_days | 5     |
+------------------+-------+
1 row in set      

binlog和redo log的区别

binlog和redo log本质上是不一样的:

  • ​redo log​

    ​​是存储引擎层产生,仅支持Innodb;​

    ​binlog​

    ​是mysql数据上层产生,支持所有存储引擎。
  • ​redo log​

    ​​是记录物理日志,记录的是页的物理修改;​

    ​binlog​

    ​记录的是逻辑日志,记录的是SQL语句。
  • ​redo log​

    ​​是在事务进过程中产生,日志内容并不是随着事务提交顺序写入;​

    ​binlog​

    ​是在事务提交完成后进行一次性的写入。
  • ​redo log​

    ​​主要所用是保证事务持久性;​

    ​binlog​

    ​主要用来所恢复和复制。

中继日志(relay log)

作用

​relay log​

​主要用来实现MySQL的复制功能。

复制原理

MySQL的日志类型
  1. 主服务器(master)把数据更改记录到二进制日志(binlog)中,然后通过​

    ​binary log dump​

    ​线程将二进制文件推送到从服务器。
  2. 从服务器(slave)通过I/O线程,把主服务器的二进制日志复制到自己的中继日志(relay log)中,中继日志通常会位于os缓存中,所以中继日志的开销很小。
  3. 从服务器通过SQL线程重做中继日志中的日志,把更改应用到自己的数据库上,以达到数据的最终一致性。

从服务器有2个线程,一个是I/O线程,负责读取主服务器的二进制日志,并将其保存为中继日志;另一个是SQL线程,复制执行中继日志。这里需要特别注意的是,复制是一个异步过程,从服务器数据存在延迟。

查看复制状态

查看当前的延迟,可以通过命令​

​SHOW SLAVE STATUS​

​​和​

​SHOW MASTER STATUS​

​得知。

​SHOW SLAVE STATUS​

​:

mysql>SHOW SLAVE STATUS;
*************************** 1. row ***************************
      Slave_IO_State: Waiting for master to send event
        Master_Host: 192.168.190.10
        Master_User: rep
        Master_Port: 3306
      Connect_Retry: 60
      Master_Log_File: mysql-bin.000007
    Read_Master_Log_Pos: 555176471
      Relay_Log_File: gamedb-relay-bin.000048
      Relay_Log_Pos: 224355889
    Relay_Master_Log_File: mysql-bin.000007
      Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
      Replicate_Do_DB:
    Replicate_Ignore_DB:
    Replicate_Do_Table:
  Replicate_Ignore_Table:
  Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table: mysql.%,DBA.%
        Last_Errno: 0
        Last_Error:
      Skip_Counter: 0
    Exec_Master_Log_Pos: 555176471
      Relay_Log_Space: 224356045
      Until_Condition: None
      Until_Log_File:
      Until_Log_Pos: 0
    Master_SSL_Allowed: No
    Master_SSL_CA_File:
    Master_SSL_CA_Path:
      Master_SSL_Cert:
    Master_SSL_Cipher:
      Master_SSL_Key:
    Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
        Last_IO_Errno: 0
        Last_IO_Error:
      Last_SQL_Errno: 0
      Last_SQL_Error:
1 row in set (0.00 sec)      

主要参数说明:

MySQL的日志类型

​SHOW MASTER STATUS​

​:

mysql>SHOW MASTER STATUS;
*************************** 1. row ***************************
      File: mysql-bin.000007
    Position: 606181078
  Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.01 sec)      

可以看到,当前二进制日志记录了偏移量606181078的位置,该值减去这一时间点时从服务器上的Read_Master_Log_Pos,就可以得知I/O线程的延时。

在考虑监控的时候,我们因该考虑从服务器的I/O线程和SQL线程监控;同时也需要考虑主从服务器之间的延迟。

错误日志(errorlog)

MySQL的错误日志用于记录MySQL服务在启动、关闭和运行过程中遇到的错误信息。可以直接在​

​my.cnf​

​​中配置,也可以通过​

​show variables like 'log_error%';​

​命令查看。

mysql> show variables like 'log_error%';
+---------------------+------------------+
| Variable_name       | Value            |
+---------------------+------------------+
| log_error           | .\CD-HZTK5H2.err |
| log_error_verbosity | 3                |
+---------------------+------------------+
2 rows in set      

文件内容:

2018-04-24T05:53:02.093532Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2018-04-24T05:53:02.093532Z 0 [Warning] '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.
2018-04-24T05:53:02.095758Z 0 [Note] C:\Program Files\MySQL\MySQL Server 5.7\bin\mysqld.exe (mysqld 5.7.17-log) starting as process 7196 ...
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Uses event mutexes
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: _mm_lfence() and _mm_sfence() are used for memory barrier
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Adjusting innodb_buffer_pool_instances from 8 to 1 since innodb_buffer_pool_size is less than 1024 MiB
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Number of pools: 1
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Not using CPU crc32 instructions
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Initializing buffer pool, total size = 8M, instances = 1, chunk size = 8M
2018-04-24T05:53:02.099268Z 0 [Note] InnoDB: Completed initialization of buffer pool
2018-04-24T05:53:02.130523Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
2018-04-24T05:53:02.199317Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2018-04-24T05:53:02.199317Z 0 [Note] InnoDB: Setting file '.\ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2018-04-24T05:53:02.230607Z 0 [Note] InnoDB: File '.\ibtmp1' size is now 12 MB.
2018-04-24T05:53:02.261912Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
2018-04-24T05:53:02.261912Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
2018-04-24T05:53:02.261912Z 0 [Note] InnoDB: Waiting for purge to start
2018-04-24T05:53:02.330562Z 0 [Note] InnoDB: 5.7.17 started; log sequence number 2535181
2018-04-24T05:53:02.330562Z 0 [Note] InnoDB: Loading buffer pool(s) from C:\ProgramData\MySQL\MySQL Server 5.7\Data\ib_buffer_pool
2018-04-24T05:53:02.330562Z 0 [Note] Plugin 'FEDERATED' is disabled.
2018-04-24T05:53:02.345812Z 0 [Note] InnoDB: Buffer pool(s) load completed at 180424 13:53:02
2018-04-24T05:53:02.345812Z 0 [Warning] Failed to set up SSL because of the following SSL library error: SSL context is not usable without certificate and private key
2018-04-24T05:53:02.345812Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
2018-04-24T05:53:02.345812Z 0 [Note] IPv6 is available.
2018-04-24T05:53:02.361434Z 0 [Note]   - '::' resolves to '::';
2018-04-24T05:53:02.361434Z 0 [Note] Server socket created on IP: '::'.
2018-04-24T05:53:02.398707Z 0 [Note] Event Scheduler: Loaded 0 events
2018-04-24T05:53:02.398707Z 0 [Note] Executing 'SELECT * FROM INFORMATION_SCHEMA.TABLES;' to get a list of tables using the deprecated partition engine. You may use the startup option '--disable-partition-engine-check' to skip this check. 
2018-04-24T05:53:02.398707Z 0 [Note] Beginning of list of non-natively partitioned tables
2018-04-24T05:53:02.430064Z 0 [Note] End of list of non-natively partitioned tables
2018-04-24T05:53:02.430064Z 0 [Note] C:\Program Files\MySQL\MySQL Server 5.7\bin\mysqld.exe: ready for connections.
Version: '5.7.17-log'  socket: ''  port: 3306  MySQL Community Server (GPL)
2018-04-24T05:53:03.246194Z 3 [Note] Access denied for user 'root'@'localhost' (using password: YES)
2018-04-24T12:03:13.235530Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 6142555ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)
2018-04-24T12:19:42.998307Z 0 [Note] C:\Program Files\MySQL\MySQL Server 5.7\bin\mysqld.exe: Normal shutdown
...      

慢查询日志(slow query log)

SQL语句在数据库中执行超时时,会产生该日志,通过对这些特殊的SQL语句分析,改进以达到提高数据库性能的目的。

重要参数

注意:修改以下参数,需要重新启动数据库服务才会生效。

​​

​slow_query_log=off|on​

​​:是否开启慢查询日志。

​​

​slow_query_log_file=filename​

​​:指定保存路径及文件名,默认为数据文件目录。

​​

​long_query_time=2​

​​:指定多少秒返回查询的结果为慢查询。

​​

​long-queries-not-using-indexes​

​​:记录所有没有使用到索引的查询语句。

​​

​min_examined_row_limit=1000​

​​: 记录那些由于查找了多余1000次而引发的慢查询。

​​

​long-slow-admin-statements​

​​:记录那些慢的optimize table,analyze table和alter table语句。

​​

​log-slow-Slave-statements​

​:记录由Slave所产生的慢查询。

通过​

​show variables like '%slow_query_log%'​

​可以查看参数值。

实战:

show variables like '%slow_query_log%'; #  查看慢日志参数
SET GLOBAL  slow_query_log = 1; # 打开慢日志
SET long_query_time=0.000001; # 设置超时时间
SELECT * FROM `user` WHERE `name` = 'wyf'; #执行查询      

慢日志文件:

# Time: 2020-05-06T09:36:02.242452Z
# User@Host: root[root] @ localhost [::1]  Id:     6
# Query_time: 0.001961  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 1
SET timestamp=1588757762;
SELECT * FROM `user` WHERE `name` = 'wyf';

# Time: 2020-05-06T09:36:02.257462Z
# User@Host: root[root] @ localhost [::1]  Id:     6
# Query_time: 0.001041  Lock_time: 0.000000 Rows_sent: 16  Rows_examined: 315
SET timestamp=1588757762;
SELECT STATE AS `状态`, ROUND(SUM(DURATION),7) AS `期间`, CONCAT(ROUND(SUM(DURATION)/0.002464*100,3), '%') AS `百分比` FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID=301 GROUP BY STATE ORDER BY SEQ;      

通过慢日志工具 ​

​mysqldumpslow​

​可以对慢日志进行分析:

常用慢查询分析工具

  • mysqldumpslow(结果简陋不方便阅读分析)
  • mysqlsla
  • percona-toolkit中的pt-query-digest

一般查询日志(general log)

当客户端连接数据库执行SQL语句时会产生该日志。

DDL 日志(metadata log)

执行DDL语句时会产生该日志。

总结

日志类型 说明 默认名称 文件选项 开启选项 产生时间 释放时间
General query log 记录从客户端获取到的连接和语句 host_name.log general_log_file=file_name general_log 在服务器接收到客户端发来的命令时就写入到日志中
Slow query log 记录超过long_query_time时间的查询 host_name-slow.log low_query_log_file=file_name slow_query_log 在语句执行完毕,释放锁之后写入到日志中
Binary log 记录修改数据的语句 pif-file-bin log_bin=base_name log-bin 在语句执行完毕,释放锁之前写入到日志中 到期自动删除
Error log 记录在mysqld服务启动、运行或停止时遇到的问题 host_name.err log_error=file_name log-error
Relay log 在复制结构中,从库从主库获取到的数据修改 hostname-relay-bin.nnnnnn relay-log=file_name 不需要额外开启 I/O线程写入 SQL线程重做后删除
DDL log DD语句执行的元数据操作 ddl_log.log 无法修改 不需要额外开启 执行DDL语句时
redo log 重做日志 .\ 不需要额外开启 事务进行时
undo log 回滚日志 .\

继续阅读