浅析InnoDB引擎架构(已完结)

大家好,我是此林。

今天来介绍下InnoDB底层架构。

1. 磁盘架构

我们所有的数据库文件都保存在 /var/lib/mysql目录下。

由于我这边是docker部署的mysql,用如下命令查看mysql数据挂载。

docker inspect mysql-master

如下图,目前只有一个数据库 db_user,数据库本质上是文件夹的形式。

在db_user文件夹下,目前只有一张表,表空间就是idb文件形式。

 表空间idb文件以B+树的形式组织存储,其中B+树的非叶子结点存储索引段,叶子结点存储的是数据段。此外还有回滚段。段用来管理多个区。

区是表空间的单元结构,每个区大小为1M,一个区有64个连续的页。

页,是InnoDB存储引擎磁盘管理的最小单元,每个页默认大小为16K。为了保证页的连续性,Inn哦DB存储引擎每次从磁盘申请4-5个区。

行,InnoDB存储引擎数据是按行存放的。

所有文件介绍:

1. db_user:自定义的数据库

2. mysql:mysql自带数据库,包含用户、权限和管理信息表

3. performance_schema、sys:mysql自带数据库,用于mysql性能监控

4. ib_logfile0、ib_logfile1:redo_log(重做日志)

5. binlog.000001、binlog000002:binlog(二进制日志)

6. undo_001、undo_002:undo_log(回滚日志)

2. 内存架构

1. BufferPool

数据表都保存在磁盘文件中,而用户是无法直接操作磁盘文件的,必须先把数据文件加载到内存中,用户对内存中的数据进行增删改操作,最后再以一定的频率把内存中的数据刷新到磁盘中。

InnoDB内存架构中,BufferPool(缓冲区)就是类似的作用。

BufferPool 中,以页(Page)为单位,每次它会去磁盘中加载整页(16K)数据。这样做的好处是减少磁盘IO,相当于缓存的作用。

BufferPool 中的 Page有三种类型:

1. 空页(free page),空闲页,未被使用

2. clean page,被使用的页,但是数据没有被修改过

3. 脏页(dirty page),被使用的page,数据被修改过,也就是和磁盘中数据不一致的页。

2. ChangeBuffer

更改缓冲区(针对非唯一的二级索引),在执行DML语句(增删改语句)时,如果这些这些数据Page不在BufferPool中,不会区操作磁盘,而是先把数据变更存在更改缓冲区中,未来数据被读取时,再将数据合并恢复到BufferPool中,最后再刷新到磁盘。

存在的意义?

和聚簇索引不同,二级索引通常是非唯一的,并且每次以相对随机的顺序插入二级索引。同样,删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作一次磁盘IO,会造成大量的磁盘IO,有了ChangeBuffer后,我们可以在缓冲池中进行合并操作,减少磁盘IO。

3. Adaptive Hash Index

InnoDB不支持Hash索引,它只支持B+树索引,我们目前所有的索引,底层结构都是B+树,主要原因是Hash索引虽然快,但是只支持等值匹配,不支持范围查询。

自适应Hash索引,用于优化对BufferPool的查询。InnoDB 存储引擎会监控对表上各个索引页的查询,如果观察到Hash索引可以提升速度,则建立Hash索引。系统自动优化,无需人工干预。

查询参数:

show variables like '%hash%';

默认是开启的。

4. LogBuffer

日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log,undo log)。默认大小为16MB,日志缓冲区的日志会定期刷到磁盘中。

参数:

show variables like 'innodb_log_buffer_size';  # 缓冲区大小
show variables like 'innodb_flush_log_at_trx_commit'; # 日志刷新到磁盘的时机

innodb_flush_log_at_trx_commit:

1: 日志在每次事务提交时写入并刷新磁盘

0:每秒将日志写入并刷新磁盘一次

2:日志在每次事务提交后写入,并且每秒刷新一次到磁盘中。

3. 后台线程

1. Master Thread

核心后台线程,负责调度其他线程,还负责将缓冲区中的数据异步刷新到磁盘中,保持数据的一致性,还包括脏页的刷新、合并插入缓存、undo页的回收。

2. IO Thread

