阅读更多

0顶
1踩

数据库

原创新闻 数据库压缩技术探索

2017-06-09 10:01 by 副主编 jihong10102006 评论(0) 有21768人浏览
引用
作者:雷鹏,Terark核心技术发明人。曾就职奇虎360,负责搜索引擎核心研发;曾就职Yahoo!北研所负责搜索广告、广告交易(AdExchange)等项目。在数据库、高性能计算、分布式、系统架构上都深有造诣。
责编:仲培艺(zhongpy@csdn.net)
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅《程序员》

作为数据库,在系统资源(CPU、内存、SSD、磁盘等)一定的前提下,我们希望:
  • 存储的数据更多:采用压缩,这个世界上有各种各样的压缩算法;
  • 访问的速度更快:更快的压缩(写)/解压(读)算法、更大的缓存。
几乎所有压缩算法都严重依赖上下文:
  • 位置相邻的数据,一般情况下相关性更高,内在冗余度更大;
  • 上下文越大,压缩率的上限越大(有极限值)。
块压缩

传统数据库中的块压缩技术

对于普通的以数据块/文件为单位的压缩,传统的(流式)数据压缩算法工作得不错,时间长了,大家也都习惯了这种数据压缩的模式。基于这种模式的数据压缩算法层出不穷,不断有新的算法实现。包括使用最广泛的gzip、bzip2、Google的Snappy、新秀Zstd等。
  • gzip几乎在在所有平台上都有支持,并且也已经成为一个行业标准,压缩率、压缩速度、解压速度都比较均衡;
  • bzip2是基于BWT变换的一种压缩,本质是上对输入分块,每个块单独压缩,优点是压缩率很高,但压缩和解压速度都比较慢;
  • Snappy是Google出品,优点是压缩和解压都很快,缺点是压缩率比较低,适用于对压缩率要求不高的实时压缩场景;
  • LZ4是Snappy一个强有力的竞争对手,速度比Snappy更快,特别是解压速度;
  • Zstd是一个压缩新秀,压缩率比LZ4和Snappy都高不少,压缩和解压速度略低;相比gzip,压缩率不相上下,但压缩/解压速度要高很多。
对于数据库,在计算机世界的太古代,为I/O优化的Btree一直是不可撼动的,为磁盘优化的Btree block/page size比较大,正好让传统数据压缩算法能得到较大的上下文,于是,基于block/page的压缩也就自然而然地应用到了各种数据库中。在这个蛮荒时代,内存的性能、容量与磁盘的性能、容量泾渭分明,各种应用对性能的需求也比较小,大家都相安无事。

现在,我们有了SSD、PCIe SSD、3D XPoint等,内存也越来越大,块压缩的缺点也日益突出:
  • 块选小了,压缩率不够;块选大了,性能没法忍;
  • 更致命的是,块压缩节省的只是更大更便宜的磁盘、SSD;
  • 更贵更小的内存不但没有节省,反而更浪费了(双缓存问题)。
于是,对于很多实时性要求较高的应用,只能关闭压缩。

块压缩的原理

使用通用压缩技术(Snappy、LZ4、zip、bzip2、Zstd等),按块/页(block/page)进行压缩(块尺寸通常是4KB~32KB,以压缩率著称的TokuDB块尺寸是2MB~4MB),这个块是逻辑块,而不是内存分页、块设备概念中的那种物理块。

启用压缩时,随之而来的是访问速度下降,这是因为:
  • 写入时,很多条记录被打包在一起压缩成一个个的块,增大块尺寸,压缩算法可以获得更大的上下文,从而提高压缩率;相反地,减小块尺寸,会降低压缩率。
  • 读取时,即便是读取很短的数据,也需要先把整个块解压,再去读取解压后的数据。这样,块尺寸越大,同一个块内包含的记录数目越多。为读取一条数据,所做的不必要解压就也就越多,性能也就越差。相反地,块尺寸越小,性能也就越好。
