Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

发布时间:2022-06-26 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Mysql整体介绍(适用于5.X版本)(下)(标贝科技)脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

MySQL整体介绍(适用于5.X版本)(下)(标贝科技

二、InnoDB介绍[9-11]

InnoDB是MySQL取得成功的最关键的引擎,其重要性不言而喻,下面将单独对该引擎的核心特性进行介绍,其他引擎如MyISam、MEMORY、NDB等,本文不作说明。 本文主要从宏观角度整体性地对InnoDB进行介绍,索引、事务、锁等具体的知识点在后文章单独介绍。

2.1 InnoDB体系架构和关键技

在MySQL 5.1中,可以支持两个版本的InnoDB,一个是静态编译的InnoDB版本,可将其视为老版本的InnoDB;另一个是动态加载的InnoDB版本,官方称为InnoDB Plugin,可将其视为InnoDB 1.0.x版本。MySQL 5.5版本中又将InnoDB的版本升级到了1.1.x,InnoDB Plugin成为历史。在MySQL 5.6版本中,InnoDB的版本又升级为1.2.x,这也是本文即将展开介绍的版本。表2显示了各个版本中InnoDB存储引擎的功能。

Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

2.1.1 InnoDB体系架构 (5.7版本)

本文第一部分对Mysql数据库整体的体系架构进行了介绍,这里将继续深入介绍InnoDB内部的架构设计,如图8所示。

Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

图8 InnoDB引擎官方架构设计图[11] InnoDB内部主要包括内存架构和硬盘存储架构两部分,打通这两部分的工作主要由后台线程来完成。下面分别对三者进行介绍,同时对Checkpoint机制进行简单说明。

2.1.2 内存架构

InnoDB的内存架构主要包括4个概念:缓存池 (Buffer Pool)、更新缓冲 (Change Buffer)、自适应哈希 (Adaptive Hash Index)、日志缓冲 (LOG Buffer)。

2.1.2.1 缓存池(Buffer Pool)

缓存池是主内存中的一块区域,在专用的MySQL服务器上,通常会将最多80%的物理内存分配给它。缓存池允许直接从内存中处理经常使用的数据,从而加快处理速度。 Mysql缓存池存储的内容主要有:索引页、数据页、undo页、Change Buffer、自适应哈希索引、InnoDB存储的锁信息 (lock info)、数据字典信息 (data dictionary) 等,其中最主要的内容是索引页和数据页。

Mysql缓存池方面的设计思想主要体现在三个方面:1). 在为了提高大容量的读操作的效率,Mysql将缓冲池划分为可以容纳多行的数据页;2). 为了提高缓存管理的效率,将缓冲池实现为数据页的链表;3). 很少访问的数据使用经过变体的LRU算法从缓存中淘汰。下面介绍一下缓存池的LRU算法实现细节,参考图9。

Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

图9 Buffer Pool数据页链表的官方示意图[11] 当需要新的空间将数据页添加到缓冲池时,最近最少使用的数据页将被移除,并将新数据页添加到数据页链表的“中点” (注意,并不是指正中心位置)。 这个“中间插入策略”将列表视为两个子列表:靠近表头的一部分为young区,这里的数据页是最近访问过的;靠近表尾的一部分为old区,这里的数据页是最近较少使用的。默认情况下,算法按照下面的规则运行: 1). 链表的3/8被设置为old区; 2). “中点”并不是指不是链表的中间点,而是young区的表尾节点和old区的表头节点中间的位置; 3). 当读取的数据不在缓冲池里的时候,读取到的数据页需要插入到链表中,插入点为“中点” 。但是插入的新节点被看作old区的节点,如果此时old区满了,则移除链表尾部的数据页; 4). 当读取old区的数据页时,该节点将变成young节点:此节点移动到young区的表头位置 5). 这样一来,随着数据库不断操作,在young区中的未被访问的节点将逐渐往表尾移动,当移动过“中点” ,则变为old区的节点。old区中未被访问的节点也会随着往表尾移动,当链表满时,表尾那个数据页会被淘汰。 2.1.2.2 更新缓冲区(Change Buffer)

Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

