* 时间紧迫时,可通过频繁删除文件来腾挪空间来临时解决
* 预算充足时,可更换更大容量的存储设备,做数据全量迁移
* 预算、时间充足时,可添加更多服务器做数据拆分
* 时间紧迫时,可以通过杀死存储吞吐量消耗最大的进程来临时解决
* 预算充足时,更换更高吞吐带宽的存储设备,做数据全量迁移
* 预算、时间充足时,可添加更多服务器做数据拆分
* 对大表做数据拆分,先做垂直拆分(按业务拆分,将不同业务的字段拆分到不同的表、或不同的数据库、甚至不同的实例中),然后做水平拆分(对于无法继续拆分字段的表,如果数据量仍然大到影响性能,则可能还需要以不超过1000W行数据量的标准继续对大表执行拆分,即就是我们常说的数据分片)
* InnoDB 数据文件默认的Page Size为16k,文件系统默认的块大小为4k,也就是说,InnoDB数据文件的最小IO操作单位是16k,文件系统最小IO操作单位是4k,当InnoDB数据文件写入一个16k的页到文件系统时,文件系统需要将其分解成4个4k大小的块,再写入到存储设备中。由于大部分的文件系统并不支持原子写,如果文件系统在写入存储设备期间,发生了意外(例如掉电),则可能导致InnoDB的Page Size发生部分写(损坏),进而导致MySQL Server无法正常启动
* 为了避免这个问题,InnoDB引入了doublewrite特性,doublewrite用来做什么的呢?当有数据需要写入数据文件时(即刷脏),先写入doublewrite(MySQL 8.0.20版本之前,doublewrite位于共享表空间ibdata1中,8.0.20版本开始,使用独立的文件存储,且支持多个文件,但文件的最大数量是buffer pool instance的2倍,即每个buffer pool instance有2个doublewrite文件),每次1MB连续写入,数据页写入doublewrite成功之后,再将数据页写入到数据文件中,这样一来,如果发生意外导致数据页发生损坏,则在数据库执行Crash Recovery期间,会尝试从doublewrite中找到发生损坏的页进行覆盖修复,修复之后即可正常启动MySQL Server(注:Redo虽然能够支持数据恢复,但它记录的是数据页的增量修改内容,并不是记录的完整的数据页,但doublewrite中的数据页是完整的,所以,可以使用doublewrite中的完整数据页恢复损坏的数据页,然后就能够正常应用Redo)
* doublewrite分成2个部分,内存中有2M的doublewrite buffer,磁盘文件中也有2个1M的连续doublewrite空间,引入doublewrite之后的数据写入简单示意图如下,从图中我们可以看到,脏数据要成功写入到数据文件中,需要写2次磁盘(一次写入到doublewrite中,一次写入到数据文件中)
* 既然存储支持硬件级别的原子写,那么,也就是说,数据库层面的doublewrite特性就可以关掉了,关掉之后,脏数据写入到数据文件只需要一次写磁盘即可,从而节省了一半的刷脏流量。即,在能保证数据页不发生部分写的情况下,直接就能缓解存储吞吐能力不足的燃眉之急!
* 简单来说,就是在数据量达到一定程度之后,大幅度节省存储成本,降低存储的TCO
* 软压缩/解压(即CPU压缩):如下图所示,依赖主机CPU执行压缩与解压运算,存在大量数据复制且复制链路长,且压缩与解压运算逻辑需要应用程序自行实现与控制
* 硬件压缩/解压(压缩卡):如下图所示,依赖占用PCI插槽的专用压缩卡执行压缩与解压运算,虽然释放了主机CPU资源,但仍然需要在主机内存与压缩卡之间大量拷贝数据,占用大量的主机带宽资源
* 透明压缩/解压:如下图所示,压缩/解压的运算工作,直接由存储卡上集成的计算单元执行,对应用完全透明,数据的压缩与解压完全是在盘内执行,释放主机CPU资源的同时,也释放了主机带宽资源,也不需要在主机内存与压缩卡之间大量拷贝数据(零拷贝),而且,扩展存储卡时可同时扩展压缩/解压的计算单元,能够同时实现并行的压缩/解压运算
* 在对应用透明、不占用主机任何资源的前提下,大幅度降低存储成本
* 在存储卡的存储单元中,存放的数据是经过压缩的,因此,大幅度减少存储数据量,对于固态存储元器件来讲,就意味着可以大幅度降低写放大,而写放大的降低能够让固态存储元器件最大化地发挥性能优势,降低IO响应延迟。因此,对于数据库来说,在实现了数据压缩的情况下,能够不影响性能,甚至性能还能有一定提高(尤其是MySQL数据库,在数据量达到一定大小之后,随着压缩比的提升,使用计算存储的透明压缩 + 关闭doublewrite,在某些场景下性能甚至有大幅度的提高)
* 因为压缩功能使得binlog占用物理空间减少,从而也降低因为存储空间不足,清理binlog的频率,同时,由于压缩/解压功能是在盘内进行(写入数据时先由盘内的计算算元进行压缩,然后再存入存储单元;读取时先从存储单元中读取,然后再由盘内的计算单元进行解压),也进一步降低了对存储设备的吞吐带宽的占用
* InnoDB的Buffer Pool主要是用于减少IO操作的,读写IO响应延迟的降低,意味着对主机内存的依赖也就随之减少,也就是说,InnoDB的Buffer Pool可以设置得更小,也就是说,可以进一步释放主机的内存资源,将其更多地用于处理用户的连接请求
* 生产环境中实际的查询类型,非等值查询(如:非唯一索引查询、联结表查询等)往往占比较高,而这些查询(尤其是查询条件涉及到多列时),在没有类似MySQL的ICP特性支持的情况下,从存储引擎读取的数据量往往会超过它们真实需要的数据量(例如:满足所有查询条件的数据可能只有10行,而实际上从存储引擎读取的数据量是100行),这是因为MySQL在执行查询时,会选择一个条件列在存储引擎中做数据的检索,将检索到的数据返回到MySQL Server,再用其余的条件列做数据过滤,过滤出满足所有条件的数据,然后再返回给客户端。这个过程中,被过滤掉的数据,其实是一种浪费,如果使用了类似MySQL ICP的特性,则可以将所有的条件列都下推到存储引擎层,直接返回满足所有条件列的数据,就不需要读取不满足所有条件的数据了。
* 虽然MySQL ICP的特性,能够避免从存储引擎读取的不必要的数据,但是,存储引擎层的过滤计算也仍然需要消耗主机CPU资源,能不能够将计算量进一步下推到存储设备呢?能!
* 假设某个存在多个条件列的查询(注:这里假设多个条件列都是索引列,下不赘述),在没有类似MySQL ICP特性支持的情况下,查询执行的流程大致如下图(注意红色字体,下不赘述)。假设查询能够使用到多列索引,则会先使用索引顺序的第一个列进行数据检索(检索列),从存储引擎获取数据,然后,在MySQL Server层使用其余的条件列(过滤列),过滤出满足所有条件的数据
* 如果上述查询,有类似MySQL ICP特性支持的情况下,那么查询就能够避免从存储引擎中读取不满足所有条件的数据了,如下图,将所有的条件列(必须是索引列)都下推到存储引擎层,只读取匹配所有条件列的数据,就不再需要在MySQL Server层做数据过滤了
* 计算下推到存储设备,指的就是在类似MySQL ICP的特性上进一步优化,将计算逻辑下推到存储设备上,进一步释放主机CPU资源和主机的带宽资源,如下图
* 通过上面的介绍,我想,将类似MySQL ICP的计算下推到存储设备上的收益是什么已经无需多言!如果能够将更多的计算逻辑下推到存储设备,那么,必然能够进一步释放主机的CPU、带宽,甚至是内存资源,让主机的资源能够更多地用于接受与处理用户的业务请求,从而进一步提高数据库的性能!
作者介绍:
罗小波@ScaleFlux,《千金良方——MySQL性能优化金字塔法则》作者之一。
熟悉MySQL体系结构,擅长数据库的整体调优,喜好专研开源技术,并热衷于开源技术的推广,在线上线下做过多次公开的数据库专题分享,发表过近100篇数据库相关的研究文章。
全文完。