InnoDB存储引擎-程序员宅基地

技术标签: java  MYSQL  开发语言  

其实存储引擎也很简单,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。

有哪些已有的存储引擎可以让我们选择呢?

InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated、Example

种类很多,但是常用的存储引擎目前就只有InnoDB和MyISAM,下面将会介绍到InnoDB存储引擎。

InnoDB体系架构

InnoDB存储引擎有多个内存块,这些内存块组成了一个大的内存池。后台线程主要负责刷新内存池中的数据、将已修改的数据刷新到磁盘等等。接下来我们分别介绍后台线程和内存池。

后台线程

InnoDB后台有多个不同的线程,用来负责不同的任务。主要有如下:

  • Master Thread
    这是最核心的一个线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括赃页的刷新、合并插入缓冲、UNDO 页的回收等.
  • IO Thread
    在 InnoDB 存储引擎中大量使用了异步 IO 来处理写 IO 请求, IO Thread 的工作主要是负责这些 IO 请求的回调处理。
  • Purge Thread
    事务被提交之后, undo log 可能不再需要,因此需要 Purge Thread 来回收已经使用并分配的 undo页. InnoDB 支持多个 Purge Thread, 这样做可以加快 undo 页的回收。
  • Page Cleaner Thread
    Page Cleaner Thread 是在InnoDB 1.2.x版本新引入的,其作用是将之前版本中脏页的刷新操作都放入单独的线程中来完成,这样减轻了 Master Thread 的工作及对于用户查询线程的阻塞。

内存

InnoDB的内存架构主要分为三大块:

  • 缓冲池(Buffer Pool)
  • 重做缓冲池(Redo Log Buffer)
  • 额外内存池

缓冲池

InnoDB为了做数据的持久化,会将数据存储到磁盘上。但是面对大量的请求时,CPU的处理速度和磁盘的IO速度之间差距太大,为了提高整体的效率, InnoDB引入了缓冲池

当有请求来查询数据时,如果缓存池中没有,就会去磁盘中查找,将匹配到的数据放入缓存池中。同样的,如果有请求来修改数据,MySQL并不会直接去修改磁盘,而是会修改已经在缓冲池的页中的数据,然后再将数据刷回磁盘,这就是缓冲池的作用,加速读,加速写,减少与磁盘的IO交互。

缓冲池说白了就是把磁盘中的数据丢到内存,那既然是内存就会存在没有内存空间可以分配的情况。所以缓冲池采用了LRU算法,在缓冲池中没有空闲的页时,来进行页的淘汰。但是采用这种算法会带来一个问题叫做缓冲池污染

LUR算法

在 MySQL 中,LRU 指的是 Least Recently Used 缓存淘汰算法。该算法用于在缓存空间不足时,通过淘汰最近最少使用的数据来腾出空间,以便让新的数据进入缓存。

MySQL 中常用 LRU 算法来管理缓存,例如 InnoDB 存储引擎就使用了 LRU 算法来管理其缓冲池(Buffer Pool)。InnoDB 的缓冲池是一个内存区域,用于缓存数据库中的数据页,通过缓存页,可以避免频繁读取磁盘,从而提高数据库的性能。当需要获取一个数据页时,InnoDB 会首先在缓冲池中查找,如果找到了就直接返回,否则会从磁盘中读取并放入缓冲池中。

当缓冲池空间不足时,InnoDB 就需要根据 LRU 算法来淘汰一些数据页。具体来说,InnoDB 会维护一个“最近使用列表”(Recently Used List)和一个“最近未使用列表”(Recently Unused List),最近使用的数据页会被移到最前面,最近未使用的数据页则会移到后面。当需要淘汰数据页时,InnoDB 会选择最近未使用的数据页进行淘汰,以便让更常用的数据页留在缓冲池中,从而提高缓存命中率。

需要注意的是,LRU 算法是一种基于历史访问模式的淘汰算法,它假设未来的访问模式会和过去的访问模式相似,因此会尽可能地保留最近使用的数据。但是,在实际应用中,访问模式并不一定会保持不变,因此 LRU 算法也有其局限性。针对这个问题,还有其他缓存淘汰算法,如 MRU(Most Recently Used)、LFU(Least Frequently Used)等,可以根据具体场景来选择合适的算法。

缓冲池污染

缓冲池污染(Buffer Pool Contention)是数据库系统中的一个性能问题,指的是多个事务同时访问和争用缓冲池中的同一数据页,从而导致了事务之间的等待和竞争,以及数据库性能下降。缓冲池污染通常发生在高负载的数据库系统中,它可能会导致系统响应变慢,甚至服务不可用。