图10 Change Buffer工作原理示意图[11] 在内存架构里,更改缓冲区本质是一块内存空间,同时以一种特殊的数据结构组织,只用来存储辅助索引页 (也就是说,不会作用于主键索引、全文索引、空间索引)。其基本的工作原理是:1). 当辅助索引页不在缓存池 (Buffer Pool) 中时,会先将对辅助索引页的更改保存至到Change Buffer内,如果已经在缓存池内,当然是直接更新缓存池内的数据页;2). 对Change Buffer数据页的修改操作(INSERT、UPDATE或DELETE)合并更新至缓存池里对应的数据页的时机是:有其他读操作将数据页加载到缓冲池时,如图10所示。 为什么需要更新缓冲区呢?因为与聚集索引不同,辅助索引通常是非惟一的,并且插入辅助索引的顺序相对随机,同时,删除和更新也可能影响索引树中实际并不相邻的辅助索引页,直白的说,会引起随机I/O访问。引入更新缓冲区可以大大减少随机I/O的次数,从而提高效率。 需要特别注意的是,更新缓冲区同时存在于内存架构里面的缓存池内和硬盘存储架构里面的系统表空间内。在硬盘存储架构里,更新缓冲区主要用于在服务器关闭时,缓存对辅助索引页的更新。 更新缓冲区是一个非常重要的概念,如果还有疑问,可以阅读官方FAQ[12]。 2.1.2.3 自适应哈希(Adaptive Hash Index, AHI) 哈希(hash)是一种非常快的查找方法,在一般情况下这种查找的@R_791_1304@为O(1),即一般仅需要一次查找就能定位数据。而B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般为3~4层,故需要3~4次的查询。 InnoDB存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引。它是通过缓冲池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引。 InnoDB存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引,这个过程完全是引擎自主控制的,没有提供参数让用户进行配置。 2.1.2.4 日志缓冲(Log Buffer) 日志缓冲区用于在内存中暂存要写入磁盘日志文件的数据,日志缓冲区的内容会定期刷新到磁盘。日志缓冲区大小由innodb_log_buffer_size变量定义,默认大小为16MB。在日志缓冲区空间比较大的情况下,允许运行大型事务时,可以不需要在事务提交之前将重做日志 (redo log) 数据写入磁盘。因此,如果有更新、插入或删除许多行的事务,那么增加日志缓冲区的大小可以节省磁盘I/O。

2.1.3 硬盘存储架构

在Mysql 5.7版本中,硬盘存储架构包括5个表空间和重做日志文件 (redo log) 。5个表空间分别是:系统表空间 (The System Tablespace)、独立表空间 (File-PEr-table Tablespaces)、通用表空间 (General Tablespaces)、Undo表空间、临时表空间 (The Temporary Tablespace)。 重做日志:在服务端正常运行期间,对SQL语句或低级API调用产生的更改表数据的请求进行编码,并写入磁盘中的重做日志,并用于在崩溃恢复期间纠正不完整事务写入的数据。 系统表空间中包含4个部分:InnoDB数据目录 (the InnoDB data dictionary)、两次写缓存 (the doublewrITe buffer)、更新缓存区(the change buffer)和回滚日志 (undo logs)。默认情况下,系统表空间的数据文件名为ibdata1,不过InnoDB提供了配置的方式来设置数据文件的位置、大小甚至文件的个数。 独立表空间用来存储一张单独的逻辑表的数据和索引,所有数据存储于一个单独的磁盘文件中,文件名的后缀是.ibd。 通用表空间可以存储多张逻辑表的数据和索引。创建通用表空间后,有两种方式把表保存于通用表空间: 1). 创建的方式:CREATE TABLE t1 (c1 INT Primary KEY) TABLESPACE ts1; 2). 更新的方式:ALTER TABLE t2 TABLESPACE ts1; Undo表空间用来存储回滚日志。其实回滚日志默认是存储于系统表空间的,但它也可以存储于一个或多个Undo表空间。Undo表空间存在的优势是:1). 减少系统表空间中存储回滚日志所需的空间;2). Undo表空间如果单独采取SSD存储,也与回滚日志的I/O模式相匹配,Undo表空间的存在使整体的灵活性更高。 临时表空间也是一个共享的表空间,用于存储所有非压缩的由用户创建的临时表和内部的查询临时表,压缩的临时表则存储于独立表空间中。

