如何让MySQL“不会挂”?了解这三大日志系统,让你事半功倍!

背景MySQL实现事务、崩溃恢复、集群的主从复制,底层都离不开日志,所以日志是MySQL的精华所在。只有了解MySQL日志,才算是彻底搞懂MySQL。 今天我就带你深入浅出的学习MySQL的三大日志系统,Redo Log(重做日志)、Undo Log(恢复日志)、Bin Log(备份日志)。

一、Redo Log(重做日志)

Redo Log是一个很有趣的东西,它记录的是物理日志,也就是磁盘数据页的修改。其实它就像一个小助手,当你的MySQL服务器崩溃时,它可以帮助你把事务中变更的数据重新恢复到磁盘上。

当你在MySQL中执行一个事务操作时,MySQL会先把磁盘上需要修改的数据页加载到内存中,然后你对这些数据页进行修改操作。当你修改完之后,新的数据会被写入到一个叫做Redo Log Buffer的缓冲区中。这个缓冲区其实就像一个小水库,暂时存储了你的修改操作。

但是,Redo Log Buffer并不是最终的存储位置,因为直接把修改的数据持久化到磁盘上会非常浪费资源。所以,MySQL采用了一种称为Write-Ahead Logging(预写日志)的方式,先把修改操作写入Redo Log中,再写入磁盘。这样一来,MySQL就可以避免频繁地进行磁盘I/O操作,提高了性能。

下面我们来看一下写入Redo Log的流程:

START TRANSACTION;
-- 修改数据
COMMIT;

当你执行START TRANSACTION语句时,MySQL会创建一个新的事务,并为其分配一个唯一的事务ID(Transaction ID,简称trx_id)。当你修改数据时,MySQL会把修改操作写入到Redo Log Buffer中,并在修改之前将当前事务的trx_id写入到Redo Log中,这样就能保证在恢复数据时只恢复该事务的修改。

当你执行COMMIT语句时,MySQL会把当前事务的Redo Log Buffer刷入到Redo Log文件中。这个过程称为刷盘(Flush),也就是把内存中的数据持久化到磁盘中。你可能会问,什么时候才会把Redo Log文件中的数据持久化到数据库磁盘中呢?这要看你的innodb_flush_log_at_trx_commit参数配置了什么值。

如果你将innodb_flush_log_at_trx_commit的值设为0(延迟写),那么提交事务后,Redo Log会延迟一秒钟刷入到OS Buffer中,然后再调用fsync()操作将其写入Redo Log文件中,可能会丢失一秒钟的数据。如果你将其设为1(实时写),那么每次提交事务都会直接写入Redo Log文件中,并调用fsync()操作,这样可以保证数据不会丢失,但是性能会受到影响。如果你将其设为2(延迟刷新),那么每次提交事务只会刷新到OS Buffer中,一秒钟后再调用fsync()操作写入Redo Log文件中。

需要注意的是,Redo Log文件是固定大小的,你可以通过配置参数来设置每组文件的大小和数量。比如,可以将每组文件的大小设置为1GB,这样就可以记录4GB的操作。Redo Log文件是循环写入的,写入位置由write pos记录,写入的内容是位于write pos到checkpoint之间的可写区域。checkpoint记录了将要擦除的位置,这个位置也是向后移动的,所以checkpoint到write pos之间的位置是已写区域。

二、Undo Log(回滚日志)

Undo Log是记录逻辑日志的一种机制,它记录的是SQL语句的相反操作。比如,当你执行一条insert语句时,Undo Log就会记录一条相反的delete语句。这个机制的作用是什么呢?其实它有很多用处,比如用来回滚事务、实现MVCC(多版本并发控制)等。

当你执行一条事务操作时,MySQL会在执行之前为其分配一个唯一的事务ID(Transaction ID,简称trx_id)。当你对数据进行修改时,MySQL会把修改操作写入到Undo Log中,并在修改之后将当前事务的trx_id写入到Undo Log中,这样就能保证在回滚数据时只恢复该事务的修改。

Undo Log的实现方式是通过版本链来实现的,每一个版本都有一个trx_id和一个roll_pointer,roll_pointer指向上一个版本。当你执行SELECT语句时,MySQL会生成一个ReadView(读视图),在Read Committed隔离级别下,每次读取都会生成一个读视图,而在Repeatable Read隔离级别下,只会在第一次读取时生成一个读视图。

回滚操作的实现方式也是通过版本链来实现的,MySQL会先找到当前事务对应的版本,然后依次回滚到上一个版本,直到回滚到所有修改操作执行之前的状态。

下面我们来看一下如何使用Undo Log来回滚一个事务:

START TRANSACTION;
-- 修改数据
ROLLBACK;

