3. InnoDB日志

3.1 InnoDB架构

分为

  • 内存区域架构

    • buffer pool
    • log buffer
  • 磁盘区域架构
    • redo log
    • undo log

2.1.1 内存区域架构

1)Buffer Pool
  • 定义

    InnoDB对会将磁盘中经常访问的数据所在的页存入Buffer Pool中以加快访问速度,这种操作称为预读,后续对磁盘上某条数据做修改时,也是先读取到buffer pool中,再修改buffer pool中的数据

  • 组成

    由多个Page组成,其中存储了磁盘上的多行数据,方便了大容量的高效读操作,此外,将Page组织成链表结构,便于采用LRU进行内存淘汰

2)Change Buffer
  • 定义

    对于非唯一索引,如果在修改其对应的数据时,行记录不存在于Buffer Pool,那么就将修改操作记录到Change Buffer,等待后面真正读取到该记录到Buffer Pool中时,再将结果进行merge,并修改磁盘中的数据

  • 为何必须非唯一

    对于唯一索引,InnoDB需要对记录的唯一性做校验,也就必须从磁盘中读取到数据,而change buffer的存在意义是尽量避免不必要的随机磁盘io,而对于唯一性校验来说,磁盘io是不可避免的,且由于唯一索引b+树的特点,在是自增的情况下,插入操作是一次顺序io,效率是很高的,也就不必有change buffer

3)自适应哈希索引
  • 定义

    为了让MySQL性能更接近于基于内存的数据库,对于经常访问的数据,会根据数据的特点,以表的某几列建立hash索引,存储结构类似于hashmap,采用拉链法解决hash冲突,使得查询复杂度降低到O(1)

  • 特性

      • 适应等值比较
      • 适应单条数据查询
      • 不适应范围查询
      • 不可用范围或like比较
      • 不适用连表查询
4)Log Buffer

是磁盘上log文件的缓冲区,修改会先记录到此buffer,之后异步的同步到磁盘上的log文件

3.1.2 磁盘区域架构

除了表、索引、表空间之外还有

1)Doublewrite Buffer

buffer pool中对页面的修改信息不会直接同步到对应的表中,而是会以大的连续块的形式调用fsync()写入到双写缓存中,这样在os、存储引擎或其他异常发生时,可以从双写缓存中找到备份

2)redo log
3)undo log

3.2 bin log&redo log&undo log

3.2.1 binlog

1)组成
  • binlog cache

    作为binlog的缓存,会先写入cache中

  • binlog-xxx

    存在于磁盘上的binlog文件,是append only式创建

2)存储内容

可以配置成三种类型

  • statement

    记录为逻辑日志,存储提交的事务的DML语句和事务号

  • row

    记录为物理日志,记录了实际的修改,会使得日志比较大

  • mixed

    前两者的结合

3)作用

多用于主从同步和冷备

4)层级

位于MySQL server层

3.2.2 redo log

1)组成
  • redo log buffer

    作为redo log的缓存,会先写入cache中

  • ib_logfile-xxx

    存在于磁盘上的redo log文件,是循环写入的,对于已经提交的事务,会清空

2)存储内容

是物理日志和逻辑日志的结合,物理体现在记录了具体某一页上发生了修改,逻辑体现在页内的实际修改是以记录DML语句完成的

3)作用

用于宕机恢复,保证一致性

4)层级

位于存储引擎层

3.2.3 undo log

1)组成
  • undo log

    • update log

      对于未提交的事务内发生的update操作,会存储相反的update

    • insert log

      对于未提交的事务内发生的delete操作,会存储对应的insert

    • delete log

      对于未提交的事务内发生的insert操作,会存储对应的delete

上述log会以事务号的顺序编排成一个链表以便于确定要回滚到哪个事务

2)存储内容

是逻辑日志,存储相反的DML语句

3)作用

用于回滚,保证原子性

4)层级

位于存储引擎层

3.3 事务内修改流程

假设事务内存在一条insert语句,那么实际执行流程如下

  • 导入buffer并修改
  • 记录undo log
  • 记录redo log buffer并写盘
  • 2PC提交

详细流程如下

3.3.1 导入buffer并修改

检查buffer pool中是否存在要更新的数据所在的页,如果不存在,需要将页面读入buffer pool,之后修改对应的数据

3.3.2 记录undo log

将delete语句记录到磁盘中的undo log,组织成链表

3.3.3 记录redo log buffer并写盘

将修改记录到buffer,之后根据写盘策略,将buffer中的数据写入到redo log,同步的策略有下面三种,通过设定innodb_flush_log_at_trx_commit完成

  • 0

    每次提交都写入redo log buffer,之后每秒执行fsync()同步到redo log

  • 1

    每次提交都直接写入到redo log中

  • 2

    每次提交写入os cache,之后根据innodb_flush_log_at_timeout配置,决定多久后fsync()

