MySQL技术内幕

2. InnoDB存储引擎

2.1 InnoDB存储引擎概述

特点:行锁设计、支持MVCC、支持外键、提供一致性非锁定读

2.2 InnoDB体系架构

2.2.1 后台线程

InnoDB存储引擎时多线程的模型,因此后台有多个不同的后台线程,负责处理不同的任务。

1. Master Thread

非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(INSERT BUFFER)、UNDO页的回收等

2. IO Thread

InnoDB引擎中使用了大量的AIO(Async IO)来处理IO请求,IO Thread的主要工作时负责这些IO请求的回调处理。

4个IO Thread:write、read、insert buffer和log IO Thread。

3. Purge Thread

事务被提交后,其所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。

4. Page Cleaner Thread

作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。

2.2.2 内存

1. 缓冲池(Buffer Pool)
  • 读取:在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页“FIX”在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
  • 修改:对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为Checkpoint的机制刷新回磁盘。

缓冲池中的数据类型:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、锁信息(lock info)、数据字典信息(data dictionary)。

2. LRU算法及优化

典型的LRU算法是最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。

问题:

  1. 全表扫描:全表扫描的数据量大,需要淘汰的数据页多,在淘汰的过程中极有可能将频繁使用到的数据页给淘汰了,而新数据却是使用频率很低的数据。
  2. 预读

优化:

  1. 冷热分离:

    • 将LRU链表分为两部分,一部分用来存放冷数据,也就是刚从磁盘读进来的数据,另一部分用来存放热点数据,也就是经常被访问到的数据。
    • 当从磁盘读取数据页后,会先将数据页放到LRU链表冷数据区的head,如果这些数据页在1s后再被访问,则这些数据页会被移动到热点数据区的head。
    • 淘汰数据页时,从冷数据区的tail开始淘汰。
  2. 当一个数据页处于热点数据区,且在热点数据区的前1/4区域,那么当访问这个数据页的时候,不需要移动到热点数据区的head部,如果位于热点数据区的后3/4区域,那么当访问这个数据页的时候,会把它移动到热点数据区的head部。
  3. 支持多个Buffer Pool。
3. Flush列表

在LRU列表中的页被修改后,称该页为脏页(dirty page),即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过CHECKPOINT机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。需要注意的是,脏页既存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘,二者互不影响。

4. 重做日志缓冲(redo log buffer)

重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中:

  • Master Thread每一秒将重做日志缓冲刷新到重做日志文件;
  • 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
  • 当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件。

2.3 Checkpoint 技术

脏页:如果一条DML语句,如Update、Delete改变了页中的记录,也就是缓冲池中页的版本比磁盘的新,那么此时页就是脏的。

事务提交时,先写重做日志,再修改页,实现ACID中的D(Durability持久性)。

在InnoDB引擎中,通过LSN(Log Sequence Number)来标记版本,LSN是8字节的数字,单位是字节。

发生Fuzzy Checkpoint的情况:

  1. Master Thread Checkpoint:Master Thread每秒或每十秒从缓冲池的脏页列表中异步刷新一定比例的页回磁盘;
  2. FLUSH_LRU_LIST Checkpoint:Page Cleaner线程在LRU列表中空闲页少于某值得时候,会从LRU列表尾端移除一些页,如果这些页中有脏页,那么需要进行Checkpoint;
  3. Async/Sync Flush Checkpoint:重做日志文件不可用时,Page Cleaner Thread强制刷新一些页回磁盘;
  4. Dirty Page too Much:缓冲池中脏页比例超过设定值时,强制刷新一些页回磁盘。

2.4 Master Thread

Master Thread:最高优先级,由主循环、后台循环、刷新循环、暂停循环组成,根据数据库状态自动切换循环。

Master Thread 伪代码:

void master_thread() {
goto loop; loop: // 1. 主循环
for (int i = 0; i< 10; i++) {
Thread.sleep(1000); // 休眠一秒
// 每秒的操作
1.1.1. 刷新日志缓冲到磁盘,即使这个事务还没有提交;
// innodb_io_capacity设置的磁盘IO吞吐量
if (last_one_second_ios < 5% * innodb_io_capacity) {
// 如果当前1秒发生IO次数小于5
1.1.2. 合并插入缓冲(Insert Buffer), 数量:5% * innodb_io_capacity;
}
if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {
// 如果当前缓冲池中脏页比例大于配置文件中的设定值
1.1.3.1. 刷新至多innodb_io_capacity个脏页到磁盘;
} else if (enable adaptive flush) { // 自适应刷新,通过产生redo日志速度判断
1.1.3.2. 刷新合适量的脏页到磁盘;
}
if (no user activity) {
// 没有用户活动(数据库空闲),则切换到后台循环
1.1.4. goto background loop;
}
}
// 每十秒的操作
if (last_ten_second_ios < innodb_io_capacity) {
1.2.1. 刷新innodb_io_capacity个脏页到磁盘;
}
1.2.2. 合并至多5% * innodb_io_capacity个插入缓冲;
1.2.3. 将日志缓冲刷入到磁盘;
1.2.4. 删除最多20个无用的undo页;
if (buf_get_modified_ratio_pct > 70%) {
1.2.5.1 刷新innodb_io_capacity个脏页到磁盘
} else {
1.2.5.2 刷新10% * innodb_io_capacity脏页到磁盘
}
goto loop; background loop: // 2. 后台循环
2.1. 删除无用的undo页;
2.2. 合并innodb_io_capacity个插入缓冲;
if (not idle) {
// 跳回主循环
goto loop;
} else {
// 跳到刷新循环
goto flush loop;
} flush loop: // 3. 刷新循环
3.1. 刷新innodb_io_capacity个脏页到磁盘;
if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {
// 如果当前缓冲池中脏页比例大于配置文件中的设定值
goto flush loop;
}
goto suspend loop; suspend loop: // 4. 暂停循环
suspend_thread(); // Master Thread 挂起
waiting event; // 等待事件的发送
goto loop;
}

InnoDB 1.2.x版本的Master Thread

if InnoDB is idel:
srv_master_do_idle_tasks();
else:
srv_master_do_active_tasks();

其中:srv_master_do_idle_tasks()就是之前版本中每10秒的操作,srv_master_do_active_tasks()处理的是之前每秒中的操作。刷新脏页的操作,分离到一个单独的Page Cleaner Thread。

2.5 InnoDB的关键特性

2.5.1 Insert Buffer

对于非聚集且不是唯一索引的插入或者更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入;若不在,则先放到一个Insert Buffer对象中,然后在以一定的频率和情况进行Insert Buffer和辅助索引叶子节点的merge操作。能大大提高对于非聚集索引插入的性能。

Insert Buffer的使用需要满足以下两个条件:

  1. 索引是辅助索引(secondary index);
  2. 索引不是唯一(unique)。

Merge Insert Buffer

可能发生在以下几种情况:

  • 辅助索引页被读取到缓冲池;
  • Insert Buffer Bitmap页追踪到该辅助索引页已无可用空间;
  • Master Thread

2.5.2 两次写(double write)

部分写失效(partial page write):

数据库宕机时,缓冲池的某个页只写了一部分到磁盘中,比如16KB的页,只写了前4KB就发生了宕机,这种情况被称为部分写失效。

redo日志记录的是对页的物理操作,如偏移量,因此重做是无意义的。

2.5.3 自适应哈希

数据库自优化,通过B+树页构造哈希索引,提升查询速度。

2.5.4 异步IO

2.5.5 刷新邻接页