当你执行ROLLBACK语句时,MySQL会查找当前事务的Undo Log,并把修改操作逆序执行,以恢复数据到修改之前的状态。

三、Bin Log(备份日志)

Bin Log是MySQL自带的备份日志,它记录的是原始的SQL语句,也就是逻辑日志。Bin Log的作用是用来进行数据备份和主从同步。

当你在MySQL中执行一个事务操作时

,MySQL会将该操作记录到Bin Log中,并将Bin Log写入到磁盘中,以保证数据不会丢失。这种方式称为WAL(Write-Ahead Logging),即先写日志,再写磁盘。

在MySQL中,Bin Log有三种日志格式,分别是Statement、Row和Mixed。Statement格式记录的是原始的SQL语句,Row格式记录每行数据的变化,Mixed格式是Statement和Row的混合模式,默认采用Statement模式,但涉及日期、函数等相关操作时会采用Row模式,以减少数据量。

Bin Log的写入方式是追加写入的方式,它不会覆盖原有的日志,所以可以用来恢复到之前某个时刻的数据。为了保证数据的一致性,MySQL也是采用WAL的方式,先写日志,再写磁盘。你可以通过配置参数sync_binlog来指定Bin Log的刷盘规则,0表示延迟写,1表示实时写,N表示提交N个事务后刷盘。

下面我们来看一下Bin Log的使用场景:

  1. 数据备份

你可以通过Bin Log来进行数据备份,具体实现方式是将某个时间点之后的所有操作记录下来,当你需要恢复到该时间点的状态时,只需要执行这些操作的相反操作即可。

-- 开启Bin Log
SET GLOBAL binlog_format = 'ROW';
-- 备份数据
mysqldump --master-data=2 --single-transaction --flush-logs db > db_backup.sql

当你需要恢复数据时,只需要执行以下操作即可:

-- 恢复数据
mysql db < db_backup.sql
  1. 主从同步

你可以通过Bin Log来进行主从同步,具体实现方式是将主库的Bin Log复制到从库中,并在从库上执行相同的操作。这样就可以保证从库的数据与主库的数据一致。

-- 在主库上执行以下操作
-- 开启Bin Log
SET GLOBAL binlog_format = 'ROW';
-- 在从库上创建复制用户
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'%' IDENTIFIED BY 'password';
-- 在从库上执行以下操作
-- 指定主库的地址和Bin Log位置
CHANGE MASTER TO MASTER_HOST='master', MASTER_USER='replication_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=4;
-- 启动复制
START SLAVE;

当你需要停止复制时,只需要执行以下操作即可:

-- 停止复制
STOP SLAVE;

以下是一些示例:

  1. Redo Log

假设有一个表t,包含两个字段id和name,现在需要将id为1的记录的name字段更新为"new_name"。

首先,MySQL将需要修改的页加载到内存中,然后在内存中修改记录,并将新记录写入到Redo Log Buffer中。接着,Redo Log Buffer的内容会定期或者在特定情况下被刷到Redo Log文件中,并最终写入到磁盘中。

这个过程中,如果MySQL发生了崩溃,那么可以通过Redo Log文件来恢复未完成的事务。假设更新id为1的记录的事务未提交,那么MySQL可以通过Redo Log文件将id为1的记录的name字段恢复为原来的值。

  1. Undo Log

假设有一个表t,包含两个字段id和name,现在需要执行如下SQL语句:

BEGIN;
UPDATE t SET name='new_name' WHERE id=1;
SELECT * FROM t WHERE id=1;

首先,MySQL将执行UPDATE语句,并将id为1的记录的name字段更新为"new_name"。接着,MySQL将该操作记录到Undo Log中,并生成一个事务ID。最后,MySQL执行SELECT语句并返回更新后的记录。

如果此时事务被回滚,那么MySQL会通过Undo Log将id为1的记录的name字段恢复为原来的值。

Bin Log

假设有一个表t,包含两个字段id和name,现在需要将id为1的记录的name字段更新为"new_name"。

首先,MySQL将执行UPDATE语句,并将该操作记录到Bin Log中。接着,MySQL将需要修改的页加载到内存中,在内存中修改记录,并将新记录写入到Redo Log Buffer中。接下来的过程与Redo Log相同,最终将Redo Log写入到Bin Log文件中。

如果需要进行数据备份,那么可以将Bin Log文件复制到备份机器中,并按照Bin Log中的操作记录恢复数据。

如果需要进行主从同步,那么可以将主库的Bin Log文件复制到从库中,并在从库中执行相同的操作。这样就可以保证从库的数据与主库的数据一致。

至此,我们已经介绍了MySQL的三大日志系统:Redo Log、Undo Log和Bin Log。了解这些日志系统对于深入理解MySQL非常重要,希望本文能够对你有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开心上班

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值