读Paimon源码聊设计:引子

最近我司开始探索Paimon在部分场景下的使用,因此我这边需要做一些技术储备,慢慢关注起来Paimon的一些实现细节。

简单介绍一下前辈Iceberg

一般的数据湖都会设计成开放通用的,即不和特定的存储、计算引擎(比如Spark和Flink)绑定。所以数据湖的定位是在计算引擎之下,又在存储之上,将其称之为table format。需要强调的是数据湖一般是面向OLAP场景的,所以一般存储会选择分布式文件系统。现在OLAP底层存储支持对象存储基本算是快成业界共识了,这玩意儿挺划算的。

数据湖的前辈基本就是Hive了。当时大家用Hive碰到的问题就是Hive耦合HDFS很厉害,最主要体现在:

  1. Hive上的计算执行首先依赖于list操作。在对象存储上做list是个很慢的操作。
  2. Hive的写数据依赖于rename。但同样这个操作在对象存储上做特别的慢。

这两个问题直接导致无法降本。从这点上来说,Iceberg是自己维护了一套元数据,这块网上非常的全,就不再赘述了,google上搜iceberg file layout一大把。

Hive还有其他的问题,如:

  1. metastore的瓶颈问题。
  2. 没有ACID保证。
  3. parition字段必须显示的在query里。
  4. 下推能力有限。Hive只能通过partition和bucket对需要扫描哪些文件进行过滤,无法更加细致。尽管parquet文件里保存了max和min值可以用于进一步的过滤,但没软用。

Iceberg把这些都解了。基于快照实现事务、数据的更新,快照的数据也允许跳版本读取来做时间回溯。同时收集的统计信息也更加细粒度,不仅仅是文件parition级别的,还会记录文件级的内容(比如一个文件中的min、max值)和实现文件内容级的信息------一个文件中的min、max等等。

听起来一切都还很美好。唯一美中不足的就是Iceberg对于实时场景支持得不好:

  • Flink写入Iceberg会引发小文件的问题。
  • Iceberg不支持CDC(OLAP支持CDC的确有点离谱,但是的确有需求呀)。
  • Iceberg主键表不支持部分字段更新。这在实时数仓的场景中有点离谱。

Paimon可以解决什么问题

目前看来Paimon基于Iceberg的场景上,去支持流读流写(这块后续会做源码分析),甚至还支持了点查和预聚合。本质是分布式文件系统上套了一个LSM,这样数据都是有序写入------将多次写入优化成一次顺序写入,对存储系统上比较友好的。同时LSM可以作为一个简单的缓存,且有序写入为后面查询也可以减少代价,这都可以为查询减少代价。

从场景上来说它可以解决一些准实时业务的场景。因为基于对象存储来做底层存储,尤其还是列式存储。无论如何都不好做到实时场景:

  • Paimon的CDC根据不同的模式,会有不同的新鲜度。发出完整CDC的模式要选择Lookup。一般是Checkpoint的间隔+10s多新鲜度,这是比较好的性能考量下。具体还要看数据量、分桶数、小文件数量的影响。
  • 实时场景要求是毫秒级点查响应。Paimon支持的是秒级点查。

但现实中真正需要实时类场景的业务有多少呢?因为数据的新鲜度往往和业务决策周期有关系。这么来看,数据新鲜度的要求从高到低,对于业务场景的总数来说,一定是一个金字塔形状的。

我们前面提到过数据湖一般不会和任何计算引擎绑定。因此业界还有一种玩法叫湖上建仓,计算能力用的是OLAP,数据来自数据湖。这样就很有想象力了,因此现在一些实时+离线的场景会用不同的存储引擎,那么数据就会拷贝好几份。如果数据都放在同一个数据引擎中,这样可以减少不少的存储成本。(对于通用型设计 这块后续会做源码分析

具体实现还是看对于性能的要求的:

  • 要求低就做一些简单的优化直接捞数据。
  • 再高点就缓存到OLAP里。
  • 再高点就不仅仅是缓存到OLAP里,还会做物化视图。

Trade Off

Serving、Trascantion、Analytics

根据业界常识,我们会发现:

  • 面向在线应用,高并发、快速、简单,如:HBase、Redis
  • 面向分析的,大规模数据扫描、过滤、汇总,如:Hive、Presto
  • 面向事务、随机读写的,如:MySQL,PostgreSQL

数据湖是典型的OLAP产物。但结合上文,它的确具有一定的随机读写能力。

Buffer、Mutable、Ordered

存储结构有三个常见变量:是否使用缓冲、使用不可变的还是可变的文件,以及是否按顺序存储值(有序性)。

由于TiDB底层的RocksDB用了LSM。因此使用了缓冲、不可变性以及顺序性。

RUM

有一种流行的存储结构开销模型考虑了如下三个因素:读取(Read)、更新(Update)和内存(Memory)开销。它被称为RUM猜想。

RUM猜想指出,减少其中两项开销将不可避免地导致第三项开销的恶化,并且优化只能以牺牲三个参数中的一个为代价。我们可以根据这三个参数对不同的存储引擎进行比较,以了解它们针对哪些参数进行了优化,以及其中隐含着哪些可能的权衡。

一个理想的解决方案是拥有最小的读取开销,同时保持较低的内存与写入开销。但在现实中,这是无法实现的,因此我们需要进行取舍。

Paimon允许在配置中自由设置LSM的高度,以便获取读与写之前的权衡。

内幕鸟瞰

前面说到过,计算部分是依赖于计算引擎实现的,本身Paimon没有提供计算能力。存储则是基于部分是文件系统做了薄薄的一层LSM。

从文件布局来看,Partition相当于是一级索引,和Hive一样。Bucket为二级索引,每个Bucket下都会有Data file和Change log file。这意味着如果命中了Parition和Bucket条件,有一些额外的条件查询也不会太慢------一般都会收集文件级的统计信息,并对文件的Reader做一些过滤优化。

整体的布局还是和Iceberg挺像的,这边不再过多赘述。

小结

在这篇文章中我简单的介绍了一下Paimon要解决的问题,以及它的前辈Iceberg的强大与不足之处。

目前该项目还处于孵化中,后续我会一直关注其实现细节,敬请期待。

相关推荐
加油,旭杏6 分钟前
【go语言】grpc 快速入门
开发语言·后端·golang
brzhang26 分钟前
墙裂推荐一个在 Apple Silicon 上创建和管理虚拟机的轻量级开源工具:lume
前端·后端
一张假钞34 分钟前
Spark的基本概念
大数据·分布式·spark
一张假钞40 分钟前
Spark On Yarn External Shuffle Service
大数据·分布式·spark
沈韶珺2 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺2 小时前
Perl语言的函数实现
开发语言·后端·golang
美味小鱼2 小时前
Rust 所有权特性详解
开发语言·后端·rust
我的K84092 小时前
Spring Boot基本项目结构
java·spring boot·后端
慕璃嫣3 小时前
Haskell语言的多线程编程
开发语言·后端·golang
晴空๓3 小时前
Spring Boot项目如何使用MyBatis实现分页查询
spring boot·后端·mybatis