Day.13 Crash Recovery - InnoDB 架构 -> MYSQL 二阶段提交(2PC) _1


今天开始的主题有关於MYSQL的crash-safe能力(二阶段提交),如何保证服务在任何时间发生崩溃时,重启後之前的提交纪录不会发生数据丢失状况。

事务提交流程

在binlog内容中我们可以看到事件的上下文都会有纪录BEGIN和COMMIT 代表这个事件的开始与结束,因为预设autocommit为开启,所以当我们输入一条SQL指令,MYSQL就会自动帮我们提交执行内容(等於在binog里看到的一个事件)。

透过以下简单例子了解开启与关闭自动提交的差异~ 开启2个连线而右边的连线只做查询资料动作。
https://ithelp.ithome.com.tw/upload/images/20210829/20130880Pzlu1zZpzx.png

  • mysql执行Transaction的流程分别为:
  1. 进入交易模式- start transaction 或 begin
  2. 本次交易要执行的SQL内容(update/insert....)
  3. 结束交易模式- commit
  • 当交易过程中(2.)的时候有错误- rollback (表示取消交易,还原到未交易时的状态)

ps. DDL语句是无法进行rollback 的喔!!


储存引擎

就像是资料库的核心,以MYSQL来说常见的有InnoDB&MyISAM。MYSQL 5.5版开始所使用的(预设引擎)是InnoDB,不同引擎有各自优缺点与应用需求,这边就不多描述罗~

#看支持的引擎有哪些
mysql> show engines;

9 rows in set (0.00 sec)

mysql> show variables like 'default_storage_engine';
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+

为什麽会看到叙述时有时候用(事务)有时候用(事件),透过show engines可以发现除了InooDB其他引擎都是不支援事务的,像常见的MyISAM ~ 所以才会以事件叙述避免混淆。不过现在预设就是使用InnoDB所以看成同样的就行啦~


认识一点innoDB架构

由於二阶段流程上会牵扯到一些innoDB架构内部机制流程,所以这边先带一点innoDB架构相关内容在进入正题比较好了解意思。/images/emoticon/emoticon33.gif

(引用mysql官方5.7的InnoDB架构图) 先看一下架构中(左)内存区&(右)磁盘区分别包含什麽~
https://ithelp.ithome.com.tw/upload/images/20210908/20130880ZuhVJpChcN.png

  • 认识InnoDB内存架构中的Buffer Pool(缓冲池):

观念: 资料库中的数据最终都是要存放到磁盘上的,不过在磁盘的读取速度会比内存慢很多,所以不可能每次读写资料都往磁盘执行,势必造成效能上的影响。

  • 数据页(Page)- InnoDB储存数据的基本结构,页会储存资料库相关数据内容,作为磁盘与内存交互的最基本单位。

  • 脏页- 指的是在缓冲池中已经被修改的页,还没被刷新到磁盘上。
    (ex.数据页A 在buffer pool中的内容比在disk中的还要新= 脏页)

那身为一个储存资料系统,资料会频繁的做存取是很正常的。透过缓冲池在资料读取上缓存访问时的表和索引数据,去达到加快读取请求的处理速度提升效能。另外执行资料的更新异动时也是先在buffer pool中完成的喔!

观念: 如果内存中不存在要读取or更新的数据,会先从disk载入数据所在数据页至buffer pool中在做更新,而不是直接透过disk去存取资料。ex.读取一条数据

查询语句 ->                        (判断有无命中)    
           判断数据页是否存在於内存中     --->    if N (从磁盘中将该纪录对应的数据页加载至内存)
                                     --->    if Y 返回数据

MYSQL崩溃复原Q&A /images/emoticon/emoticon33.gif

Q1: 如果内存中的数据已更新(磁盘上的数据尚未更新),那当MySQL服务在任何时间发生异常关闭的状况下,如何去保证重启後还尚未落盘的内存资料不会丢失?

A1: mysql如何实现crash-safe保证事务完整性,靠的就是innoDB架构中的redo log和undo log日志纪录,在提交阶段中如果发生意外崩溃,对於已提交的事务资料就不会造成丢失(redo log),而对於提交尚未完整的事务则会进行rollback(undo log)。

Q2: 为什麽binlog无法做到crash-safe能力,而redo log可以做到?

来看一下两者之间差异:

