关于mysql:MySQL事务机制是如何实现的

52次阅读

共计 4866 个字符,预计需要花费 13 分钟才能阅读完成。

写在后面

周末,我与阿里 P9 资深技术专家(这里就不说名字了),聊起了 MySQL 这个话题,为啥会聊这个呢?因为他看到我出版了一部《MySQL 技术大全:开发、优化与运维实战》,对书籍的评估也是不错的。随后,咱们聊了对于 MySQL 的几个话题,其中一个就是 MySQL 的日志机制。明天,我就把大略聊的一些内容以书面文章的模式分享给大家。心愿可能为小伙伴们带来实质性的帮忙!

文章已收录到:

https://github.com/sunshinelyz/technology-binghe

https://gitee.com/binghe001/technology-binghe

MySQL 日志

说起 MySQL 的日志,有三种类型的日志对于 MySQL 来说是至关重要的,这三种日志别离为:Binlog、Undo Log 和 Redo Log。

因为 Binlog 和 UndoLog 有相似的中央,所以,咱们依照如下程序顺次介绍 MySQL 中的三大日志原理:Undo Log——> Redo Log ——> Binlog。

Undo Log 日志

什么是 Undo Log

顾名思义,Undo Log 的字面意思就是撤销操作的日志,指的是使 MySQL 中的数据回到某个状态。

在 MySQL 数据库中,事务开始之前,MySQL 会将待批改的记录保留到 Undo Log 中,如果数据库解体或者事务须要回滚时,MySQL 能够通过利用 Undo Log 日志,将数据库中的数据回滚到之前的状态。

MySQL 新增、批改和删除数据时,在事务开始前,就会将信息写入 Undo Log 中。事务提交时,并不会立即删除 Undo Log,InnoDB 存储引擎会将事务对应的 Undo Log 放入待删除列表中,之后会通过后盾的 purge thread 看待删除的列表进行删除解决。这里,值得注意的是:Undo Log 是一种 逻辑日志,记录的是一个变动过程。比方,MySQL 执行一个 delete 操作,Undo Log 就会记录一个 insert 操作;MySQL 执行一个 insert 操作,Undo Log 就会记录一个 delete 操作;MySQL 执行一个 update 操作,Undo Log 就会记录一个相同的 update 操作。

Undo Log 以段的形式来治理和记录日志信息,在 InnoDB 存储引擎的数据文件中,蕴含了一种叫做 rollback segment 的回滚段,其外部蕴含了 1024 个 undo log senment。

Undo Log 作用

Undo Log 对于 MySQL 实现事务来说,起着至关重要的作用,它实现了事务的原子性和多版本并发管制,也就是咱们常常说的 MVCC。

  • 实现事务的原子性

Undo Log 可能实现 MySQL 事务的原子性,在事务的处理过程中,如果 MySQL 呈现了谬误或者用户手动执行了事务的回滚操作(执行了 rollback 操作),MySQL 能够利用 Undo Log 日志将数据库中的数据恢复到之前的状态。

  • 实现 MVCC 机制

Undo Log 在 MySQL 的 InnoDB 存储引擎中实现了多版本并发管制(MVCC)机制。事务未提交前,Undo Log 保留了未提交之前的版本数据,Undo Log 中的数据能够作为旧版本数据的正本或者快照以便其余并发事务进行读取操作。

事务 A 手动开启事务后,对 goods 数据表中 id 为 1 的数据进行更新操作,首先会把更新命中的数据写入到 Undo Buffer 中。在事务 A 未提交之前,此时,事务 B 手动开启事务,对 goods 数据表中的 id 为 1 的数据进行查问操作,此时的事务 B 会读取 Undo Log 中的数据并返回给客户端,这就是 MySQL 中的 MVCC 机制。

能够在 MySQL 中通过上面的命令来查看管制 Undo Log 日志的参数。

show variables like '%innodb_undo%';

Redo Log 日志

说了 MySQL 中的 Undo Log,咱们再来看看 MySQL 中的 Redo Log 日志。

什么是 Redo Log

顾名思义 Redo Log 的字面意思就是重做日志,指的是在数据库出现意外状况时可能对从新执行某种操作。在 MySQL 中,事务中批改的任何数据,都会将最新的数据写入 Redo Log 中进行备份。

在 MySQL 中,随着事务操作的执行,就会产生 Redo Log 日志,在事务提交时会产生 Redo Log 并将其写入 Redo Buffer,Redo Buffer 也并不是随着事务的提交就会被立即写入到磁盘中,而是等事务操作的脏页写入到磁盘之后,Redo Log 的使命也就实现了,此时,Redo Log 日志占用的空间能够从新利用,会被后续产生的 Redo Log 日志笼罩。

Redo Log 的原理

Redo Log 可能实现事务的持久性,避免在产生故障的工夫点,有脏页未写入表的 ibd 文件中,在重启 MySQL 服务的时候,依据 Redo Log 进行重做,从而将未提交的事务进行长久化。这个过程能够简化为下图所示。

Redo Log 的写机制

Redo Log 文件的内容是以程序循环的形式写入文件的,写满时就会回到第一个文件,进行笼罩写。

  • Write Pos 是以后记录的地位,一边写一边后移,写到最初一个文件开端后就回到 0 号文件结尾;
  • CheckPoint 是以后要擦除的地位,也是往后推移并且循环的,擦除记录前要把记录更新到数
    据文件;

Write Pos 和 CheckPoint 之间还空着的局部,能够用来记录新的操作。如果 Write Pos 追上 CheckPoint,示意曾经写满,此时就须要向后挪动 CheckPoint 来擦除数据。