在一个并发访问的环境中,当多个事务同时需要访问或修改同一个数据页时,它们都需要先将该数据页读入到缓冲池中,再进行读取或修改操作。由于缓冲池的大小有限,当缓冲池中的数据页被占满后,新的事务需要等待已有事务归还缓冲池中的数据页才能继续执行,这就是缓冲池的竞争现象。

缓冲池污染的另一个原因是缓冲池管理算法的问题,常见的缓冲池管理算法包括最近最少使用(LRU)、先进先出(FIFO)等,它们都是基于一些策略来选择要从缓冲池中淘汰的数据页。如果选择的策略不够优秀,就会导致缓冲池中的热点数据页被频繁淘汰,从而影响系统性能。

当你在进行批量扫描甚至全表扫描时,可能会将缓冲池中的热点页全部替换出去。这样以来可能会导致MySQL的性能断崖式下降。所以InnoDB对LRU做了一些优化,规避了这个问题。

MySQL采用日志先行,在真正写数据之前,会首先记录一个日志,叫Redo Log,会定期的使用CheckPoint技术将新的Redo Log刷入磁盘,这个后面会讲。

除了数据之外,里面还存储了索引页、Undo页、插入缓冲、自适应哈希索引、InnoDB锁信息和数据字典。下面选几个比较重要的来简单聊一聊。

插入缓存

插入缓冲针对的操作是更新或者插入,我们考虑最坏的情况,那就是需要更新的数据都不在缓冲池中。那么此时会有下面两种方案。

  1. 来一条数据就直接写入磁盘
  2. 等数据达到某个阈值(例如50条)才批量的写入磁盘

很明显,第二种方案要好一点,减少了与磁盘IO的交互。

两次写

鉴于都聊到了插入缓冲,我就不得不需要提一嘴两次写,因为我认为这两个InnoDB的特性是相辅相成的。

插入缓冲提高了MySQL的性能,而两次写则在此基础上提高了数据的可靠性。我们知道,当数据还在缓冲池中的时候,当机器宕机了,发生了写失效,有Redo Log来进行恢复。但是如果是在从缓冲池中将数据刷回磁盘的时候宕机了呢?

这种情况叫做部分写失效,此时重做日志就无法解决问题。

在刷脏页时,并不是直接刷入磁盘,而是copy到内存中的Doublewrite Buffer中,然后再拷贝至磁盘共享表空间(你可以就理解为磁盘)中,每次写入1M,等copy完成后,再将Doublewrite Buffer中的页写入磁盘文件。

有了两次写机制,即使在刷脏页时宕机了,在实例恢复的时候也可以从共享表空间中找到Doublewrite Buffer的页副本,直接将其覆盖原来的数据页即可。

自适应哈希索引

自适应索引就跟JVM在运行过程中,会动态的把某些热点代码编译成Machine Code一样,InnoDB会监控对所有索引的查询,对热点访问的页建立哈希索引,以此来提升访问速度。

异步IO(AIO)

为了提高磁盘操作性能,当前的数据库系统都采用异步IO的方式来处理磁盘操作。InnoDB也是如此。

与AIO对应的是Sync IO,即每进行一次IO操作,需要等待此次操作结束才能继续接下来的操作。但是如果用户发出的是一条索引扫描的查询,那么这条SQL语句可能需要扫描多个索引页,也就是需要进行多次IO操作。在每扫描一个页并等待其完成再进行下一次扫描,这是没有必要的。用户可以在发出一个IO请求后立即再发出另外一个IO请求,当全部IO请求发送完毕后,等待所有IO操作完成,这就是AIO。

AIO的另外一个优势是进行IO Merge操作,也就是将多个IO合并为一个IO操作,这样可以提高IOPS的性能。

在InnoDB 1.1.x之前,AIO的实现是通过InnoDB存储引擎中的代码来模拟的。但是从这之后,提供了内核级别的AIO的支持,称为Native AIO。Native AIO需要操作系统提供支持。Windows和Linux都支持,而Mac则未提供。在选择MySQL数据库服务器的操作系统时,需要考虑这方面的因素。

MySQL可以通过参数innodb_use_native_aio来决定是否启用Native AIO。在InnoDB存储引擎中,read ahead方式的读取都是通过AIO完成,脏页的刷新,也是通过AIO完成。

刷新邻接页

InnoDB存储引擎在刷新一个脏页时,会检测该页所在区(extent)的所有页,如果是脏页,那么一起刷新。这样做的好处是通过AIO可以将多个IO写操作合并为一个IO操作。该工作机制在传统机械磁盘下有显著优势。但是需要考虑下吧两个问题:

是不是将不怎么脏的页进行写入,而该页之后又会很快变成脏页?
固态硬盘有很高IOPS,是否还需要这个特性?
为此InnoDB存储引擎1.2.x版本开始提供参数innodb_flush_neighbors来决定是否启用。对于传统机械硬盘建议使用,而对于固态硬盘可以关闭。

