技术内幕|Hummock: 为流处理而生的云原生存储引擎重大优化

作者:刘玮 RisingWave Labs 内核开发工程师

1. 背景

在「Hummock :专为 RisingWave 流处理而设计的云原生存储引擎」一文中里我们已经介绍了 Hummock 的设计理念与基本架构,本文主要介绍 Hummock 近期几个版本的重大改进与优化。

2. Fast Compaction

在设计之初,Hummock 的数据文件格式参考了 RocksDB Sstable 的设计。之后为了提升查询性能,Hummock 引入了 Xor Filter 用于替换原有的 Bloom Filter (RocksDB 也引入了基于 Xor Filter 改造的 Ribbon Filter 算法)。但是 Xor Filter 在构建过程中会短暂使用大量的内存,为了减少内存的使用,Hummock 改造了数据存储格式,转而为每个 block 单元的数据构建 Filter 而不是构建全局的单一 Filter,从而降低了构建过程中的内存峰值,使得 RisingWave 可以运行在更加低配的环境中。

LSM Tree 相比 BTree 类的数据结构而言,通过顺序写入+后台整理的方式换来了更高的写入吞吐,然而也付出写放大的代价的,也就是说同一份数据可能会被反复整理(compact),更多细节参考此处。对于 L1 及更旧的数据而言,当数据库试图把上层的一个文件的数据挪到下层时,往往会和下层的多个文件产生重合,为此不得不把远多于一个文件引入同一个 compact 任务中,这正是写放大的主要来源之一。我们注意到,即便上层的文件和下层的多个文件产生了范围重叠,依然不意味着上层的每一个 block (通常在 4KB ~ 256KB 之间)都和下层的某个 block 产生了范围重叠,除非每次写入的数据都在同一个范围内严格的等概率分布。因此,如果我们的 compact 算法不是按照 key 为粒度来遍历数据,而是以 block 为粒度,那么对于那些没有和任务中其他文件的 block 产生重叠的 block,可以避免解压以及再次压缩的开销,直接将这部分数据复制到新的文件中。

传统的 compact 算法如下图所示:

而改进后的算法如下图所示:

通过对比可以看出,SST2 中的 block-1 和 block-3 如果和 SST1 中的数据没有重复的话,可以直接复制到输出文件中,避免额外的解析以及压缩开销

我们测试了多种不同的读写负载,该优化能够节约20%~50%的 compactor CPU 资源。对于那些写入数据较多、吞吐较大的场景,该优化能够显著降低 compact 操作带来的成本问题。目前该功能还在测试中,默认不开启。

3. IO Prefetch

由于 Hummock 的存储设计和 RocksDB 一样,是基于 Block 为粒度来组织数据。当上层应用查询数据时,会逐个读取 block ,如果 block 不在 cache 中,则触发一次 IO 操作读取 remote storage (如果是 AWS 环境部署,则后端为 S3 存储)。然而对 S3 有所了解的开发者都知道,S3 的随机读延迟极高,更适合用于大对象的顺序读取。因此,当用户执行 OLAP 类型的查询时(例如:select count(*) from mv; ),Hummock 需要逐一发送 IO 操作,极大地增加了查询耗时。还有一种类似的场景,对于已经导入的数据表,用户希望再次创建出另外的 Materialize View, 此时也需要遍历所有的历史数据,因此也会受制于上面所提到的读取方式。

因此,对于 RisingWave 中的 batch 查询,我们在底层的存储中,当发现 cache 中没有当前 block 时,会一次性读取当前范围内的多个 block。通过这样的方式我们能够尽可能最大限度地利用用满 S3 的带宽吞吐,同时由于 S3 按照 IO 个数收费,而流式接口只算做一次 IO,因此该优化也同时降低了 S3 的 IO 成本。通过一些简单的测试,该优化可以提升部分 OLAP 查询速度至多 8 倍。当然这只是极端情况下,还有很多复杂的 SQL 瓶颈在于计算操作,实际提升还取决于查询类型与业务场景。

4. 总结

除了查询性能以外,成本也是数据库所关注的重点。对于 AWS S3 这样的存储后端来说,除了存储数据按照大小每月固定收费以外,IO 操作按照次数收费。因此,除了优化性能以外,如何利用 S3 的高吞吐高延迟的特征,尽可能提高 S3 的使用效率来降低成本,也是我们优化存储系统的重要方向之一。接下来我们会根据查询计划的不同更加精确地选择 IO 策略来进一步提高处理速度,以及基于本地磁盘作为二级缓存来进一步提高命中率,减少对 S3 的访问频率。

5.关于 RisingWave

RisingWave 是一款分布式 SQL 流处理数据库,旨在帮助用户降低实时应用的的开发成本。作为专为云上分布式流处理而设计的系统,RisingWave 为用户提供了与 PostgreSQL 类似的使用体验,并且具备比 Flink 高出 10 倍的性能以及更低的成本。

🔧如果你还不知道如何上手 RisingWave,请体验中文入门教程:www.risingwavetutorial.com/

💻想要更深入地理解并使用 RisingWave,请阅读中文用户文档:zh-cn.risingwave.com/docs

相关推荐
superman超哥42 分钟前
Rust HashSet与BTreeSet的实现细节:集合类型的底层逻辑
开发语言·后端·rust·编程语言·rust hashset·rust btreeset·集合类型
Web项目开发1 小时前
Mysql创建索引的SQL脚本,复制粘贴即可使用
数据库·sql·mysql
2501_939909051 小时前
k8s基础与安装部署
云原生·容器·kubernetes
晴天¥1 小时前
Oracle如何在DBeaver上进行登录
数据库·oracle
2301_800256112 小时前
事务处理-同步与调度-两阶段锁-隔离级别
数据库·oracle
小罗和阿泽2 小时前
MySql数据库系列 数据库基础操作
数据库·mysql
superman超哥2 小时前
Rust String与&str的内部实现差异:所有权与借用的典型案例
开发语言·后端·rust·rust string·string与str·内部实现·所有权与借用
周末吃鱼2 小时前
mysql8.0支持CURRENT_DATE如何写
数据库·sql·mysql
kaico20182 小时前
MySQL的窗口函数
数据库·mysql
MM_MS2 小时前
Halcon控制语句
java·大数据·前端·数据库·人工智能·算法·视觉检测