一旦启用压缩,为了缓解以上问题,传统数据库一般都需要比较大的专用缓存,用来缓存解压后的数据,这样可以大幅提高热数据的访问性能,但又引起了双缓存的空间占用问题:一是操作系统缓存中的压缩数据;二是专用缓存(例如RocksDB中的DBCache)中解压后的数据。还有一个同样很严重的问题:专用缓存终归是缓存,当缓存未命中时,仍需要解压整个块,这就是慢Query问题的一个主要来源(慢Query的另一个主要来源是在操作系统缓存未命中时)。

这些都导致现有传统数据库在访问速度和空间占用上是一个此消彼长、无法彻底解决的问题,只能采取一些折衷。

RocksDB 的块压缩

以RocksDB为例,RocksDB中的BlockBasedTable就是一个块压缩的SSTable,使用块压缩,索引只定位到块,块的尺寸在dboption里设定,一个块中包含多条(key,value)数据,例如M条,这样索引的尺寸就减小到了1/M:
  • M越大,索引的尺寸越小;
  • M越大,Block的尺寸越大,压缩算法(gzip、Snappy等)可以获得的上下文也越大,压缩率也就越高。
创建BlockBasedTable时,Key Value被逐条填入buffer,当buffer尺寸达到预定大小(块尺寸,当然,一般buffer尺寸不会精确地刚好等于预设的块尺寸),就将buffer压缩并写入BlockBasedTable文件,并记录文件偏移和buffer中的第一个Key(创建index要用),如果单条数据太大,比预设的块尺寸还大,这条数据就单独占一个块(单条数据不管多大也不会分割成多个块)。所有Key Value写完以后,根据之前记录的每个块的起始Key和文件偏移,创建一个索引。所以在BlockBasedTable文件中,数据在前,索引在后,文件末尾包含元信息(作用相当于常用的FileHeader,只是位置在文件末尾,所以叫footer)。

搜索时,先使用searchkey找到searchkey所在的block,然后到DB Cache中搜索这个块,找到后就进一步在块中搜索searchkey,如果找不到,就从磁盘/SSD读取这个块,解压后放入DB Cache。RocksDB中的DB Cache有多种实现,常用的包括LRU Cache,另外还有Clock Cache、Counting Cache(用来统计Cache命中率等),还有其他一些特殊的Cache。

一般情况下,操作系统会有文件缓存,所以同一份数据可能既在DB Cache中(解压后的数据),又在操作系统Cache中(压缩的数据)。这样会造成内存浪费,所以RocksDB提供了一个折衷:在dboption中设置DIRECT_IO选项,绕过操作系统Cache,这样就只有DB Cache,可以节省一部分内存,但在一定程度上会降低性能。

传统非主流压缩:FM-Index

FM-Index的全名是Full Text Matching Index,属于Succinct Data Structure家族,对数据有一定的压缩能力,并且可以直接在压缩的数据上执行搜索和访问。

FM-Index的功能非常丰富,历史也已经相当悠久,不算是一种新技术,在一些特殊场景下也已经得到了广泛应用,但是因为各种原因,一直不温不火。最近几年,FM-Index开始有些活跃,首先是GitHub上有个大牛实现了全套Succinct算法,其中包括FM-Index,其次Berkeley的Succinct项目也使用了FM-Index。

FM-Index属于Offline算法(一次性压缩所有数据,压缩好之后不可修改),一般基于BWT变换(BWT变换基于后缀数组),压缩好的FM-Index支持以下两个最主要的操作:
  • data = extract(offset, length)
  • {offset} = search(string) ,返回多个匹配string的位置/偏移(offset)
FM-Index还支持更多其他操作,感兴趣的朋友可以进一步调研。

但是,在笔者看来,FM-Index有几个致命的缺点:
  • 实现太复杂(这一点可以被少数大牛们克服,不提也罢);
  • 压缩率不高(比流式压缩例如gzip差太多);
  • 搜索(search)和访问(extract)速度都很慢(在2016年最快的CPU i7-6700K上,单线程吞吐率不超过7MB/sec);
  • 压缩过程又慢又耗内存(Berkeley的Succinct压缩过程内存消耗是源数据的50倍以上);
  • 数据模型是Flat Text,不是数据库的KeyValue模型。
