背景
随着大数据、云计算、物联网等技术的飞速发展,用户场景产生的数据量持续增长,花费在数据存储上的成本也越来越高⇧。如果能在数据持久化保存到存储介质之前对其进行压缩,一方面可以减少存盘的数据量,降低存储成本,另一方面可以减少数据库系统对存储介质的访问次数和数据量,能够在一定程度上提升数据库的性能。
数据压缩是在保证数据完整性和安全性的基础上,使用一定的压缩算法对数据进行编码处理,以达到减少存储空间的一种技术手段。MogDB 从3.0版本开始引入行存表的行级压缩特性,自动对行存表中的数据进行压缩,该特性在保证数据完整性和正确性的前提下,能够帮助用户节省存储空间,提高数据访问效率➚。5.0版本则对行级压缩特性进一步优化,兼容 MogDB 已发布的各种工具和插件,以及段页式存储,进一步提高行级压缩特性的使用价值。
业界主流方案
商业数据库压缩方案
在数据库领域,主流的数据库大都支持数据压缩存储的功能。商业数据库 Oracle 是数据压缩技术的先驱,早在 Oracle 9i版本就引入了数据压缩功能,在后续的版本中引入了基于字典的行级压缩。Oracle 的压缩方案是在页面内训练数据字典并将其存放在页面内部,数据的压缩和解压不会引入因读写字典而导致额外的IO开销。数据的压缩和解压以表中的一行数据处理单元,数据页中压缩数据和未压缩数据混合存储。在 Oracle 的早期版本中,数据的压缩通常由数据导入和DML操作触发,会在一定程度上影响数据库的读写性能,从Database 12c Release 2开始新增后台压缩任务,根据页面的的空间使用情况,选择性地对数据页进行压缩。DB2 采用的压缩方案与 Oracle 类似,也是以表中的一行数据为压缩解压单元。
开源数据库压缩方案
开源数据库 MySQL 与 Oracle/DB2 的压缩方案有所区别。MySQL 采用zlib库提供的Lz77压缩算法,在压缩解压单元的选择上,MySQL 以一个数据页面为压缩解压单元,在创表时可以通过参数设置压缩后的页面大小。数据下盘时对数据页面进行压缩,按照创表时指定的页面大小进行对齐后写入存储介质。缓冲池中同时缓存压缩和未经压缩的数据页面,存储介质上全是压缩后的数据。PostgreSQL 采用的压缩方案与 MySQL 类似,也是在数据下盘时以一个数据页面为压缩单元进行数据压缩,与 MySQL 不同的是 PostgreSQL 支持的压缩算法更多,压缩后的数据页面大小是变长的,并引入新的文件来管理原始数据页面和压缩后的数据页面之间的对应关系。
现有方案优缺点分析
MySQL 和 PostgreSQL 采用的压缩方案以一个数据页面作为压缩解压单元,在数据页面内训练数据字典,在数据下盘时进行数据压缩,读取页面时进行解压。这种方案生成的数据字典能够跟随写入数据的变更进行演进,保持字典的有效性,但是在进行查询时会出现解压放大的现象,即使读取一行数据,也会对整个数据页面进行解压。此外,系统长时间运行后还容易产生磁盘碎片,降低磁盘的使用效率。
Oracle 和 DB2 采用的压缩方案以数据页内的一行数据为压缩解压单元,解决了页级压缩带来的解压放大的问题。但是 Oracle 的数据字典无法识别跨页面的重复数据,不同数据页面之间的重复字段无法进行有效压缩。早期的 DB2 版本在表级训练数据字典,训练生成的数据字典不会随着数据的变更进行演进,对于长时间运行的系统,新增的数据只能使用已经生成的字典,字典的有效性逐渐下降,导致压缩率降低。而重新训练字典是一个特别重量级的操作,会消耗大量的系统资源,对数据库的其他业务产生影响。为了保持字典信息的有效性,DB2 v10开始引入自适应压缩,在页级训练字典,解决表级字典难以动态调整的问题。
MogDB 压缩方案
方案整体概述
MogDB 结合开源 PostgreSQL/MySQL 和商业数据库 Oracle/DB2 的压缩方案,推出的行级压缩特性有效地融合了两者的优点。首先,以数据页内的一行数据为压缩解压单元,消除了页级压缩方案带来的解压放大问题。其次,在压缩字典的方案设计上,采用多页共享字典的方案,每10GB数据共享一个数据字典,使数据字典既能够对不同数据页面之间的重复数据进行编码处理,也能够随着写入的数据进行演进,保持数据字典的有效性。此外,MogDB 还引入后台压缩线程对数据进行压缩处理,降低压缩对数据库前台业务的影响;设计实现了基于开销的后台压缩流量控制机制,进一步降低压缩任务对数据库前台业务的影响。
MogDB 行级压缩方案整体概述如下图所示。
行级压缩:对每个数据页面进行压缩时,首先识别一行数据的边界,对行记录中用户的数据部分进行压缩处理。
数据字典:对表的数据进行切割,每10GB数据页面共享一个字典,称为一个共享字典段,训练数据字典时,抽样128MB的数据作为样本,通过 MogDB 专用的压缩算法训练生成该共享字典段使用的数据字典,数据字典持久化保存到存储介质中。
后台压缩:数据插入时会判断当前页面已写入的数据量是否达到给定的阈值,达到阈值后设置当前页面对应的可压缩标志,后台压缩线程根据页面的可压缩标志判断是否需要对页面进行压缩处理。
整体方案架构图
后台压缩
为了不影响数据库前台业务的写入性能,MogDB 的行级压缩特性采用后台压缩的方式对压缩表中的数据进行压缩处理。前台业务写入的数据直接由专门的刷脏线程写入磁盘,单个表累计写入的数据量达到一定的阈值后由后台压缩线程对表中的数据进行压缩处理。后台压缩线程的线程模型如图。数据库服务启动后会启动一个后台压缩调度线程launcher线程,launcher线程是常驻线程,在数据库正常运行期间一直运行。launcher线程会定期扫描系统表`pg_database`,然后通知postmaster线程启动一个worker线程对指定的DB进行处理,worker线程启动后会扫描并处理当前DB下所有需要压缩的表。后台压缩在不同的表之间是并行的,MogDB 支持的最大同时运行的worker数量可以通过GUC参数进行设置,详情请参考[MogDB 官方文档]
(https://docs.mogdb.io/zh/mogdb/v5.0/backend-compression#autocmpr_max_workers)。
后台压缩线程模型图
基于开销的流量控制机制
由于 MogDB 采用的是后台压缩的方式对数据进行压缩,数据库前台业务写入的数据会直接落盘,后台压缩所线程扫描到相关数据页面的时候会将数据从磁盘加载到内存中,然后进行数据压缩。如果不对后台压缩线程进行流量控制的话,进行数据压缩时会占用大量的系统资源,影响数据库其他业务的执行。为了尽可能降低数据压缩对数据库其他业务的影响,MogDB 引入了一种基于开销的后台压缩流量控制机制,在数据压缩过程中实时统计压缩产生的系统开销,并对压缩任务进行适当地限制,以降低后台压缩对数据库其他业务的影响。
在执行数据压缩的过程中,系统会维护一个内部的计数器,记录压缩过程中各种I/O操作的近似开销。每次对数据页面进行压缩之前会对当前压缩线程的累计开销进行检查,如果累计的开销达到一定的阈值,则令发起压缩任务的线程睡眠一定的时间,暂停压缩线程的各种I/O活动,然后系统会重置计数器并继续执行压缩。流量控制机制的相关参数介绍请参考[MogDB 官方文档]
(https://docs.mogdb.io/zh/mogdb/v5.0/backend-compression#基于开销的行级压缩)。
字典缓存
数据库服务在正常运行时会频繁地进行数据的写入和查询,进行数据的压缩解压时会频繁地访问字典信息,如果每次访问都从磁盘上读取字典信息,会造成大量的系统I/O消耗和时间消耗,降低数据库性能。为了提高字典的访问效率,MogDB 实现了两级的字典缓存机制,将字典信息缓存在系统中,压缩解压时会首先到缓存中查找字典,如果缓存中没有字典信息,再到磁盘中读取,同时将读取到的字典信息缓存在系统中。对于压缩操作,如果缓存和磁盘中都没有所需的字典信息,则会训练一个字典,并将训练生成的字典持久化到磁盘,同时将字典信息缓存到系统中。
MogDB 采用两级的字典缓存机,提高字典访问效率。在一级缓存中,每个表的字典信息通过一个数组缓存到全局字典缓存中,数组的每一个元素保存一个字典项以及该字典项对应的编码器和解码器,数组的索引即对应字典的编号。由表空间OID、数据库OID和表OID组成的三元组通过哈希打散后分布到不同的哈希桶中。为了解决哈希操作产生的冲突,在每个哈希桶下挂了一个双链表来保存当前桶中的不同元素,双链表的每个节点保存一个指向该节点表示的表的字典缓存数组。通常来说,在单次会话中不会频繁地进行表的切换,因此单次会话中使用到的字典相对固定,没必要频繁地到全局字典缓存中查找字典。在二级缓存中,MogDB 在表的结构体中挂载了一个指针,使其指向该表的字典缓存数组。每次进行压缩解压时优先在二级缓存中查找所需的字典信息,若二级字典信息不存在再去一级缓存中查找,进一步提升访问字典的效率。
字典缓存示意图
为了避免因缓存字典导致过高的内存占用,MogDB 对单表的最大字典数进行了限制,单表最大字典数限制为100个,即前1000GB数据每10GB数据共享一个字典,数据量超过1000GB后,新写入的数据复用第100个字典。在这种限制下,单表的字典最多12.5MB,对于10TB数据量级的生产环境,缓存字典也仅需1GB内存空间,完全可以做到字典信息的全缓存,达到100%的字典缓存命中率。
客户价值
性能
MogDB 的行级压缩特性能够在不对数据库前台业务产生明显影响的前提下对数据进行压缩,减少数据占用的磁盘空间。在TPCC性能测试场景中,设置TPCC参数`warehouses=200, terminals=50, rumMins=360`,数据库参数`max_process_memory=126GB, shared_buffer=64GB`前提下,5.0版本的压缩表和非压缩表的性能表现如下表。对于`NEW_ORDER`和`PAYMENT`这两种主要事务类型,相比较于非压缩表,压缩表的最大事务延迟分别降低了32%和50%,而性能的衰减仅为3%。MogDB 5.0采用的行级压缩方案即使是在大压力的使用场景下,依然能够保持性能的平稳,为客户提供稳定的服务。
压缩表TPCC性能表现
非压缩表TPCC性能表现
磁盘空间节省
MogDB 的行级压缩特性能够为用户节约大量的的存储空间,在典型应用场景中,能够将数据库占用的空间减少50%到70%。这样的空间节省对用户来说是非常有价值的,能够有效降低存储成本、提升存储效率,有助于帮助用户应对数据爆炸式增长带来的挑战。
下面的SQL示例直观地展示了 MogDB 行级压缩特性带来的存储空间的节省。在插入相同数据量的情况下,等后台压缩结束之后,压缩表可用的空闲空间总共有198MB,而非压缩表仅有1202KB。后续写入的数据可以直接填充到压缩节省出来的空闲空间中,以达到节省磁盘空间的目的。
MogDB=# create table mog_cmpr(id int, name text, city text, addr text) with (compression = yes);
CREATE TABLE
MogDB=# create table mog(id int, name text, city text, addr text);
CREATE TABLE
MogDB=# insert into mog_cmpr values (generate_series(0, 1999999), 'asefhouyasbfouyafseasbfoausydfoatysudef', 'asfp9asugbfowusygrfasdfbnoasiuyfgvoasutyfdvoasdf', 'asehofuiyasbfouasyfoatsrvasrga');
INSERT 0 2000000
MogDB=# insert into mog values (generate_series(0, 1999999), 'asefhouyasbfouyafseasbfoausydfoatysudef', 'asfp9asugbfowusygrfasdfbnoasiuyfgvoasutyfdvoasdf', 'asehofuiyasbfouasyfoatsrvasrga');
INSERT 0 2000000
MogDB=# \d+
List of relations
Schema | Name | Type | Owner | Size | Storage | Description
--------+----------+-------+--------+--------+-----------------------------------+-------------
public | mog | table | sxbmog | 301 MB | {orientation=row,compression=no} |
public | mog_cmpr | table | sxbmog | 301 MB | {orientation=row,compression=yes} |
(2 rows)
MogDB=# select pg_size_pretty(sum(avail)) from pg_freespace('mog_cmpr');
pg_size_pretty
----------------
198 MB
(1 row)
MogDB=# select pg_size_pretty(sum(avail)) from pg_freespace('mog');
pg_size_pretty
----------------
1202 kB
(1 row)
总结
在行级压缩特性中,MogDB 在开源压缩算法的基础上进行压缩算法及应用的创新,包括优化压缩算法、引入后台压缩线程、流量控制机制和字典缓存机制等,能够在提供合理的数据压缩率的同时,尽可能地降低数据压缩对数据库其他业务的影响。行级压缩特性支持普通表、分区表和二级分区表,能够显著地节省用户的存储空间,降低存储成本。并且,为应对批量数据导入场景,MogDB 还在`COPY FROM`操作和`VACUUM FULL`操作中集成了数据压缩功能,提高行级压缩特性的易用性,为客户带来更大的使用价值。
数据驱动,成就未来,云和恩墨,不负所托!
云和恩墨创立于2011年,以“数据驱动,成就未来”为使命,是智能的数据技术提供商。我们致力于将数据技术带给每个行业、每个组织、每个人,构建数据驱动的智能未来。
云和恩墨在数据承载(分布式存储、数据持续保护)、管理(数据库基础软件、数据库云管平台、数据技术服务)、加工(应用开发质量管控、数据模型管控、数字化转型咨询)和应用(数据服务化管理平台、数据智能分析处理、隐私计算)等领域为各个组织提供可信赖的产品、服务和解决方案,围绕用户需求,持续为客户创造价值,激发数据潜能,为成就未来敏捷高效的数字世界而不懈努力。