网易视频云:InnoDB透明页压缩与稀疏文件

MySQL 5.7中包括了很多让人耳目一新的新特性,其中就包括了InnoDB Transparent Page Compression,姑且称之为InnoDB透明页压缩。其实透明页压缩这个东西,早就关注过,其用到了sparse file和hole punching技术,但一直没能将这两种技术跟InnoDB压缩联系起来。最近花了点时间了解了下。

熟悉InnoDB的同学都知道,InnoDB从MySQL 5.1版本开始就支持压缩,提供zlib压缩算法,是记录压缩(record compress),曾大概看过InnoDB这部分相关的源码,逻辑比较复杂,如果对InnoDB page的组织结构不了解,相信很难看出个所以然,该压缩是页感知的(page aware),即需要知道页里面记录是怎么保存的。与之相反,MySQL 5.7最新支持的压缩是页透明的(page transparent),当然,页首尾的元数据是不压缩的,不关心这个页里面保存的是什么内容,可以理解为页/块压缩(page/block compress,本文将块和页混用)。

假设有个16KB的InnoDB页P1,通过块压缩为11KB,如果表空间使用的文件系统在mkfs时指定block size为4KB,那么只需要使用3个文件块来保存11KB的数据,节省1个文件块即4KB的空间。那么是不是说InnoDB下个页P2的数据直接从所节省的这4KB开始写入吗,答案是否定的。

网易视频云:InnoDB透明页压缩与稀疏文件_第1张图片

InnoDB透明页压缩不会改变表文件的结构,我们可以理解为每页都占据了文件中4个块的大小,页压缩后的最终大小不会影响每个页在表文件中的起始偏移位置。即第k个页的数据,还是从表文件第4*k个块开始写入。问题来了,为什么不呢,因为压缩页经过修改后,再次压缩后的大小是不可知的,可能本来压缩后的大小为11KB,再次压缩就变成15KB了,那么仍需要4K文件块来保存,如果文件第4*n+3个块已经被写入了P2的数据,P1再次压缩后多出来4K数据就没地方放了。

从上段描述来看,不管P1被压缩成什么熊样,P2仍然需要从表文件的第4*n+4个偏移块开始写入数据,这种压缩并没有改变文件逻辑大小。虽然压缩后,IO是小了,但4KB的IO相比16KB的IO并不能带来多大的性能提升。然并卵!

怎样才能节省被压缩后释放的空间呢,这就需要用到文件系统/操作系统内核层面的技术 - sparse file,简单来说,sparse file是这样的文件, file 1大小是12KB,但是其实只占用首尾2个文件块共8KB的磁盘空间,中间4KB由于没有真实数据,并未分配磁盘空间,或者本来已经分配了,但又被回收了,像是中间被挖了个洞(punch hole)。这被挖的4KB,可以被文件系统用来分配给其他文件保存数据。如果中间4KB的数据被用户填上了呢,没事,文件系统分配一个新的空闲快给file 1即可。关于sparse file更详细的介绍参见参考文献。当然这可能会导致数据库IO不连续。

通过上面的描述,相信很容易就能够将sparse file技术应用到InnoDB透明页压缩上。不再赘述,只放一张图。

网易视频云:InnoDB透明页压缩与稀疏文件_第2张图片

为什么InnoDB要另辟蹊径,采用新的压缩方案,不再原来的压缩实现上进行优化呢,可能有以下两点原因:

首先,原有的记录级压缩,代码实现复杂的,需要基于不同的页类型采用不同的处理方式,需要熟悉InnoDB的索引和页结构,代码封装性较差,添加新的压缩算法或进行性能优化提升较费劲,所以一直仅支持zlib。在这个基础上进行优化提高较困难。这个观点得到MySQL官方的验证,详见参考文献中的官方描述。

其次,相对于原来的记录级压缩,新方案更加灵活,因为压缩算法是保持在InnoDB页的元数据中,理论上可以做到同个表中不同页采用了不同的压缩算法,比如根据不同页类型来决定是否压缩,采用某种压缩算法(当然目前MySQL官方还没这么做)。现实中,也会存在同个表包括多种压缩算法的场景,因为用户可以动态修改压缩算法(也可以启动和关闭压缩),而动态修改并不是说把已经压缩的页马上使用新的压缩算法重新压一次,而是对新产生或更新的页起作用,这就会导致有些页是不压缩的,有些页是采用zlib,有些采用lz4。吐槽下,为什么InnoDB还不支持snappy或quicklz呢。

你可能感兴趣的:(技术推文)