每个 InnoDB 存储引擎至多有 1 个重做日志文件组(group),每个文件组至多有 2 个重做日志文件,默认为 ib_logfile0 和 ib_logfile1。

能够在 MySQL 中通过如下命令来查看管制 Redo Log 的参数。

show variables like '%innodb_log%';

Redo Log 写入机制

在 Redo Log 日志信息从 Redo Buffer 长久化到 Redo Log 时,具体的长久化策略能够通过 innodb_flush_log_at_trx_commit 参数进行设置,具体策略如下所示。

  • 0:每秒提交 Redo buffer ->OS cache -> flush cache to disk,可能失落一秒内的事务数据。由后盾 Master 线程每隔 1 秒执行一次操作。
  • 1(默认值):每次事务提交执行 Redo Buffer -> OS cache -> flush cache to disk,这种形式最平安,性能最差。
  • 2:每次事务提交执行 Redo Buffer -> OS cache,而后由后盾 Master 线程再每隔 1 秒执行 OS cache -> flush cache to disk 的操作。

个别倡议抉择取值 2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失 1 秒的事务提交数据。

Binlog 日志

什么是 Binlog

Binlog 记录所有 MySQL 数据库表构造变更以及表数据批改的二进制日志,不会记录 select 和 show 这类查问操作的日志。Binlog 日志是以事件模式记录,还蕴含语句所执行的耗费工夫。开启 Binlog 日志有以下两个最重要的应用场景。

  • 主从复制:在主库中开启 Binlog 性能,这样主库就能够把 Binlog 传递给从库,从库拿到 Binlog 后实现数据恢复达到主从数据一致性。
  • 数据恢复:通过 mysqlbinlog 等工具来复原数据

对于 Binlog 的应用场景能够参见我出版的图书《MySQL 技术大全:开发、优化和运维实战》一书。

Binlog 文件记录模式

Binlog 文件记录模式有 STATEMENT、ROW 和 MIXED 三种,具体含意如下。

ROW 模式

ROW(row-based replication, RBR):日志中会记录每一行数据被批改的状况,而后在 slave 端对雷同的数据进行批改。

长处:能分明记录每一个行数据的批改细节,能齐全实现主从数据同步和数据的复原。

毛病:批量操作,会产生大量的日志,尤其是 alter table 会让日志暴涨。

STATMENT 模式

STATMENT(statement-based replication, SBR):每一条被批改数据的 SQL 都会记录到 master 的 Binlog 中,slave 在复制的时候 SQL 过程会解析成和原来 master 端执行过的雷同的 SQL 再次执行。简称 SQL 语句复制。

长处:日志量小,缩小磁盘 IO,晋升存储和复原速度

毛病:在某些状况下会导致主从数据不统一,比方 last_insert_id()、now()等函数。

MIXED 模式

MIXED(mixed-based replication, MBR):以上两种模式的混合应用,个别会应用 STATEMENT 模式保留 binlog,对于 STATEMENT 模式无奈复制的操作应用 ROW 模式保留 binlog,MySQL 会依据执行的 SQL 语句抉择写入模式。

Binlog 文件构造

对于 MySQL 的 Binlog 文件构造有三种版本,见下图。

对于 Binlog 文件构造的具体信息,小伙伴们能够参考 MySQL 的官网文档,具体链接为:https://dev.mysql.com/doc/internals/en/event-header-fields.html

Binlog 写机制

依据记录模式和操作触发 event 事件生成 log event(事件触发执行机制)。

将事务执行过程中产生的日志工夫(log event)写入缓冲区,每个事务线程都有一个缓冲区。Log Event 保留在一个 binlog_cache_mngr 数据结构中,在该构造中有两个缓冲区,一个是 stmt_cache,用于寄存不反对事务的信息;另一个是 trx_cache,用于寄存反对事务的信息。

事务在提交阶段会将产生的 log event 写入到内部 binlog 文件中。不同事务以串行形式将 log event 写入 Binlog 文件中,所以一个事务蕴含的 log event 信息在 binlog 文件中是间断的,两头不会插入其余事务的 log event。

Binlog 文件操作

Binlog 状态查看

show variables like 'log_bin';

开启 Binlog 性能,须要批改 my.cnf 或 my.ini 配置文件,在 [mysqld] 上面减少 log_bin=mysql_bin_log,重启
MySQL 服务。

binlog-format=ROW
log-bin=mysqlbinlog

应用 show binlog events 命令

show binary logs; // 等价于 show master logs;
show master status;
show binlog events;
show binlog events in 'mysqlbinlog.000001';

应用 mysqlbinlog 命令

mysqlbinlog "文件名"
mysqlbinlog "文件名" > "test.sql"

应用 binlog 复原数据

// 按指定工夫复原
mysqlbinlog --start-datetime="2021-02-28 18:00:00" --stopdatetime="2021-03-01 00:00:00" mysqlbinlog.000001 | mysql -uroot -p123456
// 按事件地位号复原
mysqlbinlog --start-position=1789 --stop-position=2674 mysqlbinlog.000001
| mysql -uroot -p123456

删除 Binlog 文件

purge binary logs to 'mysqlbinlog.000001'; // 删除指定文件
purge binary logs before '2021-03-01 00:00:00'; // 删除指定工夫之前的文件
reset master; // 革除所有文件

能够通过设置 expire_logs_days 参数来启动主动清理性能。默认值为 0 示意没启用。设置为大于 0 的整数示意超出多少天 binlog 文件会主动革除。

好了,明天就到这儿吧,我是冰河,大家有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,我拉你进群,一起交换技术,一起进阶,一起进大厂~~

正文完
 0