做目录网站注意事项,有自己域名的个人网站,wordpress网站乱码,深圳官方网站新闻前言
2023 年某一天周末#xff0c;新手程序员小明因为领导安排的一个活来到公司加班#xff0c;小明三下五除二#xff0c;按照领导要求写了一个跑批的数据落库任务在测试环境执行 #xff0c;突然间公司停电了#xff0c;小明大惊#xff0c;“糟了#xff0c;MySQL …前言
2023 年某一天周末新手程序员小明因为领导安排的一个活来到公司加班小明三下五除二按照领导要求写了一个跑批的数据落库任务在测试环境执行 突然间公司停电了小明大惊“糟了MySQL 还在跑任务会不会因为突然断电导致数据库崩了”。
这时候傍边的同事云淡风清的说了一句“没事小明MySQL 有一套预写日志机制就是应对这种情况的。你的落库任务启用了事务没启用了的话就等来电重新跑一下任务就行了。”
听了同事的话小明悬着的心放了下来。 “哦哦我启用了事务那我还是等周一来重新跑一遍”。
回家的公交车上小明默默的打开百度搜索 MySQL 预写日志 写下了这篇文章 。 本文思维导图
什么是预写日志机制
一般情况下大部分数据库都是将表和索引存储在磁盘文件中。当新增数据时数据库系统会先写入内存然后将其写入磁盘上的数据文件。 那为什么不直接写入磁盘嘞主要是每次新增都直接写入磁盘性能很低放在内存中可以批量写入磁盘以提升性能。 但有一个问题如果数据在写入磁盘文件中途断电怎么办当来电恢复后我们重启数据库发现数据不一致又该如何处理。
所以我们需要一些其他机制来避免断电引发的数据不一致其实 MySQL 已经考虑到了这一点内部已经实现一套 WAL预写日志机制来避免这一点。
MySQL 设计有健壮的恢复机制特别是使用 InnoDB 存储引擎的情况下它能够在断电后重启而不会崩溃。InnoDB 存储引擎使用预写日志WAL机制来确保数据的一致性和原子性。
预写日志机制是一种数据库事务日志技术它要求在任何数据库修改被写入到永久存储也就是磁盘之前先将这些修改记录到日志中。
这样当 MySQL 遇到意外的断电情况时它会在重启后利用 Redo log 来恢复已提交但未写入数据文件的事务继续写入数据文件从而保证一致性再利用 undo log 来撤销未提交事务的需改从而保证原子性。
MySQL 中的预写日志机制 在 MySQL 中InnoDB 存储引擎实现了 WAL 机制。包含 Redo log buffer、Redo log、Undo Log 等来记录事务已提交但未写入数据文件的数据变更以及事务回滚后的数据还原。
为了给大家讲清楚 MySQL 的预写日志机制会涉及到 MySQL 架构中的以下内容
Buffer Pool缓冲池
Buffer Pool 缓冲池是 InnoDB 存储引擎中非常重要的内存结构顾名思义缓冲池就是起到一个缓存的作用因为我们都知道 MySQL 的数据最终是存储在磁盘中的如果没有这个 Buffer Pool 那么我们每次的数据库请求都会磁盘中查找这样必然会存在 IO 操作这肯定是无法接受的。
但是有了 Buffer Pool 就是我们第一次在查询的时候会将查询的结果存到 Buffer Pool 中这样后面再有请求的时候就会先从缓冲池中去查询如果没有再去磁盘中查找然后在放到 Buffer Pool 中。
Redo log buffer日志缓冲区
Redo log buffer 是用作数据变更记录写入 Redo log 文件前的一块内存区域。日志缓冲区大小由 innodb_log_buffer_size 变量定义默认大小为 16MB。
日志缓冲区的内容会定期刷新到 Redo log 文件中大型日志缓冲区允许大型事务运行而无需在事务提交之前将 Redo log 数据写入磁盘。因此如果事务涉及的更新、插入或删除操作数据量较大时可以增加日志缓冲区的大小可以节省磁盘 I/O。
MySQL 提交事务的时候会将 Redo log buffer 中的数据写入到 Redo log 文件中刷磁盘可以通过 innodb_flush_log_at_trx_commit 参数来设置 值为 0 表示不刷入磁盘 值为 1 表示立即刷入磁盘 值为 2 表示先刷到 os cache
为了提高性能MySQL 首先将修改操作写入到日志缓冲区之后以 innodb_flush_log_at_trx_commit 参数设置落盘时机将日志缓冲区刷入到磁盘的 Redo log 文件中去。
Redo Log
MySQL Redo Log 是 InnoDB 存储引擎中的一个重要组件它是一种磁盘基础的数据结构用于在崩溃重启期间修复由已提交事务但未写入数据文件的数据。
在正常操作中Redo log 记录了由 SQL 语句执行导致的表数据变更记录。将 Redo log buffer 中的数据持久化到磁盘中就是将 Redo log buffer 中的数据写入到 Redo log 磁盘文件中。
数据在由 Redo log buffer 写入 Redo log 时的触发时机如下 MySQL 正常关闭时触发 当 Redo log buffer 中记录的写入量大于 Redo log buffer 内存空间的一半时会触发落盘 InnoDB 的后台线程每隔 1 秒将 Redo log buffer 持久化到磁盘 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘这个策略就是由上文提高 innodb_flush_log_at_trx_commit 参数控制
Redo log 是 WAL 机制的核心它记录了事务所做的所有修改。如果数据库发生故障可以使用 Redo 日志来重做事务从而确保数据的一致性。
Undo Log
Undo Log 记录了如何撤销一个事务的修改。如果需要回滚事务或在执行事务时还未提交数据库就发生了崩溃这时我们就需要将未提交事务前的数据回滚回去难道这个操作有我们自己来做吗显然 MySQL 也考虑到了这一点。
MySQL 会使用 Undo log 来撤销未提交的修改。在操作数据前MySQL 首先将数据备份到 Undo log然后进行数据修改。
如果出现错误或者用户执行了 Rollback 语句系统可以利用 Undo log 中的备份将数据恢复到事务操作前的状态。
通过 Undo log 撤销修改从而确保数据的原子性。 结合 Buffer Pool、Redo log buffer、Redo log、Undo log 后我们在MySQL 中更新一条数据的流程如下 图片来源https://pdai.tech/md/db/sql-mysql/sql-mysql-execute.html 准备更新一条 SQL 语句 MySQLinnodb会先去缓冲池Buffer Pool中去查找这条数据没找到就会去磁盘中查找如果查找到就会将这条数据加载到缓冲池Buffer Pool中 在加载到 Buffer Pool 的同时会将这条数据的原始记录保存到 undo 日志文件中 innodb 会在 Buffer Pool 中执行更新操作 更新后的数据会记录在 Redo log buffer 中 MySQL 提交事务的时候会将 Redo log buffer 中的数据写入到 Redo log 文件中刷磁盘可以通过 innodb_flush_log_at_trx_commit 参数来设置 MySQL 重启的时候会将 Redo log 恢复到缓冲池中
额外知识检查点Checkpoint 检查点是什么为什么有了 Redo log、Undo log 还要引入检查点。 明明借助 Redo log、Undo log 我们就可以实现 MySQL 的故障恢复了。 虽然数据在写入 Redo log 文件后就代表数据变更已经生效了但是还未写入到数据文件也就是还没有完成事务的持久性。
那么检查点就是帮助 MySQL 实现事务的持久性。
如果说 Redo log 可以无限地增大能够保存所有数据库变更的数据那么在发生宕机时完全可以通过 Redo log 来恢复数据库系统的数据到宕机发生前的情况。
然而现实是我们的物理磁盘文件大小是有效的。即使达成无限了如果数据库运行了很久后发生宕机那么使用 Redo log 进行恢复的时间也会非常的久。
所以在 Redo log 文件容量是有限的情况下还需要定期将 Redo log 写入数据文件完成数据的持久化在这样的情况下就引入了 Checkpoint检查点技术。 Checkpoint检查点技术不仅仅是会同步 Redo log 写入数据文件也会同步脏页数据写入数据文件。 检查点的触发时机有两种如下
Sharp Checkpoint(完全检查点)
将内存中所有脏页全部写到磁盘就是完全检查点比如数据库实例关闭时。
Fuzzy Checkpoint(模糊检查点)
将部分脏页刷新到磁盘就是模糊检查点一般就是脏页达到一定数量时触发。数据库实例运行过程产生的检查基本上就是这种类型的检查点。
因此其实 Checkpoint 就是指一个触发点时间点当发生 Checkpoint 时会将脏页写回磁盘以确保数据的持久性和一致性。并且 Redo log、Undo log 文件也可以重新覆写这样可以保证重启时不会因为 Redo log、Undo log 文件太大而导致重启时间过长。
断电故障恢复案例 图片来源https://www.pcworld.com/article/419101/what-to-do-when-a-power-disaster-bricks-your-pc.html
OK假如我们正在使用 MySQL 添加数据。在提交事务的过程中突然发生了断电那么这个数据会丢吗
我们结合上文MySQL 中更新一条数据的流程来给大家分析下具体场景
数据在写入 Buffer Pool、Redo log buffer 中时发生断电
先说结论会丢。因为数据没有写入 Redo log 前MySQL 是没办法保证数据一致性的。但是这没关系的因为 MySQL 会认为本次事务是失败的在重启后可以根据 Undo log 文件将数据恢复到更新前的样子并不会有任何的影响。
数据在写入 Redo log 文件后发生断电
先说结论不会丢。因为 Redo log buffer 中的数据已经被写入到 Redo log 了就算数据库宕机了在下次重启的时候 MySQL 也会将 Redo log 文件内容恢复到 Buffer Pool 中进行重放。
参考资料 https://xiaolincoding.com/mysql/log/how_update.html#redo-log-%E6%96%87%E4%BB%B6%E5%86%99%E6%BB%A1%E4%BA%86%E6%80%8E%E4%B9%88%E5%8A%9E https://pdai.tech/md/db/sql-mysql/sql-mysql-execute.html https://zhuanlan.zhihu.com/p/552706911?utm_mediumreferral
最后说两句
预写日志机制是数据库管理系统中保证数据安全性的关键技术。在 MySQL 中通过 InnoDB 存储引擎实现的 WAL 机制即使在发生断电等意外情况下也能够有效地保护数据不受损坏。这使得 MySQL 成为了一个可靠和健壮的数据库解决方案适用于各种需要高数据一致性和可靠性的应用场景。 关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、国外优质文章翻译等您的关注将是我的更新动力