2.1.4 后台线程(InnoDB 1.2.x)

Mysql后台线程包括4种:Master Thread、IO Thread、purge Thread、Page Cleaner Thread。 2.1.4.1 Master Thread 不同版本InnoDB的Master Thread并不相同,本文仅介绍1.2.x版本的工作内容和原理。 Master Thread的伪代码如下:

if InnoDB is idle
srv_master_do_idle_tasks();
else
srv_master_do_active_tasks();
srv_master_do_idle_tasks()

即之前版本中每10秒执行的操作:

  1. 刷新100个脏页到磁盘 (可能);
  2. 并同步更新缓冲区的数据至缓存池 (总是);
  3. 将日志缓冲刷新到磁盘 (总是);
  4. 删除无用的Undo页 (总是)。

srv_master_do_active_tasks()即之前版本中每秒执行的操作:

  1. 日志缓冲刷新到磁盘,即使这个事务还没有提交 (总是);
  2. 合并同步更新缓冲区数据至缓存池 (可能);
  3. 如果当前没有用户活动,则切换到background loop(可能)。

扩展:InnoDB 1.2.x之前的版本中,master thread还负责刷新脏页的操作,从1.2.x版本开始,Mysql将这一工作分离给单独的Page Cleaner Thread,减轻master thread工作,提高系统并发性。 2.1.4.2 IO Thread 在InnoDB存储引擎中大量使用了aiO (Async IO) 来处理写IO请求,这样可以极大提高数据库的性能。而IO Thread的工作主要是负责这些IO请求的回调 (call back) 处理。 2.1.4.3 Purge Thread 事务被提交后,其所使用的Undo log可能不再需要,由PurgeThread来承担回收已经使用并分配的Undo页的工作。 从InnoDB 1.2.x版本开始,InnoDB支持多个Purge Thread,加快了Undo页的回收。同时由于Purge Thread需要离散地读取Undo页,采用多个Purge Thread也能更进一步利用磁盘的随机读取性能。 2.1.4.4 Page Cleaner Thread Page Cleaner Thread的作用是:将之前版本中由master thread执行的脏页的刷新操作都放入到单独的线程中来完成,提高性能。

2.1.5 Checkpoint机制

Checkpoint机制用于脏页的刷新,该机制InnoDB存储引擎通过LSN (Log Sequence Number) 标志redo log来实现,InnoDB存储引擎通过LSN (Log Sequence Number) 来标记版本的。每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘;当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。 该机制原理简单,但在InnoDB存储引擎中,Checkpoint发生的时间、条件及脏页的选择等都非常复杂。而Checkpoint所做的事情无外乎是将缓冲池中的脏页刷回到磁盘。不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint。发挥的作用非常大,解决了内存容量瓶颈,并大大缩短了数据库的平均故障恢复时间。 InnoDB会在四种情况下会触发Checkpoint机制:master thead的定时刷新、LRU列表中没有足够的空闲页时 (脏页太多时)、redo log不可用时 (async/sync flush checkpoint)、数据库关闭时。 Checkpoint有两种工作模式:刷新所有脏页 (Sharp Checkpoint) 和刷新部分脏页 (Fuzzy Checkpoint)。一般情况下使用刷新部分脏页模式,只有数据库关闭且设置了innodb_fast_shutdown=1时,才会刷新所有脏页回磁盘的模式。

2.2 InnoDB其他特性

上面介绍了InnoDB的更新缓冲 (Change Buffer)、自适应哈希 (Adaptive Hash Index) 等特性的原理和作用,除此之外,还有一些重要的特性可以关注。

2.2.1 两次写(Double Write)

