MySQL是一个功能强大的关系型数据库管理系统,它的高可靠性、高性能和易用性使得它成为众多企业和开发者的首选。在MySQL内部,为了保证数据的完整性、恢复能力和并发性能,设计了一套复杂的日志系统。其中,redo log、bin log和undo log是MySQL中最为重要的三种日志,它们各自扮演着不同的角色,共同维护着数据库的稳定运行。
MySQL的日志系统概述
MySQL的日志系统是其稳定性和性能的重要保障。MySQL的日志主要包括以下几种:
-
错误日志(Error Log):记录启动、运行或停止mysqld时出现的问题。
-
查询日志(General Query Log):记录已连接到MySQL服务器的客户端所执行的SQL语句。
-
慢查询日志(Slow Query Log):记录执行时间超过指定阈值的SQL语句。
-
二进制日志(Binary Log,简称bin log):记录所有更改数据或可能更改数据的SQL语句,并以二进制格式保存在磁盘上。
-
重做日志(Redo Log):InnoDB存储引擎特有的日志,用于保证事务的ACID特性。
-
回滚日志(Undo Log):也是InnoDB存储引擎特有的日志,用于事务的回滚操作。
binlog详解
binlog是MySQL服务器层的日志,用于记录所有更改数据或可能更改数据的SQL语句。它主要用于数据复制和恢复操作。【一致性:C】
1. 记录格式:
-
binlog支持多种记录格式,如STATEMENT、ROW和MIXED。不同的格式有不同的优缺点,需要根据实际场景选择合适的格式。
2. 写入机制:
-
当执行一个可能修改数据的SQL语句时,MySQL服务器会将其记录到binlog中。
-
binlog的写入是同步的,即写入操作完成后才会返回给客户端。
3. 刷盘时机:
-
在事务提交时,为了保证数据的持久性,会将binlog写入磁盘。
-
与redo log不同,binlog的写入是同步的,即写入磁盘后才能返回给客户端。
4. 日志记录文件组和流程:
-
binlog通常由多个文件组成,当一个文件写满后,会自动切换到下一个文件继续写入。
-
记录流程包括解析SQL语句、生成事件对象、将事件对象写入binlog缓冲区、最后将事件对象写入磁盘文件。
5. binlog的作用:
-
复制:MySQL的主从复制就是依赖于binlog来实现的。主服务器上的binlog会被从服务器读取并执行,从而实现数据的同步。
-
数据恢复:如果MySQL服务器发生了数据丢失或损坏,可以通过binlog中的事件来恢复数据到某个特定的时间点。
-
审计:在某些场景下,binlog也可以用于审计目的,因为它记录了所有的修改操作。
6. binlog的三种格式:
-
ROW:基于行的复制(row-based replication, RBR),每一条会修改数据的SQL语句都会记录为每一行的变化。优点是不需要记录SQL语句上下文信息,不会产生某些特定情况下的主从数据不一致问题。缺点是有可能会产生大量的日志,尤其是修改大量数据的时候。
-
STATEMENT:基于语句的复制(statement-based replication, SBR),每一条会修改数据的SQL语句都会记录在binlog中。优点是不需要记录每一行的变化,减少了binlog日志量,节约了IO,节约了存储空间。缺点是由于记录的只是执行语句,为了保证这些语句在slave上正确运行,还必须记录每条语句在执行时的一些相关信息,例如当前的时间戳、执行的线程ID等。另外,如果SQL语句中包含了一些函数,可能会出现执行结果不一致的情况。
-
MIXED:混合复制(mixed-based replication, MBR),是以上两种格式的混合使用。MySQL会根据执行的SQL语句的类型和系统变量的设置自动选择使用STATEMENT还是ROW格式进行记录。
7. binlog的配置:
要启用binlog,你需要在MySQL的配置文件(如my.cnf或my.ini)中设置log_bin选项,并指定binlog的存储路径和文件名前缀。例如:
[mysqld]
log_bin = /var/log/mysql/mysql-bin
server_id = 1
此外,还可以通过设置binlog_format来指定binlog的格式。
8. binlog数据恢复
使用MySQL的binlog进行数据恢复是一种可靠的方法,特别是当数据丢失或损坏时。以下是使用binlog进行数据恢复的基本步骤:
1). 确定数据丢失的时间点
首先,你需要确定数据丢失或损坏的大致时间点。这通常是通过检查备份、系统日志或询问相关人员来完成的。
2). 找到对应的binlog文件
根据确定的时间点,找到包含该时间点之前所有事件的binlog文件。binlog文件通常位于MySQL服务器配置的目录中,文件名包含了一个时间戳,可以帮助你识别文件。
3). 使用mysqlbinlog工具查看binlog内容
使用mysqlbinlog工具可以查看binlog文件的内容。这个工具可以将binlog文件转换为可读的格式,方便你查看其中的事件。
-- bash
mysqlbinlog /path/to/binlog-file > output.txt
这将把binlog文件的内容输出到output.txt文件中。你可以使用文本编辑器打开这个文件,查找你感兴趣的事件。
4). 确定恢复的位置
在output.txt文件中,找到数据丢失之前的最后一个完整事务的位置。这个位置可以通过查看文件中的GTID、COMMIT等标识来确定。
5). 使用mysqlbinlog提取恢复所需的事件
使用mysqlbinlog工具的--start-position和--stop-position选项,提取从数据丢失之前的最后一个完整事务到数据丢失之前的时间点之间的所有事件。
-- bash
mysqlbinlog --start-position=YOUR_START_POSITION --stop-position=YOUR_STOP_POSITION /path/to/binlog-file > recovery-events.sql
这将生成一个包含恢复所需事件的SQL文件recovery-events.sql。
6). 应用恢复事件
在确保备份了当前数据库状态之后,登录到MySQL服务器,并使用mysql客户端执行recovery-events.sql文件中的SQL语句。
-- bash
mysql -u your_username -p your_database < recovery-events.sql
这将把提取的事件应用到数据库中,恢复数据到丢失之前的状态。
注意事项:
-
备份:在进行任何恢复操作之前,确保备份了当前的数据库状态,以防万一操作出现问题。
-
测试:在正式恢复之前,最好在一个测试环境中进行恢复操作,以确保提取的事件是正确的,并且恢复过程不会引入新的问题。
-
binlog的完整性:确保在数据丢失之前没有删除或修改过binlog文件,否则恢复可能不完整或失败。
-
权限:执行恢复操作时,确保使用的MySQL用户具有足够的权限来执行所需的SQL语句。
通过仔细操作和使用binlog,可以有效地恢复丢失的数据,并保持数据库的完整性和一致性。
undo log详解
数据库事务四大特性中有一个是 原子性 ,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。
我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先先记录到这个回滚日志中,然后再执行相关的操作。
如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。
另外,MVCC
的实现依赖于:隐藏字段、Read View、undo log。在内部实现中,InnoDB
通过数据行的 DB_TRX_ID
和 Read View
来判断数据的可见性,如不可见,则通过数据行的 DB_ROLL_PTR
找到 undo log
中的历史版本。
每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看到该事务创建 Read View
之前已经提交的修改和该事务本身做的修改。
redo log详解
redo log
(重做日志)是InnoDB
存储引擎独有的,它让MySQL
拥有了崩溃恢复能力。
比如 MySQL
实例挂了或宕机了,重启时,InnoDB
存储引擎会使用redo log
恢复数据,保证数据的持久性与完整性。
MySQL
中数据是以页为单位,你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到 Buffer Pool
中。
后续的查询都是先从 Buffer Pool
中找,没有命中再去硬盘加载,减少硬盘 IO
开销,提升性能。
更新表数据的时候,也是如此,发现 Buffer Pool
里存在要更新的数据,就直接在 Buffer Pool
里更新。
然后会把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer
)里,接着刷盘到 redo log
文件里。
理想情况,事务一提交就会进行刷盘操作,但实际上,刷盘的时机是根据策略来进行的。
小贴士:每条 redo 记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成
刷盘时机
InnoDB
存储引擎为 redo log
的刷盘策略提供了 innodb_flush_log_at_trx_commit
参数,它支持三种策略:
-
0 :设置为 0 的时候,表示每次事务提交时不进行刷盘操作
-
1 :设置为 1 的时候,表示每次事务提交时都将进行刷盘操作(默认值)
-
2 :设置为 2 的时候,表示每次事务提交时都只把 redo log buffer 内容写入 page cache
innodb_flush_log_at_trx_commit
参数默认为 1 ,也就是说当事务提交时会调用 fsync
对 redo log 进行刷盘
另外,InnoDB
存储引擎有一个后台线程,每隔1
秒,就会把 redo log buffer
中的内容写到文件系统缓存(page cache
),然后调用 fsync
刷盘。
也就是说,一个没有提交事务的 redo log
记录,也可能会刷盘。