可以用一种简单的方式把Flat Model转化成KeyValue Model:挑选一个在Key和Value中都不会出现的字符“#”(如果无法找出这样的字符,需要进行转义编码),每个Key前后都插入该字符,Key之后紧邻的就是Value。如此,search(#key#)返回了#key#出现的位置,我们就能很容易地拿到Value了。

Berkeley的Succinc项目在FM-Index的Flat Text模型上实现了更丰富的行列(Row-Column)模型,付出了巨大的努力,达到了一定的效果,但离实用还相差太远。

感兴趣的朋友可以仔细调研下FM-Index,以验证笔者的总结与判断。

Terark的可检索压缩(Searchable Compression)

Terark公司提出了“可检索压缩(Searchable Compression)”的概念,其核心也是直接在压缩的数据上执行搜索(search)和访问(extract),但数据模型本身就是KeyValue模型,根据其测试报告,速度要比FM-Index快得多(两个数量级),具体阐述:
  • 摒弃传统数据库的块压缩技术,采用全局压缩;
  • 对Key和Value使用不同的全局压缩技术;
  • 对Key使用有搜索功能的全局压缩技术COIndex(对应FM-Index的search);
  • 对Value使用可定点访问的全局压缩技术PA-Zip(对应FM-Index的extract)。
对Key的压缩:CO-Index

我们需要对Key进行索引,才能有效地进行搜索,并访问需要的数据。

普通的索引技术,索引的尺寸相对于索引中原始Key的尺寸要大很多,有些索引使用前缀压缩,能在一定程度上缓解索引的膨胀,但仍然无法解决索引占用内存过大的问题。

我们提出了CO-Index(Compressed Ordered Index)的概念,并且通过一种叫做Nested Succinct Trie的数据结构实践了这一概念。

较之传统实现索引的数据结构,Nested Succinct Trie的空间占用小十几倍甚至几十倍。而在保持该压缩率的同时,还支持丰富的搜索功能:
  • 精确搜索;
  • 范围搜索;
  • 顺序遍历;
  • 前缀搜索;
  • 正则表达式搜索(不是逐条遍历)。
与FM-Index相比,CO-Index也有其优势(假定FM-Index中所有的数据都是Key)。

表1 FM-Index对比CO-Index

CO-Index的原理

实际上我们实现了很多种CO-Index,其中Nested Succinct Trie是适用性最广的一种,在这里对其原理做一个简单介绍:

Succinct Data Structure介绍

Succinct Data Structure是一种能够在接近于信息论下限的空间内来表达对象的技术,通常使用位图来表示,用位图上的rank和select来定位。

虽然能够极大降低内存占用量,但实现起来较为复杂,并且性能低很多(时间复杂度的常数项很大)。目前开源的有SDSL-Lite,我们则使用自己实现的Rank-Select,性能也高于开源实现。

以二叉树为例

传统的表现形式是一个结点中包含两个指针:struct Node { Node *left, *right; };

每个结点占用 2ptr,如果我们对传统方法进行优化,结点指针用最小的bits数来表达,N个结点就需要2*[log2(N)]个bits。
  • 对比传统基本版和传统优化版,假设共有216个结点(包括null结点),传统优化版需要2 bytes,传统基本版需要4/8 bytes。
  • 对比传统优化版和Succinct,假设共有10亿(~230)个结点。
  • 传统优化版每个指针占用[log2(230)]=30bits,总内存占用:($\frac{2*30}{8}$)*230≈ 7.5GB。
  • 使用Succinct,占用:($\frac{2.5}{8}$)*230≈ 312.5MB(每个结点2.5 bits,其中0.5bits是 rank-select 索引占用的空间)。
Succinct Tree

Succinct Tree有很多种表达方式,这里列出常见的两种:

图1 Succinct Tree表达方式示例

Succinct Trie = Succinct Tree + Trie Label

Trie可以用来实现Index,图2这个Succinct Trie用的是LOUDS表达方式,其中保存了hat、is、it、a、四个Key。

Patricia Trie加嵌套

仅使用Succinct技术,压缩率远远不够,所以又应用了路径压缩和嵌套。这样一来,压缩率就上了一个新台阶。

