布景

前面提到,咱们有个云文档项目的快照内容是直接存储到db的,属于大文本存储,文档快照的内容字段大部分都是kb等级,部分乃至到MB等级。现在关于数据的读取,已经进行了CDN缓存优化(静态资源缓存利器——CDN),关于数据的写入和存储还有待优化,假设能够经过一些紧缩算法在大文本进行紧缩存储,能够在很大程度上节约DB的存储空间,缓解DB的I/O压力。

存量数据剖析

select
  table_name as '表名',
  table_rows as '记载数',
  truncate(data_length/1024/1024, 2) as '数据容量(MB)',
  truncate(index_length/1024/1024, 2) as '索引容量(MB)',
  truncate(DATA_FREE/1024/1024, 2) as '碎片占用(MB)'
from
  information_schema.tables
where
  table_schema=${数据库名}
order by
  data_length desc, index_length desc;

MySQL大文本存储压缩
MySQL大文本存储压缩

相关内容介绍

innodb引擎页数据超出16kb怎么办?

咱们都知道innodb的页块默许巨细为16k,假设表中一行数据长度超出了16k,就会出现行溢出,溢出的行是寄存在另外的当地(uncompress blob page)。因为innodb选用聚簇索引把数据进行寄存起来,即B+Tree结构,因而每个页块中至少有两行数据,不然就失去了B+Tree的含义,这样就得出一行数据最大的长度限制为8k(大字段在数据页会存储768个字节数据,剩下的数据溢出到另外的页中,数据页还有20个字节记载溢出页的地址)

  • 对 dynamic 格局来说,假设大目标字段(text/blob)存储数据巨细小于 40 字节,那全部放在数据页,剩下的场景,数据页只保存一个 20 字节的指针指向溢出页。 这种场景下,假设每个大目标字段保存的数据小于 40 个字节,也就和 varchar(40),作用相同。
  • innodb-row-format-dynamic:dev.mysql.com/doc/refman/…

Linux 稀少文件 & 空泛

  • 稀少文件(Sparse File):稀少文件与其他一般文件基本相同,差异在于文件中的部分数据全为0,且这部分数据不占用磁盘空间
  • 文件空泛:文件位移量能够大于文件的实践长度(位于文件中但未被写过的字节被设为0),空泛是否占用磁盘空间由操作体系决定
    • MySQL大文本存储压缩

文件空泛部分不占用磁盘空间、文件所占用的磁盘空间仍然是接连的

innodb供给的紧缩计划

页面紧缩

适用场景:因为数据量太大,磁盘空间不足,负载首要体现在IO上,而服务器的CPU又有比较多的余量的场景。

1)COMPRESS页紧缩

相关文档:dev.mysql.com/doc/refman/…

  • MySQL5.7版本之前就供给的页紧缩功能,在创建表时指定 ROW_FORMAT = COMPRESS,并经过 KEY_BLOCK_SIZE 设置紧缩页的巨细
  • 存在规划上的缺陷,有可能会导致功能下降明显,然后其规划初衷是为了进步功能,引入了“日志即数据”的理念
    • 关于紧缩页的数据修正,并不会直接修正页本身,而是将修正日志存储在这个页中,这的确对数据的变更比较友好,不用每次修正都进行紧缩/解压
      • MySQL大文本存储压缩
    • 关于数据的读取,紧缩的数据是无法直接读取的,所以这种算法会在内存中保存一个解压后的16K的页,以供数据的读取
      • MySQL大文本存储压缩
    • 这就导致了一个页在缓冲池中可能会有两个版本(紧缩版和非紧缩版),引发一个十分严重的问题,即缓冲池中能缓存的页的数量大大的削减了,然后可能会导致数据库的功能极大的下降

2)TPC(通明页紧缩)

相关文档:dev.mysql.com/doc/refman/…

  • 工作原理:写入页面时,运用指定的紧缩算法对页面进行紧缩,紧缩后写入磁盘,其间经过打孔机制从页面末尾开释空(需求操作体系支撑空泛特性)
  • ALTER TABLE xxx COMPRESSION = ZLIB 能够启用TPC页紧缩功能,但这仅仅对后续增量数据进行紧缩,假设希望对整个表进行紧缩,则需求履行 OPTIMIZE TABLE xxx
  • 实现过程:一个紧缩页在缓冲池中都是一个16K的非紧缩页,只要在数据刷盘的时分,会进行一次紧缩,紧缩后剩下的空间会用 0x00 填满,运用文件体系的空泛特性(hole punch)对文件进行裁剪,开释 0x00 占用的稀少空间
    • MySQL大文本存储压缩
  • TPC虽好,但它依靠操作体系的 Hole Punch 特性,且裁剪后的文件巨细需求和文件体系块巨细对齐(4K)。即假设紧缩后的页巨细是9K,那么实践占用的空间是12K