重做缓冲池

上面聊过,InnoDB中缓冲池中的页数据更新会先于磁盘数据更新的,InnoDB也会采用日志先行(Write Ahead Log)策略来刷新数据,什么意思呢?当事务开始时,会先记录Redo Log到Redo Log Buffer中,然后再更新缓冲池页数据。

Redo Log Buffer中的数据会按照一定的频率写到重做日志中去。被更改过的页就会被标记成脏页,InnoDB会根据CheckPoint机制来将脏页刷到磁盘。

Redo Log 日志详解

额外缓冲池

InnoDB在对一些数据结构本身的内存分配时,需要从额外的内存池中进行申请。例如缓冲池中的中的一些对象记录了锁、等待、LUR等消息,这些对象需要从额外的内存池中申请内存。

ChectPoint技术

说完缓冲池,下面说CheckPoint技术。
CheckPoint技术是用来解决如下几个问题:

  • 缩短数据库恢复时间
  • 缓冲池不够用时,将脏页刷新到磁盘
  • 重做日志不可用时,刷新脏页

缩短数据库恢复时间

缩短数据库恢复时间,重做日志中记录了的checkpoint的位置,这个点之前的页已经刷新回磁盘,只需要对checkpoint之后的重做日志进行恢复。这样就大大缩短了恢复时间。

缓冲池不够用

缓冲池不够用时,根据LRU算法,溢出最近最少使用的页,如果页为脏页,强制执行checkpoint,将脏页刷新回磁盘。

重做日志不可用

重做日志不可用,是指重做日志的这部分不可以被覆盖,为什么?因为:由于重做日志的设计是循环使用的。这部分对应的数据还未刷新到磁盘上。数据库恢复时,如果不需要这部分日志,即可被覆盖;如果需要,必须强制执行checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。

checkpoint每次刷新多少页到磁盘?每次从哪里取脏页?什么时间触发checkpoint?

InnoDB存储引擎内部,两种checkpoint,分别为:

  • Sharp Checkpoint
  • Fuzzy Checkpoint

Sharp Checkpoint

Sharp Checkpoint发生在数据库关闭时,将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数:innodb_fast_shutdown=1。
不适用于数据库运行时的刷新。

Fuzzy Checkpoint

在数据库运行时,InnoDB存储引擎内部采用Fuzzy Checkpoint,只刷新一部分脏页。

几种发生Fuzzy Checkpoint的情况:
①MasterThread Checkpoint
异步刷新,每秒或每10秒从缓冲池脏页列表刷新一定比例的页回磁盘。异步刷新,即此时InnoDB存储引擎可以进行其他操作,用户查询线程不会受阻。
②FLUSH_LRU_LIST Checkpoint
InnoDB存储引擎需要保证LRU列表中差不多有100个空闲页可供使用。在InnoDB 1.1.x版本之前,用户查询线程会检查LRU列表是否有足够的空间操作。如果没有,根据LRU算法,溢出LRU列表尾端的页,如果这些页有脏页,需要进行checkpoint。因此叫:flush_lru_list checkpoint。
InnoDB 1.2.x开始,这个检查放在了单独的进程(Page Cleaner)中进行。好处:1.减少master Thread的压力 2.减轻用户线程阻塞。
设置参数:innodb_lru_scan_dept:控制LRU列表中可用页的数量,该值默认1024
③Async/Sync Flush Checkpoint
指重做日志不可用的情况,需要强制刷新页回磁盘,此时的页时脏页列表选取的。
这种情况是保证重做日志的可用性,说白了就是,重做日志中可以循环覆盖的部分空间太少了,换种说法,就是极短时间内产生了大量的redo log。
接下来会有几个变量,图解也不难,仔细看看。
InnoDB存储引擎,通过LSN(Log Sequence Number)来标记版本,LSN是8字节的数字。每个页有LSN,重做日志有LSN,checkpoint有LSN。
写入日志的LSN:redo_lsn
刷新回磁盘的最新页LSN:checkpoint_lsn
有如下定义:
checkpoint_age = redo_lsn - checkpoint_lsn
async_water_mark = 75% * total_redo_file_size
sync_water_mark = 90% * total_redo_file_size
刷新过程如下图所示:

④Dirty Page too much Checkpoint
即脏页太多,强制checkpoint.保证缓冲池有足够可用的页。
参数设置:innodb_max_dirty_pages_pct = 75 表示:当缓冲池中脏页的数量占75%时,强制checkpoint。1.0.x之后默认75

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_72610956/article/details/134121953

智能推荐

