一文一贯(一文一贯一两)

lxf2023-11-21 00:00:02

这篇文章带给你一些关于mysql的知识,尤其是关于日志的相关问题。Mysql的日志系统是Mysql保证无论何时崩溃都不会丢失数据的关键。下面就一起来看看吧,希望能帮到你。

推荐学习:mysql视频教程

Mysql的日志系统是Mysql保证无论何时崩溃都不会丢失数据的关键。

众所周知,Mysql是一个持久化的数据库,所有的数据都是持久化在硬盘中的,这样才能保证数据不会丢失。

Mysql从以下两个方面保证数据不会丢失。

  • 可以随时恢复到数据状态。

  • 无论事务在提交之前还是之后崩溃,都可以保证数据不会丢失。

    事务期间的崩溃可以恢复到提交事务之前的状态。

    提交事务后崩溃,提交的数据不会丢失。

    MySQL确保以上两点的关键是通过三种日志实现的:undo log、redo log和binlog,下面将一一介绍

    撤消日志回滚日志

    Undo log是Mysql的回滚日志,存储旧版本的数据。

    主函数

    存储旧版本的数据

    Mysql的快照读取是用读取视图和隐藏字段实现的。

    用于在事务执行失败时,回滚到事务开始前的版本。

    撤消日志是什么类型的

    有两种类型的撤消日志。

    对于insert命令,undo log记录新添加记录的主键。回滚时,根据撤消日志中的主键删除相应的记录。

    对于update/delete命令,undo log记录被修改记录的旧数据。

    Mysql中的每一行数据都有两个字段:最近修改的当前数据行的事务id和回滚指针。当数据行被修改时,撤销日志指针将指向旧的数据行,新生成的该行数据的回滚指针将指向撤销日志指针当前指向的旧数据行。

  • 为了避免修改撤销日志指针时的并发问题,Mysql会在修改前给撤销日志指针添加独占锁,以保证撤销日志的正确写入。

  • 撤消日志什么时候会被删除

    Undo log用于确保事务在未提交时可以回滚到事务开始前的状态。事务提交后,撤销日志将失去作用,需要删除。

    撤销日志被Mysql中的purage线程删除。Purage会定期检查undo log中的deleted_bit标志,事务提交后会设置为true,为true时,purage thread会负责删除发现为true的记录。

    重做日志重做日志

    重做日志是Mysql的物理日志,负责记录一个数据页上执行了哪些操作。

    重做日志的角色

  • 负责记录提交的事务对数据的修改。记录的内容可能是对X表的Y页的Z偏移量的更新。

  • 让Mysql提交事务,不需要等待数据持久化到磁盘,只需要将重做日志持久化到磁盘。

    未清除重做日志的数量标识了尚未清理的脏页的数量。

    为什么通过持久化重做日志而不是将数据持久化到磁盘来提交事务?

    将数据持久化到磁盘是一个随机的IO过程,所以Mysql选择缓存数据,等待合适的时机一次性将数据写入磁盘,以减少IO。

    但是数据缓存有丢失在内存中的风险,所以Mysql选择持久化重做日志。

    重做日志按顺序写,持久化效率比随机写高。重做日志记录了数据的变化,所以只要重做日志存在,就能保证Mysql重启后数据的恢复。

    在InnoDB中,重做日志是一种固定大小的循环队列。每次写的时候都会从写pos后面的位置读取,数据持久化的时候检查点会前移。

    这样设计的原因是,重做日志的存在是为了防止Mysql崩溃后缓存的脏页数据丢失。

    当Mysql中的数据持久化到磁盘时,持久化部分的重做日志实际上是没有用的,可以腾出空间给空来记录新的数据。

    撤消日志和重做日志的区别

    撤消日志记录事务执行期间旧数据的状态,而重做日志记录数据更新后的状态。

    重做日志实际上保证了事务的持久性和一致性,而撤销日志保证了事务的原子性。

    Binlog归档日志

    Binlog是Mysql服务器层实现的日志,所有引擎通用。

    函数

    Binlog记录了mysql的原始语句逻辑,而且是以附加编写的形式记录的,所以可以随时用来恢复mysql的数据库数据状态。

    所以binlog是一个归档日志

    同时,binlog也是Mysql实现主从复制的依赖,从库通过复制主库的binlog回放来同步主库的数据状态。

    定义

    先把日志写到磁盘,再把数据写到磁盘。Mysql写操作不是立即写到磁盘,而是先写日志,保证重做日志和binlog都持久化到磁盘,然后后台线程择机持久化数据到硬盘。

    为什么要先将日志写入磁盘

    因为脏页是一个随机读写的过程,持久化到磁盘的速度肯定没有重做日志| binlog快,所以我们选择先修改内存中的数据,以后再选择机会异步持久化到磁盘。

    所以用重做日志| binlog来保证脏页刷入磁盘前数据的持久性,防止掉电重启情况下内存中的数据丢失。

    脏页满了,就需要写到磁盘,然后清除。为什么不彻底消除它们,下次用重做日志恢复呢?

    性能角度来说,如果每次从磁盘读取数据到内存,都需要和重做日志进行比较来更新,效率非常低。

    将MySQL中的脏页写到磁盘,保证了只要数据页在内存中,就一定可以返回最新的数据。

    如果内存中没有数据,从磁盘读取肯定可以得到最新的正确数据,而不用和重做日志对比。

    二进制日志和重做日志的写入过程wal机制的基本保证

    Binlog和重做日志将日志写入分为三个过程:写缓存、写和同步。

    在事务执行期间,Binlog和重做日志将被写入相应的分配的缓存中,以便在提交事务时可以将它们一次性写入磁盘。

    提交事务时,首先将数据写入操作系统的页面缓存。此时,数据还没有真正写入文件,而是一直被操作系统的缓存保存着。如果此时Mysql进程崩溃,这部分写入的数据不会丢失,操作系统的内核线程会负责将这部分缓存中的数据写入磁盘。

  • 但是如果操作系统崩溃,这部分数据就丢失了。

  • 最后,mysql手动调用sync将页面缓存中写入的数据持久化到硬盘上。写入完成后,数据被成功持久化。

    写入和同步mysql的最后一步提供相应的参数来控制写入策略。

    重做日志由innodb_flush_log_at_trx_commit控制。

  • 当它设置为0时,意味着每次提交事务时,只有重做日志保留在重做日志的缓存中。

  • 最大的损失风险

  • 设置为1时,意味着每次提交事务时,重做日志都直接保存在磁盘上。

  • 损失风险极小,但IO占用大。

  • 当它设置为2时,意味着每次提交事务时,只有重做日志被写入页面缓存。

  • IO占据中心,占IO最多的写磁盘的过程就交给操作系统了。

    Binlog由参数sync_binlog控制。

  • 当sync_binlog=0时,表示每次提交事务时,都只是write,而不是fsync。

  • 当sync_binlog=1时,表示每次提交事务时都会执行fsync。

    sync _ binlog = N(N & gt;1),意思是每次提交一个事务,都会被写,但是累积n个事务后才会fsync。

    两阶段日志提交

    什么是两阶段日志提交?

    重做日志提交的过程分为准备和提交两个阶段,binlog日志提交处于这两个阶段的中间。

    提交事务时,重做日志首先提交,然后进入准备状态,只有在binlog提交后,重做日志才能将日志的状态更改为提交。

    为什么我需要两阶段日志提交?

    它与InnoDB引擎的回滚机制有关。如果InnoDB的重做日志提交了事务,则不能回滚。如果binlog在重做日志提交后未能写入,两个副本将会不一致。

    如果此时数据库异常重启,那么就值得思考基于哪一个来恢复数据,所以需要两阶段日志提交。

    假设现在A时刻数据库崩溃,因为binlog还没有写,重做日志还没有提交,所以重启后事务会回滚,两个日志还是统一的状态。

    如果是时间段B,需要判断重做日志的提交标志。如果重做日志中有提交标志,如果没有问题,直接提交。

  • 如果重做日志中没有相应事务的提交标志,将检查Binlog。

  • 如果二进制日志是完整的并且标记有提交标志,则事务将被提交,并且提交标志将被添加到重做日志之后。如果binlog不完整,事务将被回滚。

    可以发现两阶段日志提交中的崩溃是根据binlog判断的,因为主从复制是基于binlog的。

    如果需要检查两个日志的完整性,主库切换到从库将需要很长时间。如果主库基于binlog挂起,只需直接取binlog从从库恢复数据,无需检查重做日志的完整性。

    另外,binlog是Mysql服务器层的通用日志,这也是选择binlog作为基准的原因。

    两阶段日志提交的缺点

  • 磁盘IO次数很高

  • 提交日志时会有对应重做日志和binlog的刷盘操作,IO次数高。

  • 锁竞争激烈。

  • 在提交多个事务时,为了确保日志记录与事务提交顺序一致,将使用锁来确保日志提交的相对顺序。

    但是在大并发的情况下,性能会变差。

    集团提交机制

    集团提交机制的作用

    当存在被回避的事务提交时,多个事务的日志被组合起来写入,从而减少了磁盘IO操作。

    实现集团提交机制

    组提交机制将提交过程分为三个过程,为每个过程维护一个队列,并通过锁保证事务的写入顺序。

  • 分三个阶段锁定可以减少锁定粒度,而不会锁定整个事务提交过程。

  • 当队列为空时,第一个进入队列的事务将成为后续事务的领导者,领导后续事务完成下一阶段的操作。

    阶段1:刷新阶段:多个事务按照条目的顺序将binlog从缓存写入文件(没有磁盘清理)。

    进入刷新阶段的第一个事务将作为领导者领导后续事务。

    leader事务将引导所有事务写一次+fsync重做日志,即把重做日志写到磁盘,完成重做日志的propare阶段。

    如果Mysql在这个阶段崩溃,重启后这组事务将回滚。

    阶段2: sync:对binlog文件进行fsync操作(多个事务的bin log合并在一起刷盘)。

    在刷新阶段将binlog写入binlog文件后,会等待一段时间再进行刷机,以便将更多事务的bin log组合起来一起刷机,减少消耗。

    等待将有时间限制和最大交易限制。如果满足其中一个条件,binlog将立即被清洗。

    sync阶段主要负责binlog的组提交。如果Mysql在当前阶段崩溃,重启后可以通过重做日志的刷记录继续完成事务提交。

  • 因为binlog此时已经完成提交,所以可以根据重做日志继续提交事务。

  • 阶段3:提交:用InnoDB提交每个事务。

    推荐学习:mysql视频教程

    以上是一篇MySQL日志的详细内容。更多详情请关注AdminJS.cn其他相关文章!

    adminjs.cn是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 Adminjs.cn还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 在Adminjs.cn中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!