列紧缩

MySQL现在没有直接针对列紧缩的计划,有一个曲线救国的方法,就是在事务层运用MySQL供给的紧缩和解压函数来针对列进行紧缩和解压操作。也就是假设需求对某一列做紧缩,在写入时调用COMPRESS函数对那个列的内容进行紧缩,读取的时分,运用UNCOMPRESS函数对紧缩过的数据进行解压。

  • 运用场景:针对表中某些列数据长度比较大的情况,一般是 varchar、text、blob、json等数据类型
  • 相关函数:
    • 紧缩函数:COMPRESS()
    • 解紧缩函数:UNCOMPRESS()
    • 字符串长度函数:LENGTH()
    • 未解压字符串长度函数:UNCOMPRESSED_LENGTH()
  • 测验:
    • 刺进数据:insert into xxx (content) values (compress('xxx....'))
    • 读取紧缩的数据:select c_id, uncompressed_length(c_content) uncompress_len, length(c_content) compress_len from xxx
      • MySQL大文本存储压缩

为什么innodb供给的都是根据页面的紧缩技术?

  • 记载紧缩:每次读写记载的时分,都要进行紧缩或解压,过度依靠CPU的核算才能,功能相对会比较差
  • 表空间紧缩:紧缩效率高,但要求表空间文件是静态不增长的,这关于咱们大部分的场景都是不适用的
  • 页面紧缩:既能进步效率,又能在功能中取得一定的平衡

总结

  • 关于一些功能不灵敏的事务表,如日志表、监控表、告警表等,这些表只希望对存储空间进行优化,对功能的影响不是很重视,能够运用COMPRESS页紧缩
  • 关于一些比较核心的表,则比较推荐运用TPC紧缩
  • 列紧缩过度依靠CPU,功能方面会稍差,且对事务有一定的改造本钱,不够灵活,需求评估影响规模,做好切换的计划。好处是能够由事务端决定哪些数据需求紧缩,并控制解压操作
  • 对页面进行紧缩,在事务侧不用进行什么改动,对线上完全通明,紧缩计划也十分老练

为什么要进行数据紧缩?

  • 因为处理器和高速缓存存储器的速度进步超过了磁盘存储设备,因而许多时分工作负载都是受限于磁盘I/O。数据紧缩能够使数据占用更小的空间,能够节约磁盘I/O、削减网络I/O然后进步吞吐量,虽然会牺牲部分CPU资源作为代价
  • 关于OLTP体系,经常进行update、delete、insert等操作,经过紧缩表能够削减存储占用和IO耗费
  • 紧缩其实是一种平衡,并不一定是为了进步数据库的功能,这种平衡取决于解紧缩带来的收益和开销之间的一种权衡,但紧缩对存储空间来说,收益无疑是很大的

简单测验

innodb通明页紧缩(TPC)

参阅:dev.mysql.com/doc/refman/…

测验数据

1)创建表

  • create table table_origin ( …… ) comment ‘测验原表’;
  • create table table_compression_zlib ( …… ) comment ‘测验紧缩表_zlib’ compression = ‘zlib’;
  • create table table_compression_lz4 ( …… ) comment ‘测验紧缩表_lz4’ compression = ‘lz4’;

2)往表中写入10w行测验数据

紧缩率

SELECT NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE
FROM information_schema.INNODB_TABLESPACES WHERE NAME like 'test_compress%';

MySQL大文本存储压缩

  • FS_BLOCK_SIZE:文件体系块巨细,也就是打孔运用的单位巨细
  • FILE_SIZE:文件的表观巨细,表示文件的最大巨细,未紧缩
  • ALLOCATED_SIZE:文件的实践巨细,即磁盘上分配的空间量

紧缩率:

  • zlib:1320636416/3489660928 = 37.8%
  • lz4:1566949376/3489660928 = 45%

耗时

  • 循环刺进10w条记载
    • 原表:918275 ms
    • zlib:878540 ms
    • lz4:875259 ms
  • 循环查询10w条记载
    • 原表:332519 ms
    • zlib:373387 ms
    • lz4:343501 ms