hdu 1229 还是A+B(水)-程序员宅基地

文章浏览阅读122次。还是A+BTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24568Accepted Submission(s): 11729Problem Description读入两个小于10000的正整数A和B,计算A+B。...

http客户端Feign——日志配置_feign 日志设置-程序员宅基地

文章浏览阅读419次。HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。NONE:不记录任何日志信息,这是默认值。配置Feign日志有两种方式;方式二:java代码实现。注解中声明则代表某服务。方式一:配置文件方式。_feign 日志设置

[转载]将容器管理的持久性 Bean 用于面向服务的体系结构-程序员宅基地

文章浏览阅读155次。将容器管理的持久性 Bean 用于面向服务的体系结构本文将介绍如何使用 IBM WebSphere Process Server 对容器管理的持久性 (CMP) Bean的连接和持久性逻辑加以控制,使其可以存储在非关系数据库..._javax.ejb.objectnotfoundexception: no such entity!

基础java练习题(递归)_java 递归例题-程序员宅基地

文章浏览阅读1.5k次。基础java练习题一、递归实现跳台阶从第一级跳到第n级,有多少种跳法一次可跳一级,也可跳两级。还能跳三级import java.math.BigDecimal;import java.util.Scanner;public class Main{ public static void main(String[]args){ Scanner reader=new Scanner(System.in); while(reader.hasNext()){ _java 递归例题

面向对象程序设计(荣誉)实验一 String_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏6次。目录1.串应用- 计算一个串的最长的真前后缀题目描述输入输出样例输入样例输出题解2.字符串替换(string)题目描述输入输出样例输入样例输出题解3.可重叠子串 (Ver. I)题目描述输入输出样例输入样例输出题解4.字符串操作(string)题目描述输入输出样例输入样例输出题解1.串应用- 计算一个串的最长的真前后缀题目描述给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。

算法设计与问题求解/西安交通大学本科课程MOOC/C_算法设计与问题求解西安交通大学-程序员宅基地

文章浏览阅读68次。西安交通大学/算法设计与问题求解/树与二叉树/MOOC_算法设计与问题求解西安交通大学

随便推点

[Vue warn]: Computed property “totalPrice“ was assigned to but it has no setter._computed property "totalprice" was assigned to but-程序员宅基地

文章浏览阅读1.6k次。问题:在Vue项目中出现如下错误提示:[Vue warn]: Computed property "totalPrice" was assigned to but it has no setter. (found in <Anonymous>)代码:<input v-model="totalPrice"/>原因:v-model命令,因Vue 的双向数据绑定原理 , 会自动操作 totalPrice, 对其进行set 操作而 totalPrice 作为计..._computed property "totalprice" was assigned to but it has no setter.

basic1003-我要通过!13行搞定:也许是全网最奇葩解法_basic 1003 case 1-程序员宅基地

文章浏览阅读60次。十分暴力而简洁的解决方式:读取P和T的位置并自动生成唯一正确答案,将题给测点与之对比,不一样就给我爬!_basic 1003 case 1

服务器浏览war文件,详解将Web项目War包部署到Tomcat服务器基本步骤-程序员宅基地

文章浏览阅读422次。原标题:详解将Web项目War包部署到Tomcat服务器基本步骤详解将Web项目War包部署到Tomcat服务器基本步骤1 War包War包一般是在进行Web开发时,通常是一个网站Project下的所有源码的集合,里面包含前台HTML/CSS/JS的代码,也包含Java的代码。当开发人员在自己的开发机器上调试所有代码并通过后,为了交给测试人员测试和未来进行产品发布,都需要将开发人员的源码打包成Wa..._/opt/bosssoft/war/medical-web.war/web-inf/web.xml of module medical-web.war.

python组成三位无重复数字_python组合无重复三位数的实例-程序员宅基地

文章浏览阅读3k次,点赞3次,收藏13次。# -*- coding: utf-8 -*-# 简述:这里有四个数字,分别是:1、2、3、4#提问:能组成多少个互不相同且无重复数字的三位数?各是多少?def f(n):list=[]count=0for i in range(1,n+1):for j in range(1, n+1):for k in range(1, n+1):if i!=j and j!=k and i!=k:list.a..._python求从0到9任意组合成三位数数字不能重复并输出

ElementUl中的el-table怎样吧0和1改变为男和女_elementui table 性别-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏2次。<el-table-column prop="studentSex" label="性别" :formatter="sex"></el-table-column>然后就在vue的methods中写方法就OK了methods: { sex(row,index){ if(row.studentSex == 1){ return '男'; }else{ return '女'; }..._elementui table 性别

java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下-程序员宅基地

文章浏览阅读1.1k次。java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下

推荐文章

热门文章

相关标签