把上面这些技术综合到一起,就是我们的Nest Succinct Trie。

对Value的压缩: PA-Zip

我们研发了一种叫做PA-Zip (Point Accessible Zip)的压缩技术:每条数据关联一个ID,数据压缩好之后,就可以用相应的ID访问那条数据。这里,ID就是那个Point,所以叫做Point Accessible Zip。

PA-Zip对整个数据库中的所有Value(KeyValue数据库中所有Value的集合)进行全局压缩,而不是按block/page进行压缩。这是针对数据库的需求(KeyValue 模型),专门设计的一个压缩算法,用来解决传统数据库压缩的问题:
  • 压缩率更高,没有双缓存的问题,只要把压缩后的数据装进内存,不需要专用缓存,可以按ID直接读取单条数据,如果把这种读取单条数据看作是一种解压,那么:
  • 按ID顺序解压时,解压速度(Throughput)一般在500MB每秒(单线程),最高达到约7GB/s,适合离线分析性需求,传统数据库压缩也能做到这一点;
  • 按ID随机解压时,解压速度一般在300MB每秒(单线程),最高达到约3GB/s,适合在线服务需求,这一点完胜传统数据库压缩:按随机解压300MB/s算,如果每条记录平均长度1K,相当于QPS = 30万;如果每条记录平均长度300个字节,相当于QPS = 100万;
  • 预热(warmup),在某些特殊场景下,数据库可能需要预热。因为去掉了专用缓存,TerarkDB的预热相对简单高效,只要把mmap的内存预热一下(避免Page Fault即可),数据库加载成功后就是预热好的,这个预热的Throughput就是SSD连续读的IO性能(较新的SSD读性能超过3GB/s)。
与FM-Index相比,PA-Zip解决的是FM-Index的extract操作,但性能和压缩率都要好得多:

表2 FM-Index对比PA-Zip

结合Key与Value

Key以全局压缩的形式保存在CO-Index中,Value以全局压缩的形式保存在 PA-Zip中。搜索一个Key,会得到一个内部ID,根据这个ID,去PA-Zip中定点访问该ID对应的Value,整个过程中只触碰需要的数据,不需要触碰其他数据。

如此无需专用缓存(例如RocksDB中的DBCache),仅使用mmap,完美配合文件系统缓存,整个DB只有mmap的文件系统缓存这一层缓存,再加上超高的压缩率,大幅降低了内存用量,并且极大简化了系统的复杂性,最终完成数据库性能的大幅提升,从而同时实现了超高的压缩率和超高的随机读性能。

从更高的哲学层面看,我们的存储引擎很像是用构造法推导出来的,因为CO-Index和PA-Zip紧密配合,完美匹配KeyValue模型,功能上“刚好够用”,性能上压榨硬件极限,压缩率逼近信息论的下限。相比其他方案:
  • 传统块压缩是从通用的流式压缩衍生而来,流式压缩的功能非常有限,只有压缩和解压两个操作,对太小的数据块没有压缩效果,也无法压缩数据块之间的冗余。把它用到数据库上,需要大量的工程努力,就像给汽车装上飞机机翼,然后要让它飞起来。
  • 相比FM-Index,情况则相反,FM-Index的功能非常丰富,它就必然要为此付出一些代价——压缩率和性能。而在KeyValue模型中,我们只需要它那些丰富功能的一个非常小的子集(还要经过适配和转化),其他更多的功能毫无用武之地,却仍然要付出那些代价,就像我们花了很高的代价造了一架飞机,却把它按在地上,只用轮子跑,当汽车用。

  • 图2 用LOUDS方式表达的Succinct Tree


    图3 路径压缩与嵌套

附录

压缩率&性能测试比较

数据集:Amazon movie data

Amazon movie data (~8 million reviews),数据集的总大小约为9GB, 记录数大约为800万条,平均每条数据长度大约1K。

Benchmark代码开源:参见Github仓库
压缩率(见图4)

图4 压缩率对比

随机读(见图5)

图5 随机读性能对比


这是在内存足够的情况下,各个存储引擎的性能。
延迟曲线(见图6)

图6 延迟曲线对比

数据集:Wikipedia英文版