3.3.4 2PC提交

1)流程

由于InnoDB的redo log出现晚于binlog,且两者都用于crash safe,那么就需要保证binlog和redolog中数据的一致性,这里采用类似于分布式事务中的想法,采用两阶段提交的方式来保证一致性,流程如下(此时默认redo log写盘已经执行)

  • 进入Prepare阶段,设置redo log为prepare

  • 写入binlog cache

  • 进入Commit阶段,设置redo log为commit

  • 根据binlog的写盘策略,将binlog cahce写入binlog,策略有下面三种

    • 0

      每次提交写入到os cache

    • 1

      每次提交都直接写入bin log

    • N

      每次都写入os cache,累计N个事务再fsync()

2)异常分析
  • 写redo log宕机

    这时可以根据已经落盘的undo log进行回滚

  • 写binlog cache宕机

    这时一致性未达成,根据undo log做回滚

  • 提交后宕机

    检查redo log中存储的最新事务号是否存在于binlog,如果不存在,将不存在的回滚

3.4 预写日志

预写日志(Write Ahead Log)即在修改磁盘内的数据页中的信息前,将修改信息先写入磁盘中的log文件,如redo log和bin log

这么做有以下优势

  • 顺序io

    由于redo log和binlog落盘时是顺序写入的,而如果直接修改磁盘中数据页中的数据,是随机io,效率非常低

  • 并发量大

    读写者互不阻塞

  • fsync调用次数少

    相较于直接写入磁盘,WAL的fsync调用次数很少,无需每个事务都写盘

3.5 sync、fsync和fdatasync

3.5.0 延迟写

linux中为了减少磁盘io,在写入磁盘时会经历如下步骤

  • 写入os cache
  • 写入output queue
  • 写入磁盘

只有当os cache满时,才会复制到output queue;只有output queue队首的数据会被写入到磁盘

3.5.1 sync

将数据同步到os cache,并不会等待到写入磁盘后返回,这需要update守护进程周期性调用sync将os cache输出到output queue保证写盘成功

3.5.2 fsync

对于某个文件的fd,调用fsync会在写盘成功后返回,写入的数据包括inode中的文件属性以及文件的数据部分

3.5.3 fdatasync

同样对于某个文件的fd,调用fdatasync会在写盘成功后返回,写入的数据只有文件的数据部分,不包括inode

3.6 double write和redo log

3.6.1 为何需要Doublewrite

buffer pool中的数据要写入到磁盘时,是以页为单位,如果写入过程出现宕机,那么就算有redo log也无法恢复,由于redo log每个页内记录的是逻辑日志,而逻辑日志需要保证表中的数据是完备且未改动的,这样where条件才不会失效,因而redo log并不能保证页面级别的crash safe

3.6.2 Doublewrite实现

1)组成

分为两部分

  • 内存中的double write buffer
  • 物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB
2)机制

流程如下

  • 每次脏页会先复制到double write buffer
  • 分两次,每次1MB将页面信息书顺序写入到磁盘上的共享表空间
  • 将buffer中的数据调用fsync离散写入磁盘

这样由于在磁盘的共享表空间中记录了页面的详细修改信息,就可以在同步页面到磁盘上时保证crash safe

# 参考

MySQL :: MySQL 5.7 Reference Manual :: 14.4 InnoDB Architecture

重要,知识点:InnoDB的插入缓冲 (qq.com)

为什么数据不会丢,InnoDB的Double Write,你必须知道 - 掘金 (juejin.cn)

MySQL--buffer pool、redo log、undo log、binlog_黄智霖的博客-CSDN博客

Write-Ahead Logging (sqlite.org)

redo log的被动刷盘机制 - 云+社区 - 腾讯云 (tencent.com)

Linux IO同步函数:sync、fsync、fdatasync | Byte_Liu's Blog (byteliu.com)

