版本 | 日期 | 备注 |
---|---|---|
1.0 | 2024.2.26 | 文章首发 |
- Hive上的计算执行首先依赖于list操作。在对象存储上做list是个很慢的操作。
- Hive的写数据依赖于rename。但同样这个操作在对象存储上做特别的慢。
这两个问题直接导致无法降本。从这点上来说,Iceberg是自己维护了一套元数据,这块网上非常的全,就不再赘述了,google上搜iceberg file layout
一大把。
Hive还有其他的问题,如:
- metastore的瓶颈问题。
- 没有ACID保证。
- parition字段必须显示的在query里。
- 下推能力有限。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产物。但结合上文,Paimon具有一定的随机读写能力。 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的强大与不足之处。 目前该项目还处于孵化中,后续我会一直关注其实现细节,敬请期待。