Wikipedia英文版的所有文本数据,109G,压缩到23G。

数据集:TPC-H

在TPC-H的lineitem数据上,使用TerarkDB和原版RocksDB(BlockBasedTable)进行对比测试:

表3 TerarkDB与原版RocksDB对比测试

API 接口

TerarkDB = Terark SSTable + RocksDB

RocksDB最初是Facebook对Google的LevelDB的一个fork,编程接口上兼容LevelDB,并增加了很多改进。

RocksDB对我们有用的地方在于其SSTable可以plugin,所以我们实现了一个RocksDB的SSTable,将我们的技术优势通过RocksDB发挥出来。

虽然RocksDB提供了一个相对完整的KeyValueDB框架,但要完全适配我们特有的技术,仍有一些欠缺,所以需要对RocksDB本身也做一些修改。将来可能有一天我们会将自己的修改提交到RocksDB官方版。

Github链接:TerarkDBhttps://github.com/Terark/terarkdb),TerarkDB包括两部分:
为了更好的兼容性,TerarkDB对RocksDB的API没有做任何修改,为了进一步方便用户使用TerarkDB,我们甚至提供了一种方式:程序无需重新编译,只需要替换 librocksdb.so并设置几个环境变量,就能体验TerarkDB。

如果用户需要更精细的控制,可以使用C++ API详细配置TerarkDB的各种选项。

目前大家可以免费试用,可以做性能评测,但是不能用于production,因为试用版会随机删掉0.1%的数据。

Terark命令行工具集

我们提供了一组命令行工具,这些工具可以将输入数据压缩成不同的形式,压缩后的文件可以使用Terark API或(该工具集中的)其他命令行工具解压或定点访问。

详情参见Terark wiki中文版https://github.com/Terark/terark-wiki-zh_cn)。
  • 大小: 50.7 KB
  • 大小: 52.9 KB
  • 大小: 13.9 KB
  • 大小: 91.4 KB
  • 大小: 135.7 KB
  • 大小: 23.3 KB
  • 大小: 18.9 KB
  • 大小: 89 KB
  • 大小: 108.9 KB
