概述

Mysql的日志系统是Mysql确保不管何时溃散数据都不会丢掉的要害

众所周知Mysql是耐久化的数据库, 一切的数据都是耐久化到硬盘中的, 确保数据不会丢掉

Mysql确保数据不会丢掉是从以下两个方面来表现的

  1. 能够康复到恣意时刻的数据状况
  2. 不管在业务提交前还是提交后溃散都能确保数据不丢掉
    • 业务进程中溃散能够康复到业务提交前的状况
    • 业务提交后溃散已提交的数据不会丢掉

MySQL确保以上两个点的要害便是经过 undo log, redo log 和 binlog 这三个日志来完结的, 接下来将逐一介绍

undo log 回滚日志

undo log是Mysql的回滚日志, 存储的是老版别的数据

首要效果

  1. 存储老版别的数据

    • 配合Read View和隐藏字段完结了Mysql的快照读
  2. 用于在业务履行失利的时分回滚到业务开始前的版别

undo log 有什么类型

undo log 有两种类型

关于 insert 指令, undo log 记载的是新增的记载的主键, 在回滚的时分依据 undo log 中的主键去删去对应的记载即可

关于 update / delete 指令, undo log 记载的是被修正的记载的旧数据

Mysql中的每一行数据都有一个最新修正当时数据行的业务id回滚指针这两个字段, 当对数据行进行修正之后, undo log指针就会指向旧的这一行数据, 而新生成的这一行数据的回滚指针就会指向undo log指针当时指向的旧数据行

  • Mysql为了避免undo log指针修正指向的时分出现并发问题, 在修正之前会对undo log指针添加排他锁以确保undo log的正确写入

MySQL日志系统 - 一文贯通MySQL日志

undo log 什么时分删去

undo log是用于确保业务在未提交的时分能够顺畅回滚到业务开始前的状况, 当业务提交之后undo log就失去效果了, 就需要被删去

undo log是交由Mysql中的 Purage 线程来担任删去的, purage会定期查看undo log中的deleted_bit 标志, 这个标志会在业务提交后被设置为true, purage 线程发现为true的记载就会担任将其删去

redo log 重做日志

redo log是Mysql的物理日志, 担任记载某个数据页履行了什么样的操作

redo log 的效果

  1. 担任记载提交的业务对数据的修正, 记载的内容大约便是对x表的y页z偏移做了a更新
  2. 让Mysql在提交业务的时分无需等候数据耐久化磁盘, 只需要将redo log耐久化到磁盘就能够了
  3. 未清除的redo log的数量标识了未刷盘的脏页数量

为什么提交业务是选择耐久化redo log, 而不是耐久化数据到磁盘

耐久化数据到磁盘是随机IO进程, 所以Mysql选择将数据缓存起来, 等候一个适宜的机遇将数据一次性写入磁盘, 削减IO

可是数据缓存在内存中有丢掉的危险, 所以Mysql选择将redo log耐久化

redo log是次序写, 耐久化的功率比随机写的功率要高, 而且redo log记载了数据的变化情况, 只需redo log在就能够确保在Mysql重启后康复数据

在InnoDB中, redo log是一个固定大小的相似循环行列的存在, 每次写入都从后边write pos的方位, 在耐久化数据的时分就移动check point往前读取

MySQL日志系统 - 一文贯通MySQL日志

  • 这样规划的原因是由于redo log是避免Mysql溃散后缓存的脏页数据丢掉而存在的
  • 当Mysql中的数据被耐久化到磁盘中后, 被耐久化部分的redo log其实就没有用了, 就能够腾出空间来记载新的数据

undo log 和 redo log 的差异

undo log记载的是业务履行进程中旧数据的状况, redo log记载的是数据更新之后的状况

redo log其实保障的是业务的耐久性和共同性,而undo log则保障了业务的原子性

binlog 归档日志

binlog是Mysql server层完结的日志, 是一切引擎通用的

效果

binlog记载的是mysql原始的语句逻辑, 而且是选用追加写入的方式记载的, 所以能够用于康复mysql在恣意时刻的数据库数据状况

  • 所以叫binlog是归档日志 一同binlog也是Mysql完结主从复制的依靠, 从库经过从主库中复制binlog回放来同步主库的数据状况

Mysql的WAL(Write Ahead Loggin)机制

界说

先写日志到磁盘中, 再写数据到磁盘中 Mysql的写操作不是立刻写入到磁盘中的, 而是先写日志, 确保redo log和binlog都耐久化到磁盘中再由后台线程选择机遇将数据耐久化到硬盘的

为什么要先写日志到磁盘中

由于刷脏页是一个随机读写的进程, 耐久化到磁盘中的速度肯定没有redo log | binlog这些次序写的速度快, 所以选择先在内存中对数据进行修正, 再后期选择机遇异步耐久化到磁盘中

所以在脏页还未刷入磁盘中的这段时刻就由redo log | binlog来确保数据的耐久化, 避免断电重启等情况内存中的数据丢掉

当脏页满的时分需要将脏页写入到磁盘再筛选, 为何不悉数筛选掉下次运用的时分再经过redo log来康复呢

从功能方面考虑的, 假如每次从磁盘中读取数据到内存都需要和redo log比对更新, 功率很低

MySQL刷脏页写入到磁盘确保了数据页只需在内存中, 就肯定是当时最新的数据能够返回

假如内存中没有数据只需从磁盘中读取肯定能得到最新的正确数据, 而不用再去同redo log进行比对