-- binlog redo log
层级 Server InnoDB
储存内容 逻辑日志 物理日志
写入方式 追加写(参数设定切换) 循环写(固定大小)
内容 SQL语句逻辑 事务执行过程中对数据页的修改
作用 mysql主从,备份,还原 mysql崩溃恢复

有关於redo log需了解以下内容:

  • 日志缓存区(Log Buffer)

参考上图InnoDB架构内存区域,Log Buffer包含了保存要写入磁盘InnoDB日志文件(redo log)的数据。

  • redo log

    • 可分为在内存中的日志缓冲(redo log buffer) 和在磁盘上的日志文件(redo log file)。

      ex.在mysql数据目录下会看到 ib_logfile0,ib_logfileN 的文件。可以发现redo log不只有一个储存文件,有ib_logfile0~ib_logfileN 个。

    透过以下参数配置redo log文件数量&大小 ex.预设为2个redo log文件档

    mysql> show variables like '%innodb_log_file%';
     +---------------------------+----------+
     | Variable_name             | Value    |
     +---------------------------+----------+
     | innodb_log_file_size      | 50331648 |
     | innodb_log_files_in_group | 2        |
     +---------------------------+----------+
     2 rows in set (0.01 sec)     
    
    
     ps.在innodb_log_file_size 的设定上对inooDB性能面来说是有相对影响的!像设置太大的值可能会造成崩溃恢复时的时间拉长。
    
    • 追加写(binlog) vs. 循环写(redolog)
      在前面我们介绍过binlog的当纪录写满时会切换至新的一个log档纪录(写满就切新日志文件),而在这边redo log循环写的意思为比如我目前redo log文件设定为2个,资料的写入与清除都是在这2个档案中(ib_logfile0 / 有ib_logfile1)中循环。

这边开始要想一下喔~

  • 注意: 当我们执行一条DML语法时会先将记录写入内存中的redo log buffer(纪录修改後的值),事务提交时再将其写至磁盘上redo log file,最後定期将内存中更改的数据(脏页)刷新至磁盘上。

  • 以下图帮助你认识redo log文件资料的纪录(write pos)与清除(checkpoint)作用
    https://ithelp.ithome.com.tw/upload/images/20210909/20130880W18fViVrLb.png

  • WAL机制(Write-Ahead Logging)- 在redo log采用。

是指写操作时不会立刻更新至磁盘上,而是先纪录到日志,等到某个时机点在更新至磁盘上。而由於写入磁碟档案是随机写,写入日志为顺序写。相比之下顺序写的方式造成的开销与效能相对小,所以使用日志先行的机制。

一般会看到日志先行的解释为先写入日志在写入磁盘,不过不知道实际上流程是指什麽~

解释: 先将内存中对应的日志页持久化(redo log buffer-写入->redo log file),才持久化内存的更新数据页至磁盘上。

A2: 看完以上比较可以看到由於redolog是固定大小的,不断的循环写。所以当日志满了的状况下,就会需要对旧的纪录做删除,而删除的前提是这些数据页内容已经从内存刷入磁盘中!以储存内容来说binlog没有能判断哪些数据是否已刷盘的标示。所以当mysql挂了重启时会使用redo log纪录进行复原,来保证数据持久完整性。


明天来讲关於redo log和binlog日志写入策略影响~


<<:  [早餐吃到饱-2] 星享道酒店 - 星飨道国际自助餐 - 早餐 In Sky International Buffet - 台中逢甲商圈

>>:  Day6 开机学习 Lua - 标准函式库

[Day 12 - Bootstrap] Bootstrap一下,快速建立响应式网站

为什麽要使用Bootstrap? 现在的网页为了能够适应不同装置,会进行响应式设计;并且大多考量到使...

Ruby、演算法学习心得(一) 二元搜寻法 Binary Search。

铁人赛结束後一阵空虚?? 文章内容都会以Ruby来撰写程序码,然後继续来传教K-POP啦! 有请韩国...

Vue CLI安装

前面都使引用CDN的script标签去使用Vue.js,今天要介绍的是用NPM去安装vue-cli ...

Day1 - 前言

这里是大卫吴的铁人纪录 嘛~这是我第一次参赛 期许自己能完成30天的挑战 以下主题相关: 这次铁人的...

postgresql-pgadmin

今天要介绍PostgreSQL(Relational database) 安装postgresql...