插入缓冲可以带来性能上的提升,两次写特性则可以提高InnoDB引擎数据页的可靠性。

当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16KB的页,只写了前4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。 如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如偏移量800,写’aaaa’记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite的,其体系架构设计如图11所示。

Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

图11 doublewrite架构[9] doublewrite由两部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区 (extent),大小同样为2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。 在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite buffer中的页写入各个表空间文件中,此时的写入则是离散的 开启doublewrite功能后,如果操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到该页的一个副本,将其复制到表空间文件,再应用重做日志。

2.2.2 异步IO(Async IO)

如果使用同步IO,用户发出一条索引扫描的查询,这条SQL查询语句可能需要扫描多个索引页,也就是需要进行多次的IO操作。每进行一次IO操作,需要等待此次操作结束才能继续接下来的操作,效率会非常低。 如果Mysql采用AIO模式,则在发出一个IO请求后,会立即发出另一个IO请求,当全部IO请求发送完毕后,等待所有IO操作的完成即可,效率能得到很大的提高。此外,使用AIO模式,还可以进行IO Merge操作,也就是将多个IO操作合并为1个IO操作,这样可以提高IOPS的性能。 在InnoDB1.1.x之前,AIO的实现通过InnoDB存储引擎中的代码来模拟实现。而从InnoDB 1.1.x开始(InnoDB Plugin不支持),提供了内核级别AIO的支持,称为Native AIO。官方的测试显示,启用Native AIO,恢复速度可以提高75%。

2.2.3 刷新邻接页(Flush Neighbor Page)

刷新邻接页的工作原理为:当刷新一个脏页时,InnoDB存储引擎会检测该页所在区(extent)的所有页,如果是脏页,那么一起进行刷新。这样做的好处显而易见,通过AIO可以将多个IO写入操作合并为一个IO操作,故该工作机制在传统机械磁盘下有着显著的优势。 但是需要考虑到下面两个问题:1). 是不是可能将不怎么脏的页进行了写入,而该页之后又会很快变成脏页;2). 固态硬盘有着较高的IOPS,是否还需要这个特性。 因此,InnoDB存储引擎从1.2.x版本开始提供了参数innodb_flush_neighbors,用来控制是否启用该特性。对于传统机械硬盘建议启用该特性,而对于固态硬盘有着超高IOPS性能的磁盘,则建议将该参数设置为0,即关闭此特性。

三、总结

本文分为两大部分,第一部分主要着眼于Mysql的体系结构、通信协议和工作流程;第二部分重点介绍Mysql最重要的存储引擎InnoDB, 对其核心特性进行概要性的解析。 需要注意的是,Mysql8.X相对于Mysql5.X,有非常多的改动,新增了非常多功能和属性,同时也修改或删除了许多功能特性,具体可以参考官方文档对应版本的release文档。在此,强烈建议如果要从Mysql5.X切换至Mysql8.X,一定要提前了解改动的详细信息,避免踩坑。 参考文献 [1]https://dev.mysql.COM/doc/dev/mysql-server/latest/PAGE_PROTOCOL.htML [2]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_packets.html#sect_protocol_basic_packets_packet [3]https://www.jianshu.com/p/5e6b33d8945f [4]https://cloud.tencent.com/developer/article/1768901 [5]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods.html [6]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase.html [7]https://dev.mysql.com/doc/internals/en/ [8]https://www.cnblogs.com/wyq178/p/11576065.html [9]Mysql技术内幕:InnoDB存储引擎 (第2版). 姜承尧 [10]MySQL运维内参:MySQL、Galera、Inception核心原理与最佳实践. 周彦伟,王竹峰,强昌金 [11]https://dev.mysql.com/doc/refman/5.7/en/innodb-Architecture.html [12]https://dev.mysql.com/doc/refman/5.7/en/faqs-innodb-change-buffer.html

脚本宝典总结

以上是脚本宝典为你收集整理的Mysql整体介绍(适用于5.X版本)(下)(标贝科技)全部内容,希望文章能够帮你解决Mysql整体介绍(适用于5.X版本)(下)(标贝科技)所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。