MySQL(3)-日志的更多相关文章

  1. MySQL错误日志总结

    MySQL错误日志是记录MySQL 运行过程中较为严重的警告和错误信息,以及MySQL每次启动和关闭的详细信息.错误日志的命名通常为hostname.err.其中,hostname表示服务器主机名. ...

  2. mysql数据库服务日志

    mysql数据库服务日志 ①. 错误日志:error_log ②. 普通日志:general_log ③. 慢查询日志:log-slow-query #有3个参数 分割:.mv .编写定时任务并执行: ...

  3. mysql 二进制日志后缀数字最大为多少

    之前看到mysql二进制日志后面会加一个以数字递增为结尾的后缀,一直在想当尾数到达999999后会发生什么情况,先查了一下官网,对后缀有这样一句介绍:The server creates binary ...

  4. MySQL慢日志监控脚本实例剖析

    公司线上的 MySQL 慢日志,之前一直没有做好监控.趁着上周空闲,我就把监控脚本写了下,今天特地把代码发出来与51博友分享一下. 针对脚本的注解和整体构思,我会放到脚本之后为大家详解. 1 2 3 ...

  5. MySQL二进制日志的备份和恢复

    二进制日志:记录数据库修改的相关操作,作用是即时点回复,主从复制 可以按时间滚动,也可以按大小滚动 server-id:服务器身份标识 一.二进制文件的删除方法,千万不要手动删除 PURGE BINA ...

  6. mysql 的日志文件

    mysql的日志文件 日志文件大致分为  error log, binary log, query log, slow query log, innodb redo log ;如图: 1.error ...

  7. [转载]mysql慢日志文件分析处理

    原文地址:mysql慢日志文件分析处理作者:maxyicha mysql有一个功能就是可以log下来运行的比较慢的sql语句,默认是没有这个log的,为了开启这个功能,要修改my.cnf或者在mysq ...

  8. ELK监控系统nginx / mysql慢日志

    ELK监控系统nginx / mysql慢日志 elasticsearch logstash kibana ELK监控系统nginx日志 1.环境准备 centos6.8_64 mini IP:192 ...

  9. MySQL 错误日志(Error Log)

    同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分.MySQL有几种不同的日志文件.通常包括错误日志文件,二进制日志,通用日志,慢查询日志,等等. 这些日志能够帮助我们定位mysqld ...

  10. Mysql Binlog日志详解

    一.Mysql Binlog格式介绍       Mysql binlog日志有三种格式,分别为Statement,MiXED,以及ROW! 1.Statement:每一条会修改数据的sql都会记录在 ...

随机推荐

  1. HCIA-物理层

    OSI七层模型 应-->表-->会-->传-->网-->数-->物理层 TCP/IP四层模型 两个主导协议 -->工业标准 应-->传-->网-- ...

  2. C++ //继承中的对象模型 //利用开发人员命令提示工具查看对象模型 //父类中所有非静态成员属性都会被 子类继承下去 //父类中私有成员属性 是被编译器给隐藏了 因此是访问不到 但是确实被继承下去了

    1 //继承方式 2 //语法:class 子类 :继承方式 父类 3 //继承方式 三种: 4 //1.公共继承 5 //2.保护继承 6 //3.私有继承 7 8 /* 9 #include &l ...

  3. String.trim的作用

    Java的字符串处理方法trim是如何改变字符串的?下面是一个例子: @Test public void testTrim() { String test = "origin"; ...

  4. 目录已存在导致Jenkins项目构建失败的解决方法

    Jenkins中的项目在下载源代码时,如果Working Directory中存在未加入版本控制的文件或者目录已经存在于SVN库中,会导致更新失败,整个构建终止,解决方法是将SVN的检出策略由&quo ...

  5. MySQL学习06(事务和索引)

    事务 概述 什么是事务 事务就是将一组SQL语句放在同一批次内去执行 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行 MySQL事务处理只支持InnoDB和BDB数据表类型 事务的ACI ...

  6. 在Django中使用Channels功能

    前言:最近后台写游戏更新版本功能,简单就是前端发送更新请求,后端需要对很多台服务器进行更新和各种操作,本来想着实现不难,后来发现因为后端需要执行很长时间,前端返回报错,后端会执行完毕,但是前端先断开了 ...

  7. 内网探测之SPN服务扫描及相关利用

    在写下一个大块之前,补充一些小知识点,也没啥新东西 0x01简介 如果常规扫描服务,结果不理想,非常GG,可以考虑使用SPN进行服务扫描,这是为了借助Kerberos的正常查询行为(向域控发起LDAP ...

  8. SQL 练习19

    统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] SELECT Course.CId,Course.Cname ,t.[0-60],t.[6 ...

  9. 题解 Prime

    传送门 考场上魔改了一下线性筛,觉得要筛到 \(\frac{R}{2}\) 就没让它跑 其实正解就是这样,只不过由于接下来类似埃氏筛的过程只要筛到根号就行了 线性筛有的时候其实并不需要筛到 \(\fr ...

  10. mysql版本:'for the right syntax to use near 'identified by 'password' with grant option'

    查询mysql具体版本 SELECT @@VERSION 问题分析:mysql版本8.0.13,在给新用户授权时,发生了变化: 1064 - You have an error in your SQL ...