在InnoDB中大量使用AIO(异步非阻塞)来处理IO请求,极大提高数据库性能。

IO Thread主要负责这些IO请求的回调。

命令:

show engine innodb status;

3. Purge Thread

主要用于回收事务已经提交的undo_log,在事务提交之后,undo log已经无用,需要回收。

4. Page Cleaner Thread

协助Master Thread刷新脏页到磁盘的线程,减轻Master Thread的工作压力,减少阻塞。

4. InnoDB 事务原理

事务特性(ACID):

1. 原子性:事务操作不可分割,要么同时成功,要么同时失败。

2. 一致性:事务完成时,所有数据必须保证一致性。

3. 隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发的影响的独立环境下运行。

4. 持久性:事务一旦 提交,对数据库的改变就是永久的。

原子性、一致性由undo_log来实现,

持久性由redo_log来实现,

隔离性由锁和MVCC机制来实现。

1. redo_log重做日志

我们知道,在执行update、delete、insert操作的时候,实际操作的是BufferPool内存中的数据,

但是BufferPool中的数据是由后台线程以一定的频率或由操作系统来决定何时同步到磁盘中的。

若BufferPool数据没来得及刷到磁盘中,服务器宕机,那么就会导致数据丢失。

redo_log出现后,流程变化如下:

1. 变更BufferPool中的数据

2. 数据页变化写入redo_log_buffer(内存)

3. 事务提交后,redo_log_buffer刷新到磁盘(redo_log)中。

4. 之后即使BufferPool没来得及刷新到磁盘,也可以通过redo_log来恢复。

问:redo_log不是多此一举吗?为什么不操作完BufferPool后,直接把脏页刷新到磁盘里?

答:

1. 我们一般在事务操作很多条记录,这些记录一般都是随机操作数据页的,此时将涉及大量的磁盘IO,性能极低。

2. 而redo_log日志文件写入都是追加顺序写入,性能高于随机磁盘IO。这种机制叫WAL(Write-Ahead-logging)——先写日志。

3. 当BufferPool中脏页的数据成功刷新到磁盘中,redo_log日志文件会被定期删除。

2. undo_log 回滚日志

回滚日志,用于记录数据被修改前的信息,作用有两个:

1. 提供回滚

2. MVCC(多版本并发控制)

可以认为当delete一条语句,undo_log中会记录一条对应的insert语句;当update一条语句,undo_log中会记录一条相反的update语句。

事务提交后,undo_log不会被立即删除,因为可能用于多版本并发控制(MVCC)。

3. MVCC 机制

1. 概要

简单来说,要保证并发安全,MYSQL觉得每次读的时候都要加锁,太损耗性能了。所以提出了MVCC机制,是不加锁的快照读(非阻塞读),提升了性能。

1. 当前读:

select ... lock in share mode (读锁)

select ... for update (写锁)

update、insert、delete

以上操作都是当前读,会对读取的记录加锁。

2. 快照读:

简单的select(不加锁)就是快照读。

Read Committed: 每次select,都生成一个快照读。

Repeatable Comitted: 开启事务后第一个select语句就是快照读的地方。

Serializable: 快照读退化成当前读。

2. 实现原理

MVCC的实现依赖数据库的行记录中的三个隐藏字段、undo_log、readView。

  • DB_TRX_ID:最近修改的事务ID,记录插入这条数据或最后一次修改该记录的事务ID。
  • DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undo_log,指向上一个版本。
  • DB_ROW_ID:当表中没有定义主键,MYSQL自动生成此字段作为主键。

查看命令:

idb2sdi table_name.idb

当insert的时候,产生的undo_log日志只在回滚时需要,事务提交后可以立即删除。

当update、delete时候,产生的undo_log日志不仅在回滚时需要,在快照读的时候也需要,不能立即删除。

3. 案例分析

来看下面一个案例:

undo_log版本链如下:

那我select的时候如何知道要访问哪个版本呢?

简单来说,它会拿到当前行的DB_TRX_ID(事务id),逐个和ReadView各个字段做条件判断,满足条件即返回该版本数据;若不满足会通过DB_ROLL_PTR回滚指针继续寻找版本,进行比对。

先看事务5:

假设当前事务隔离级别为RC,即每次select都会生成一个ReadView。

1. 执行第一个查询id为30的记录命令时,生成如下ReadView。读取到的事务2修改的age=10,name=A3。

ReadView
m_ids(当前活动事务id)[3,4,5]
min_trx_id(最小活动事务id,事务id时自增的)3
max_trx_id(最大活动事务id + 1,预分配的)6
creator_trx_id(当前ReadView创建的事务id)5

2. 执行第二个查询id为30的记录命令时,生成如下ReadView。读取到的是age=3,name=A30。

ReadView
m_ids(当前活动事务id)[4,5]
min_trx_id(最小活动事务id,事务id时自增的)4
max_trx_id(最大活动事务id + 1,预分配的)6
creator_trx_id(当前ReadView创建的事务id)5

但是当RR隔离级别下,第二个查询id为30的记录 会和 第一个查询id为30的记录 的结果一样,因为用的是同一个ReadView。如果这个时候不想快照读,用select for update可以查到最新的记录,因为这条加锁命令不走MVCC。

4. 总结

综上,MYSQL使用了MVCC和锁机制来保证了事务的四大特性(ACID)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/64793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ajax中的axios

既然提到Ajax,那就先来说一说什么是Ajax吧 关于Ajax Ajax的定义 Asynchronous JavaScript And XML:异步的JavaScript和XML。 反正就是一句话总结: 使用XML HttpRequest 对象与服务器进行通讯。 AJAX 是一种在无需重新加载整个网页的情况下&…

苹果手机怎么清理空间:拯救你的拥挤手机

在数字生活的海洋中,我们的苹果手机就像一艘小船,载满了照片、应用、视频和各种下载的“宝贝”。随着时间的推移,这艘小船开始变得拥挤,航行速度放缓,甚至有时候直接卡壳。苹果手机怎么清理空间?是时候学会…

三、使用langchain搭建RAG:金融问答机器人--检索增强生成

经过前面2节数据准备后,现在来构建检索 加载向量数据库 from langchain.vectorstores import Chroma from langchain_huggingface import HuggingFaceEmbeddings import os# 定义 Embeddings embeddings HuggingFaceEmbeddings(model_name"m3e-base")#…

C语言 函数嵌套

#include <stdio.h> void new_line() {printf("hehe\n"); } void three_line() {int i 0;for (i 0; i < 3; i){new_line;} } int main() {three_line();return 0; } 函数可以嵌套调用&#xff0c;但不能嵌套定义 链式访问 main有三个参数 //main函数的…

问题解决:发现Excel中的部分内容有问题。是否让我们尽量尝试恢复? 如果您信任此工作簿的源,请单击“是”。

在开发同步导出功能是遇到了如标题所示的问题&#xff0c;解决后遂记录下来供大家参考。 RestController public class XxxController {PostMapping("/export")public BaseResponse export(RequestBody PolicyErrorAnalysisExportReq exportReq, HttpServletRespons…

基于ST STM32MP257FAK3的MP2控制器之工业PLC 方案

简介 1.可编程逻辑控制器&#xff08;PLC&#xff09;是种专门为在工业环境下应用而设计的数字运算操作电子系统。它采用一种可编程的存储器&#xff0c;在其内部存储执行逻辑运算、顺序控制、定时、计数和算术运算等操作的指令&#xff0c;通过数字式或模拟式的输入输出来控制…

golang自定义MarshalJSON、UnmarshalJSON 原理和技巧

问题出现的原因&#xff1a;在前后端分离的项目中&#xff0c;经常出现的问题是时间戳格式的问题。 后端的日期格式兼容性强&#xff0c;比较完善。前端由于各种原因&#xff0c;日期格式不完善。 就会产生矛盾。 ms int64比较通用&#xff0c;但是unix时间没有可读性&#xff…

初始Python篇(7)—— 正则表达式

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 正则表达式的概念 正则表达式的组成 元字符 限定符 其他字符 正则表达式的使用 正则表达式的常见操作方法 match方法的…

使用 AI 辅助开发一个开源 IP 信息查询工具:一