MySQL技术内幕(一)的更多相关文章

  1. Mysql技术内幕(第四版)读书笔记(一)

    题记:写代码已经有2年了,学到了很多知识,但是没有一个好习惯去记录,去分享,好多知识点都会忘记,所以从今天开始学着像大牛一样去记录自己经历项目的点点滴滴,先从最近读<Mysql技术内幕>开 ...

  2. mysql技术内幕InnoDB存储引擎-阅读笔记

    mysql技术内幕InnoDB存储引擎这本书断断续续看了近10天左右,应该说作者有比较丰富的开发水平,在源码级别上分析的比较透彻.如果结合高可用mysql和高性能mysql来看或许效果会更好,可惜书太 ...

  3. MySql技术内幕之MySQL入门(2)

    MySql技术内幕之MySQL入门(2) 接上一篇. mysql> source create_member.sql; # 创建member表 Query OK, 0 rows affected ...

  4. MySql技术内幕之MySQL入门(1)

    目录 MySql技术内幕之MySQL入门(1) 安装 关于注释 执行SQL语句 关于命令大小写 创建数据库 查看表的信息 查看更加详细的信息 查看与给定模式相匹配的列 插入数据 利用insert添加行 ...

  5. 《MySQL技术内幕:InnoDB存储引擎(第2版)》书摘

    MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子中使用了mysqld_safe命令来启动数据库,当然启动MySQL实例的方 ...

  6. 《mysql技术内幕 InnoDB存储引擎(第二版)》阅读笔记

    一.mysql架构 mysql是一个单进程多线程架构的数据库. 二.存储引擎 InnoDB: 支持事务 行锁 读操作无锁 4种隔离级别,默认为repeatable 自适应hash索引 每张表的存储都是 ...

  7. Mysql技术内幕——InnoDB存储引擎

    Mysql技术内幕——InnoDB存储引擎 http://jingyan.baidu.com/article/fedf07377c493f35ac89770c.html 一.mysql体系结构和存储引 ...

  8. 《[MySQL技术内幕:SQL编程》读书笔记

    <[MySQL技术内幕:SQL编程>读书笔记 2019年3月31日23:12:11 严禁转载!!! <MySQL技术内幕:SQL编程>这本书是我比较喜欢的一位国内作者姜承尧, ...

  9. 读书笔记-《Mysql技术内幕》

    MYSQL 技术内幕 Mysql体系 连接池组件 管理服务和工具 SQL接口 查询分析器 优化器 缓冲 插件式存储引擎 物理文件 存储引擎 InnoDB(默认引擎) 支持事务 行锁设计 多版本并发控制 ...

  10. Mysql技术内幕之InnoDB锁探究

    自7月份换工作以来,期间一直在学习MySQL的相关知识,听了一些视频课,但是一直好奇那些讲师的知识是从哪里学习的.于是想着从书籍中找答案.毕竟一直 看视频也不是办法,不能形成自己的知识.于是想着看书汲 ...

随机推荐

  1. 【LeetCode】889. Construct Binary Tree from Preorder and Postorder Traversal 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  2. Codeforces 872B:Maximum of Maximums of Minimums(思维)

    B. Maximum of Maximums of Minimums You are given an array a1, a2, ..., an consisting of n integers, ...

  3. AOP 日志切面

    AOP把软件的功能模块分为两个部分:核心关注点和横切关注点.业务处理的主要功能为核心关注点,而非核心.需要拓展的功能为横切关注点.AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点进行分 ...

  4. Linux中架构中的备份服务器搭建(rsync)

    本期内容概要 Linux中的备份方式 架构中备份服务器搭建(rsync) 内容详细 1.备份方式 1. cp : 本机复制(只能作用在本机) 2. scp : 远程复制 两种模式: 推 : 本地上传到 ...

  5. vue 设置请求超时时间处理

    Vue.http.post('http://114.214.164.77:2222/crptorgraphy',{msg:JSON.stringify(req)},{emulateJSON:true, ...

  6. [炼丹术]使用Pytorch搭建模型的步骤及教程

    使用Pytorch搭建模型的步骤及教程 我们知道,模型有一个特定的生命周期,了解这个为数据集建模和理解 PyTorch API 提供了指导方向.我们可以根据生命周期的每一个步骤进行设计和优化,同时更加 ...

  7. CS5213设计说明书|Capstone CS5213|CS5213设计参考电路

    Capstone CS5213是一款HDMI到VGA转换器结合了HDMI输入接口和模拟RGB DAC输出且带支持片上音频数模转换器.CS5213芯片设计简单,整体芯片尺寸精悍,外围电路集成优化度较高, ...

  8. Mybatis的联合查询

    数据库表结构 department employee 要求一 现在的要求是输入 id 把 employee 表的对应员工数据查询出来,并且查询出该员工的所处部门信息 JavaBean public c ...

  9. 在CentOS7系统安装与配置RabbitMQ

    在CentOS7系统安装与配置RabbitMQ 远程访问需要开放端口 https://www.cnblogs.com/heqiuyong/p/10460150.html

  10. laravel源码分析-队列Queue

    laravel 源码分析具体注释见 https://github.com/FX-Max/source-analysis-laravel 前言 队列 (Queue) 是 laravel 中比较常用的一个 ...