mysql指引(九):理清innodb表空间的逻辑

上文 最后的innodb体系结构中我们重点指明了表空间,本篇就来看看tablespace表空间。

表空间只是逻辑概念,学习它的重点在于将逻辑理清楚。


前面的文章中提到过文件 这个虚拟概念,我们程序开发时对文件进行操作,但是根本不用关心文件在磁盘上是如何存储的。也即文件屏蔽了底层存储的细节,这当然是操作系统的功劳。

而前文也提到过,每个表的索引和数据都存放在 .ibd 文件中,既然是文件,则同样会被操作系统管理。而这个 ibd 文件在innodb看来,就可以叫做是表空间,因为在innodb应用程序的内部来看,是没有 文件 这个概念的,我的地盘我做主嘛,所以当这个文件加载到innodb进程中时,就被看做是打开(进入)了一个表空间

那么,innodb是如何找到这个表空间的入口,通过月光宝盒吗?当然是通过mysql.cnf 配置文件中配置的 data数据库目录地址找到的。姑且不论他是什么时机打开或者其他xxx,反正现在表空间这个潘多拉魔盒已经打开了,那么我们就进一步地去探索。


因为众所周知的原因,操作系统中文件是由一个个磁盘上的页组成,当然这里的文件和页都是虚拟概念,只有磁盘是物理存在的。换句话说,ibd 文件被操作系统切割成了一个个的页,存储在磁盘上。(innodb心都在滴血,表空间都被切割烂了。这样看,操作系统就是空间系的圣魔导师,哈哈哈)。

现在有个矛盾必须解决,矛盾的双发就是mysql 和 操作系统,矛盾的对象就是这个文件(表空间),矛盾如下:

  • 对于操作系统来说,明明我管理文件和磁盘等等弄的挺好,我的文件系统这么强大。但是你innodb就是不听,非要越过我去直接管理,再造一个文件系统,这可能吗?
  • 对于innodb来说,我追求的是保证可靠可用的情况下,极致地提升性能。怎么提升?你把我的表空间切得粉碎…此处省略1万字。

矛盾是真的不小,可是拥有上帝视角的开发大牛多么聪明啊。既然不能直接改变你操作系统的管理方式,那我就在你的基础上再造一个就好了呗。造一个什么呢?对,就造一个针对这些被操作系统切碎的页面的空间管理系统。

这个空间管理系统当然分成两块:表空间(仅仅是一个对象)和围绕表空间的一系列执行方法。这样,就可以实现一个建立在操作系统里的文件系统之上的文件系统


现在,对于表空间来说,我们已经十分清楚它的目的了,即:

管理表空间对应的无数页面

那么,第一步,自然要去操作系统化,将操作系统中的页替换掉,变成表空间中的页。也就是文件在操作系统上是页1、页2,到了表空间这边就变成了 页a、页b。虽然都称之为页,但是此页非彼页。下面所说的 都是表空间的这个页。

当然了,这两个不同概念的页怎么映射的,我们就不多管闲事了。

这样子,整个表空间的基石,就完完全全是自主研发可控的了。所以我们可以随便修改 innodb 的页大小,而不用管操作系统。


可是,成千上万的页全部在一个表空间中,我们该怎么管理呢?(表空间中的页就是前文我们讲到的数据页之类的)

万事万物都是有联系的,你可以考虑下,假如是你,你会提出什么建议呢?


随便举几个例子,比如军队中,难道就一个司令去管理几百万的士兵吗?

再比如,学校里,为啥分班啊,直接全部一起就好了呗?

再比如,商场里,这么多商品随便放着就好了呗,为啥还要什么生鲜区、日用品区呢?

还有很多很多例子。发现了吗,解决的办法是什么?

,也就是分区,分层次。

自然,innodb的表空间中同样引入了区 extent 概念。每个区包含64个页面,每256个区为划分为一组。这样,当页大小为16K时,每个区就为1M。每组中的第一个区中的前几页,自然就负责记录该组中关于各个区的一些关键信息。

这样,对于页面的管理就具有了层次,不会混乱。但是这样就好了吗?那肯定不是的,上文说 innodb 要极致的提升性能,光这样规定下层次有什么用呢。


所以innodb又做了如下几个处理:

  1. 每个区中页面在磁盘上都是连续的。连续意味着一定场景下减少磁盘的随机I/O。

但是连续性如何保证?这就依靠操作系统的管理。innodb可以一次申请这么多页面大小的空间,那自然就是连续的。

  1. 由于每棵 B+ 树只有叶子节点页面中存储着数据,而非叶子节点的目的就是为了找到对应的叶子节点。如果这两种类型的页面放在一起,比如是AAAABBAABBAAAA的页面排列形式,则同样不利于查找。