binlog和redo log的写入进程 – WAL机制的基本确保

binlog和redo log都是将日志写入划分为三个进程 写入cache, write和sync

在业务履行进程中会将binlog和redo log写入到对应分配的缓存中, 以便在业务提交的时分一次性写入到磁盘中

在业务提交的时分会先进行write将数据写入到操作系统的页缓存中, 此刻数据还未真实写入文件, 可是已经是交由操作系统的缓存来保管了, 假如此刻Mysql进程溃散这部分写入的数据也不会丢掉, 操作系统的内核线程会担任将这部分缓存中的数据写入磁盘

  • 可是假如操作系统溃散了这部分数据就丢掉了

最终便是mysql手动调用sync将写入在页缓存中的数据耐久化到硬盘, 写入完结后数据便是耐久化成功了

最终的write和sync进程mysql供给了对应的参数来操控写入策略

redo log是经过innodb_flush_log_at_trx_commit来操控的

  • 设置为 0 的时分,表明每次业务提交时都只是把redo log留在redo log的缓存中
    • 丢掉危险最大
  • 设置为 1 的时分,表明每次业务提交时都将redo log直接耐久化到磁盘
    • 丢掉危险最小, 可是IO占用大
  • 设置为 2 的时分,表明每次业务提交时都只是把redo log写到page cache
    • IO占用居中, 将写入到磁盘这个最占用IO的进程交由操作系统来担任

binlog是经过参数sync_binlog来操控的

  • sync_binlog=0 的时分,表明每次提交业务都只 write,不 fsync
  • sync_binlog=1 的时分,表明每次提交业务都会履行 fsync
  • sync_binlog=N(N>1) 的时分,表明每次提交业务都 write,但累积 N 个业务后才 fsync

两阶段日志提交

什么是两阶段日志提交

MySQL日志系统 - 一文贯通MySQL日志
将redo log日志提交的进程分为prepare和commit这两个阶段, binlog日志提交在这两个阶段中心

业务提交时redo log先提交后进入prepare状况, 然后binlog提交完结后redo log才能将日志的状况修正为commit已提交

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

和InnoDB引擎的回滚机制有关, InnoDB的redo log提交了业务就无法回滚了, 假如在redo log提交后binlog写入失利的话就会出现两份不共同的情况

假如此刻数据库异常重启的话要依据那一份来康复数据就值得考虑了, 所以才需要两阶段日志提交

假设现在在时刻A数据库溃散的话, 由于binlog还未写入, redo log还未提交, 所以重启后业务会回滚, 两份日志依旧是共同状况

假如是时刻段B的话, 就需要对redo log的提交标志进行判断了, 在查询redo log中是否有commit提交标志, 假如有的话业务没有问题, 直接提交

假如redo log中没有对应业务的提交标志的话会对binlog进行查看

  • 假如binlog完整而且带有commit标志, 就会提交业务并在redo log后边补上commit标志
  • 假如binlog不完整就回滚业务

这里能够发现两阶段日志提交中发生了溃散是依据binlog来进行规范判断的, 原因是由于主从复制是依据binlog来进行的

假如对两份日志都需要查看完整性的话, 主库挂掉切换到从库的时刻会变长, 以binlog为基准的话主库挂了直接拿着binlog去从库康复数据即可, 无需查看redo log的完整性

此外binlog是Mysql Server层的通用日志, 这也是选择binlog作为基准的原因

两阶段日志提交的缺点

  1. 磁盘IO次数高

    • 在提交日志的时分会有redo log和binlog对应的刷盘操作, IO次数高
  2. 锁竞赛激烈

    • 为了确保多个业务提交的时分日志的记载和业务的提交次序是共同的, 会运用锁来确保日志提交的相对次序
    • 可是在并发量大的情况下功能会变差

组提交机制

组提交机制的效果

当有躲过业务提交的时分, 将多个业务的日志兼并在一同去写入, 削减磁盘IO操作

组提交机制的完结

组提交机制将commit进程拆分红三个进程, 对每个进程都维护了一个行列, 而且经过锁来确保业务的写入次序

  • 分红三个阶段分别加锁能够削减锁粒度, 无需锁住业务的整个提交进程

当行列为空的时分第一个进入行列的业务会成为后续进入的业务的领导者, 带领后续业务完结接下来的阶段操作

阶段一 : flush阶段 : 多个业务按进入的次序将binlog从cache中写入文件 (不刷盘)

第一个进入flush阶段的业务会作为领导者领导后边进入的业务

领导者业务会带领一切的业务对 redo log 进行一次 write + fsync, 也便是将redo log 写入磁盘, 完结redo log 的propare阶段

假如在这个阶段Mysql溃散了, 会在重启后回滚这组业务

阶段二 : sync : 对binlog文件做fsync操作 (将多个业务的binlog兼并一同刷盘)

在flush阶段将binlog写入到binlog文件后, 会等候一段时刻再进行刷盘, 意图是组合更多业务的binlog一同刷盘削减耗费

等候会有时刻限制和最大业务限制, 满意其间一个条件就会立刻对binlog进行刷盘

sync阶段首要担任binlog的组提交, 假如当时阶段Mysql溃散的话, 在重启后能够经过redo log的刷盘记载持续完结业务提交

  • 由于此刻binlog已经完结提交了, 所以能够依据redo log来持续提交业务

阶段三 : commit : 对各个业务做InnoDB的commit操作