MySQL日志解析

日志

undolog
  • undo log(回滚日志 / 逻辑日志?):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC

    【错误或ROLLBACK 语句,会先记录更新前的数据到 undo log(相反的逻辑) 】

    一条记录的每一次更新操作产生的 undo log 格式都有一个 roll_pointer 指针和一个 trx_id 事务id

    • 通过 trx_id 可以知道该记录是被哪个事务修改的;

    • 通过 roll_pointer 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;

undo log 两大作用:
  • 实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。

  • 实现 MVCC(多版本并发控制)关键因素之一。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

undolog刷盘

undo log 和数据页的刷盘策略是一样的,都需要通过 redo log 保证持久化

buffer pool 中有 undo 页,对 undo 页的修改也都会记录到 redo log。redo log 会每秒刷盘,提交事务时也会刷盘,数据页和 undo 页都是靠这个机制保证持久化的。

redolog
  • redo log(重做日志/ 前滚日志 / 物理日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于断电等故障恢复

在内存修改该 Undo 页面后,也需要记录对应的 redo log。】

【redolog文件是循环写的,因为只要刷盘脏页数据到磁盘,对应的redolog信息也没用了可以覆盖】

事务的持久性就依赖于redolog日志】 重做日志缓冲区在logBuffer那里(在内存中)。----> 重做日志文件(在磁盘中),循环写(因为只要刷盘了,脏页就变成干净页,没有存在的意义了),不会永久保存,每隔一段时间清除用过的(因为用在异常时数据恢复,从而保证事务的持久性)。事务提交会把redologBuffer的数据页变更刷新到磁盘的redolog中】

WAL

为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来(比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新),这个时候更新就算完成了

后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术

WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上

重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。 该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。

  • 不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘。

因为当系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后,可以根据 redo log 的内容,将所有数据恢复到最新的状态。

崩溃恢复

【undolog可以保证事务回滚,当事务commit崩溃,需要依靠redolog恢复事务】

有了 redo log,再通过 WAL 技术,InnoDB 就可以保证即使数据库发生异常重启,之前已提交的记录都不会丢失,这个能力称为 crash-safe(崩溃恢复)。可以看出来, redo log 保证了事务四大特性中的持久性


redolog必要性

为什么需要 redo log 这个问题我们有两个答案:

  • 实现事务的持久性,让 MySQL 有 crash-safe 的能力,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;

  • 将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能。

刷盘
  • 写入 redo log 的方式使用了追加操作, 所以磁盘操作是顺序写

  • 而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写

事务提交会把redologBuffer的数据页变更刷新到磁盘的redolog中】

个人理解: 事物每次提交的时候都会刷到磁盘redo log中,而不是直接将buffer pool中的数据直接刷到磁盘中(ibd文件中),是因为redo log 是顺序写,性能处理的够快,直接刷到ibd中,是随机写(随机IO性能低),性能慢。所以脏页是在下一次读的时候,或者后台线程采用一定的机制进行刷盘到ibd中。【WAL先写日志机制】 比如update的id跨度大,索引存储,所以随机写(很多数据,数据在磁盘中分散)很慢,要搞个顺序写(在磁盘一直往后写),写内存最快

注意:【redolog文件是循环写的,因为只要刷盘脏页数据到磁盘,对应的redolog信息也没用了可以覆盖】

  • redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞因此所以针对并发量大的系统,适当设置 redo log 的文件大小非常重要),此时会停下来将 Buffer Pool 中的脏页刷新到磁盘中,然后标记 redo log 哪些记录可以被擦除,接着对旧的 redo log 记录进行擦除,等擦除完旧记录腾出了空间

    【所以整个数据库删除不能用她来恢复,因为会缺少数据,只能用binlog】

缓存在 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 参数控制【内存结构的LogBuffer的参数】

  • 当设置该参数为 0 时,表示每次事务提交时 ,还是将 redo log 留在 redo log buffer 中 ,该模式下在事务提交时不会主动触发写入磁盘的操作。

  • 当设置该参数为 1 时,表示每次事务提交时,都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘,这样可以保证 MySQL 异常重启之后数据不会丢失。

  • 当设置该参数为 2 时,表示每次事务提交时,都只是缓存在 redo log buffer 里的 redo log 写到 redo log 文件,注意写入到「 redo log 文件」并不意味着写入到了磁盘,因为操作系统的文件系统中有个 Page Cache(如果你想了解 Page Cache,可以看这篇 (opens new window)),Page Cache 是专门用来缓存文件数据的,所以写入「 redo log文件」意味着写入到了操作系统的文件缓存。