0
1
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 数据库新技术前沿总结

    (1)面向对象的方法和技术对数据库发展的影响最为深远数据库研究人员借鉴和吸收了面向对象的方法和技术,提出了面向对象数据模型(简称对象模型)。该模型克服了传统数据模型的局限性,促进了数据库技术在一个新的...

  • AWS云计算技术架构探索系列之六-数据库

    这其中的关键技术就是Vector Clock ,如下图所示: 我们来分析下这个过程: 第一步,客户端通过节点Sx一个对象,并创建对象的向量时钟 vector clock。至此,系统有了一个对象 D1 和它的向量时钟 [(Sx, 1)]。 第二...

  • 《GPU 数据库核心技术综述》论文学习

    文章目录一、背景二、GPU 数据库分类与层次1.商用型C-GDBMS 中分为3类2.研究型R-GDBMS三、查询编译器 一、背景 1.GPU性能极高 GPU 与 CPU 具有不同的体系结构和处理模式,将更多的片上空间用于计算单元,控制单元和...

  • 时序数据库的现状及核心技术

    凌云时刻编者按:本篇整理自峰会《时序数据库论坛》演讲视频的文字版本。作者孙金城,花名金竹,在阿里工作近10年,以ApacheFlink为切入点,在流计算领域贡献了5年,目前以阿里巴巴物联网...

  • 猿创征文 | 数据库技术及TiDB数据库概述

    数据库技术产生于20世纪60年代末70年代初,其主要主要研究如何存储,使用和管理数据。随着计算机硬件和软件的发展,数据库技术也不断地发展。数据库技术在理论研究和系统开发上都取得了辉煌的成就。TiDB 是 PingCAP ...

  • 字节云数据库未来方向的探索与实践

    日前,字节跳动技术社区 ByteTech 举办的第四期字节跳动技术沙龙圆满落幕,本期沙龙以《字节云数据库架构设计与实战》为主题。在沙龙中,字节跳动基础架构数据库开发工程师刘辉聪,跟大家探讨了 《字节云数据库未来...

  • MatrixDB 数据库内核技术

    第十二届中国数据库技术大会(DTCC2021),在北京火热开展,一场盛会,围绕着当前热门的“时序数据库”话题,共同探讨最前沿的技术趋势与实践。 四维纵横在大会上由“首席技术官” ——翁岩青亮相本届 DTCC,精彩...

  • 数据架构选型必读:2021上半年数据库产品技术解析

    本期要点DB-Engines数据库排行榜一、RDBMSOracle发布21c,包含200多项创新MySQL发布8.0.24及8.0.25版本PostgreSQL发布14 Beta 1,新增...

  • 腾讯云原生数据库TDSQL-C架构探索和实践

    为帮助用户了解极致体验背后的关键技术点,本期带来腾讯云数据库专家工程师王鲁俊给大家分享的腾讯云原生数据库TDSQL-C的架构探索和实践,内容主要分为四个部分: 本次分享主要分为四个部分: 第一部分,介绍腾讯云...

  • TDSQL-基于压缩数据直接计算技术,定义新型数据库处理 | SIGMOD 2022入选论文解读

    腾讯云数据库TDSQL与中国人民大学最新联合研究成果被SIGMOD 2022接收并将通过长文形式发表。SIGMOD是国际数据管理与数据库领域顶尖的学术会议之...论文针对压缩数据的直接操作与处理,提出一项新型数据库处理技术——Co

  • 年度盘点:20+主流数据库重大更新及技术要点回顾

    数据库行业年度回顾技术的多元化探索与产品的差异化发展2021年,各家数据库产品都取得了长足的进步。首先,从技术角度上看,分布式、云及云原生、多模、HTAP、AI自治等代表性技术,成为了各大...

  • 大数据时代的医学公共数据库与数据挖掘技术简介

    来源:临床模型预测本文约9500字,建议阅读10+分钟本文我们将介绍几种数据库和数据挖掘技术,帮助临床研究人员更好地理解和应用数据库技术。数据挖掘技术可以从大量数据中寻找潜在有价值的信息...

  • 数据库分类,市场上常见数据库

    按照物理模型的不同,数据库可以分为:层次模型数据库、网状模型数据库、关系模型数据库、非关系模型数据库、等其他类型模型数据库 层次模型数据库: 概念:整个库中只有一个根节点。且每一个节点都只有一个父级节点...

  • 第七章 NoSQL数据库技术(一)

    NoSQL是Not Only SQL的缩写,意即“不仅仅是SQL”,即对关系型SQL数据库系统的补充。 一类非关系数据存储系统 通常不需要一个固定的表的模式 所有的NoSQL淡化了一个或更多的ACID属性 相比传统数据库叫它分布式...

  • 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

    本文原题“阿里数据库十年变迁,那些你不知道的二三事”,来自阿里巴巴官方技术公号的分享。 1、引言 第十个双11即将来临之际,阿里技术推出《十年牧码记》系列,邀请参与历年双11备战的核心技术大牛,一起回顾...

  • 各类数据库介绍

    1961年,GE(通用电气公司,General Electric Company)的Charles Bachman ,开发了IDS(集成数据存储,Integrated Data Store),这是世界上第一个NDBMS(网状数据库管理系统,Network Database Management System...

  • 数据库系统工程师考点笔记

    本人在备战数据库系统工程师的考试,把刷历年真题碰到的知识点记录在这边。(目录是第四版教程)

  • 【java毕业设计】新冠疫情下的校园出入系统源码(ssm+mysql+说明文档+LW).zip

    功能说明: 本系统主要包括以下功能模块:个人中心,通知公告管理,用户管理,工作人员管理,进门登记管理,出门登记管理,出入统计管理,外来登记管理等模块。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7及以上 数据库工具:Navicat11及以上 开发软件:eclipse/idea Maven包:Maven3.3及以上 服务器:tomcat7及以上

  • param-1.5.1-cp34-cp34m-win_amd64.whl.rar

    PartSegCore_compiled_backend-0.12.0a0-cp36-cp36m-win_amd64.whl.rar

Global site tag (gtag.js) - Google Analytics