本文将分享如何借助当下流行的 AI 工具,一步步完成一个开源项目的开发。 写在前面 在写代码时&#xff0c;总是会遇到一些有趣的机缘巧合。前几天&#xff0c;我在翻看自己之前的开源项目时&#xff0c;又看到了 DDNS 相关的讨论。虽然在 2021 年我写过两篇相对详细的教程&am…

Powershell学习笔记

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

《Java源力物语》-2.异常训练场

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” \quad 在java.lang古域的一处偏僻角落&#xff0c;矗立着一座古老的训练场。青灰色的围墙上布满了密密麻麻的源力符文&#xff0c;这些符文闪烁着…

一起学Git【第二节:创建版本库】

创建库 这个库相当于一个目录&#xff0c;目录中的文件都被Git管理&#xff0c;会记录每个文件的修改删除和添加工作&#xff0c;便于之后随时跟踪历史记录还原到之前的某一版本。如何创建库呢&#xff1f;有两种方式&#xff0c;本地创建库和云端克隆一个库。 1.本地创建库 …

HarmonyOS NEXT 技术实践-基于基础视觉服务的多目标识别

在智能手机、平板和其他智能设备日益智能化的今天&#xff0c;视觉识别技术成为提升用户体验和智能交互的重要手段。HarmonyOS NEXT通过基础视觉服务&#xff08;HMS Core Vision&#xff09;提供了一套强大的视觉识别功能&#xff0c;其中多目标识别作为其关键技术之一&#x…

nginx-静态资源部署

目录 静态资源概述 静态资源配置指令 listen指令 server_name指令 精确匹配 ​编辑 ​编辑 使用通配符匹配 使用正则表达式匹配 匹配执行顺序 default_server属性 location指令 root指令 alias指令 root与alisa指令的区别 index指令 error_page指令 直接使用 …

时空信息平台架构搭建:基于netty封装TCP通讯模块(IdleStateHandler网络连接监测,处理假死)

文章目录 引言I 异步TCP连接操作II 心跳机制:空闲检测(读空闲和写空闲)基于Netty的IdleStateHandler类实现心跳机制(网络连接监测)常规的处理假死健壮性的处理假死方案获取心跳指令引言 基于netty实现TCP客户端:封装断线重连、连接保持 https://blog.csdn.net/z92911896…

Linux之RPM和YUM命令

一、RPM命令 1、介绍 RPM(RedHat Package Manager).,RedHat软件包管理工具&#xff0c;类似windows里面的setup,exe是Liux这系列操作系统里而的打包安装工具。 RPMI包的名称格式&#xff1a; Apache-1.3.23-11.i386.rpm “apache’” 软件名称“1.3.23-11” 软件的版本号&am…

aosp15 - Activity生命周期切换

本文探查的是&#xff0c;从App冷启动后到MainActivity生命周期切换的系统实现。 调试步骤 在com.android.server.wm.RootWindowContainer#attachApplication 方法下断点&#xff0c;为了attach目标进程在com.android.server.wm.ActivityTaskSupervisor#realStartActivityLock…

【漫话机器学习系列】017.大O算法(Big-O Notation)

大 O 表示法&#xff08;Big-O Notation&#xff09; 大 O 表示法是一种用于描述算法复杂性的数学符号&#xff0c;主要用于衡量算法的效率&#xff0c;特别是随着输入规模增大时算法的运行时间或占用空间的增长趋势。 基本概念 时间复杂度 描述算法所需的运行时间如何随输入数…

ensp 基于端口安全的财务部网络组建

ARP IP数据包通过以太网发送&#xff0c;但以太网设备并不能识别IP地址&#xff0c;它们是以MAC地址传输的。因此&#xff0c;必须把IP目的地址转换成MAC目的地址。在以太网中&#xff0c;一个主机要和另一个主机进行直接通信&#xff0c;必须要知道目标主机的MAC地址。 ARP&…

在 Ubuntu 上安装 Muduo 网络库的详细指南

在 Ubuntu 上安装 Muduo 网络库的详细指南 首先一份好的安装教程是非常重要的 C muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装-CSDN博客 像这篇文章就和shit一样&#xff0c;安装到2%一定会卡住&#xff0c;如果你不幸用了这个那真是遭老罪了 环境&#xf…