具体:MySQL 日志:undo log、redo log、binlog 有什么用? | 小林coding

这三个参数的数据安全性和写入性能的比较如下:

  • 数据安全性:参数 1 > 参数 2 > 参数 0

  • 写入性能:参数 0 > 参数 2> 参数 1

binlog
  • binlog (归档日志):是 Server 层生成的日志,主要用于数据备份和主从复制;【保存的是全量的日志,可以用来恢复全部数据】

【undo log 和 redo log 这两个日志都是 Innodb 存储引擎生成的。 binlog 是 MySQL 的 Server 层实现的日志,所有存储引擎都可以使用;】

  • binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作

  • 背景:

    一开始没有InnoDB,只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB(一开始以插件形式) 使用 redo log 来实现 crash-safe 能力

binlog与redolog区别:

四个区别。

1、适用对象不同

  • binlog 是 MySQL 的 Server 层实现的日志,所有存储引擎都可以使用;

  • redo log 是 Innodb 存储引擎实现的日志;

2、文件格式不同

  • binlog 有 3 种格式类型,分别是 STATEMENT(默认格式)、ROW、 MIXED,区别如下:

    • STATEMENT:每一条修改数据的 SQL 都会被记录到 binlog 中(相当于记录了逻辑操作,所以针对这种格式, binlog 可以称为逻辑日志),主从复制中 slave 端再根据 SQL 语句重现。但 STATEMENT 有动态函数的问题,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致;

    • ROW:记录行数据最终被修改成什么样了(这种格式的日志,就不能称为逻辑日志了),不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已;

    • MIXED:包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式;

  • redo log 是物理日志,记录的是在某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新;

3、写入方式不同

  • binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志

  • redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。

4、用途不同

  • binlog 用于备份恢复、主从复制;

  • redo log 用于掉电等故障恢复。

主从复制
  • 依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上。【异步执行】

MySQL 集群的主从复制过程梳理成 3 个阶段:

  • 写入 Binlog:主库写 binlog 日志,提交事务,并更新本地存储数据。[Master 主库在事务提交时,会把数据变更记录在二进制文件Binlog中。]

  • 同步 Binlog:把 binlog 复制到所有从库上,每个从库把 binlog 写到暂存日志中。[从库(IOThread)读取数据库的二进制日志文件Binlog,写入到从库的中继日志Relay log。]

  • 回放 Binlog:回放 binlog,并更新存储引擎中的数据。[slave(SQLThread)重做中继日志中的事件,将改变反映它自己的数据。]

注意:

  • 从库数量增加,从库连接上来的 I/O 线程也比较多,主库也要创建同样多的 log dump 线程来处理复制的请求,对主库资源消耗比较高,同时还受限于主库的网络带宽

    所以在实际使用中,一个主库一般跟 2~3 个从库(1 套数据库,1 主 2 从 1 备主)

主从复制模型:

  • 同步复制:性能、可用性差

  • 异步复制:一旦主库宕机,数据就会发生丢失。

  • 半同步复制:兼顾了异步复制和同步复制的优点,即使出现主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险

刷盘
  • 事务执行过程中,先把日志写到 binlog cache(Server 层的 cache),事务提交的时候,再把 binlog cache 写到 binlog 文件中。

    【如果超过了这个参数规定的大小,就要暂存到磁盘。】

    【一个事务的 binlog 是不能被拆开的】

  • 在事务提交的时候,执行器把 binlog cache 里的完整事务写入到 binlog 文件中,并清空 binlog cache

BufferPool

【提高数据库的读写性能】

InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool 同样需要按「页」来划分。

  • 修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。

Buffer Pool 中的页就叫做缓存页。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。

MySQL 刚启动的时候,你会观察到使用的虚拟内存空间???很大,而使用到的物理内存空间却很小,这是因为只有这些虚拟内存被访问后,操作系统才会触发缺页中断,申请物理内存,接着将虚拟地址和物理地址建立映射关系。

  • Undo页:开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。

  • 查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,将页加载到 Buffer Pool 后,再通过页里的「页目录」去定位到某条具体的记录。

    【不只是缓存一条记录】

注:感谢小林coding开源文档和黑马免费教程!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值