针对这点,innodb又引出了一个 的概念。每建立一个索引(即一棵B+树),都会在表空间中生成两个段:索引段和数据段。并且规定,段是以区为单位进行分配,即一个段可以包括好几个区。所以的出现主要是解决这个性能的。

  1. 衡量一个算法的性能是从两个方面:时间和空间。对应innodb同样是,因为他也可以看做是一个大的算法。所以对于空间上的优化,innodb还引入了一种,就是 碎片区 。有什么好处呢?

在第2点中讲到了段,每个段下面的区,这些区里面的页面都是这个段对应索引的叶子节点或者非叶子节点。不会和其他索引的段下区混在一起。但是碎片区就允许,不论是哪个段的页面,都可以存放在碎片区中。

这样,一个大致的流程就是:建立好表空间,此时出现了两个段(主键索引),插入一条数据。那么数据会存储到数据页中,而此数据页就是从碎片区拿过来的。继续插入数据,这个段已经在碎片区中占了32个页后,就会申请完整的区继续存储。

如果没有碎片区的话,那么初始插入一条数据就会直接申请一个区的空间(每个段一个),则直接占用2M空间,有些表根本用不了这么多空间。


整理下就是,表空间下具有很多区,其中一些区组成了一个个的段。同时,每256个区又为一组,组内的相关信息都放在第一个区中。每个区下面有64个连续的页。

实际上,一个区既在某个组内,同时又可能在某个段中。

这种层次一划分,很好地提升了性能。但是还引出了其他的性能问题,那就是这些区如何快速寻找?

比如一个表空间大小10G,则区就有1万个。这些区中有的区已经满了,有的区还有空间。则新插入数据时,如何找到合适的区插入,难道一个个遍历过去吗?

当然不是,看页结构时,里面就有各种链表。实际上表空间中也是由各种链表将区维护起来,比如碎片区链表或者满空间区链表等。

针对每个区而言,都处于四种状态之一:

  • 空闲
  • 有空间的碎片区
  • 占满的碎片区
  • 属于某段的区

表空间中的链表有两个角度,一个是站在整个表空间层面看,有三条链表串联起来所有的区,即:

  • 空闲区链表
  • 有空间的碎片区链表
  • 占满的碎片区链表

可以明显地看到,三条链表中的区没有第四种状态,所以另一个角度是站在某一个段的层面去看,也有三条链表,即:

  • 空闲且属于这个段的区链表
  • 有空间的且属于这个段的区链表
  • 占满的且属于这个段的区链表

所以,一个区会在不同层面被分到不同的链表中。


对应的,每个区的属性结构(结构体、对象描述)又叫做:XDES Entry ,每个段的属性结构叫做 Inode Entry 。而上面的6条链表,其节点都是 XDES Entry。

上面提到的链表,必须有能够找到链表头节点的节点,所以在 Inode Entry 中保存了它的三条链表的 base节点。

对于整个表空间来说,表空间独有的信息当然是存储在第一个区中的,也就是 extent0 区中。同时,extent0 区也是表空间第一个组的第一个区,所以也要记录组独有的信息。其他组中的第一个区,就不需要记录表空间的独有信息了。

对于上面站在表空间层面的三条链表,他们的base节点就存储在extent0中。当然具体是存储在extent0中的某个页面上了(第一个页)。

XDES Entry 有专门的页来存储,页类型即为 XDES,我们前面已经看过页类型为 数据页 的。不同类型的页结构当然是类似的。所以同样会有页之间的链表存在。

Inode Entry 的页类型为 Inode,同样 Inode 页之间会有链表存在。


那么对于系统表空间 System tablespace 来说呢?是不是还和普通表空间一样呢?

当然是,结构当然是一样的。只不过系统表空间的一些区被用来做更特殊的用途,同时存储全局的(所有表空间共享的)一些信息。

其中一些信息关键字,我们已经在innodb的基本结构中见过了,即:数据字典、双写缓冲、Change Buffer、Undo Logs等。


关于表空间就到这里,我们不再像页结构那样,去看比如 XDES Entry 中有哪些属性等等。因为表空间整体下来,各种属性太多了,没必要看也没必要记。只要把逻辑理顺,知道表空间中的各种重要元素就行了。后续学习其他锁、事务的时候,还是会遇到一些属性的,到时候说到表空间只要有宏观映像就行了。


双写缓冲、change buffer什么的我们先放放,再其他研究中顺带看看。下一篇,进入事务这个重要的专题。

最后,本篇没有画图,两个原因:主要讲逻辑,图没多大用;属性太多,画图和表格表示也不行,意义不大。想看图的网上随便搜都有的,还能顺便加深印象。

更多见:后端开发教程系列-java向

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oatlmy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值