Parquet 和 ORC:高性能列式存储 | 青训营笔记

273 阅读4分钟

这是我参与「第四届青训营 」 笔记创作活动的第10天

回顾

  • 计算层:批式处理(Spark ),流式处理(Flink ),交互式分析(Presto)
  • 存储层:HDFS,对象存储(公有云数据存储)
  • 元数据管理,狭义数据湖

所有的大数据作业都可以简化为:

  1. 从存储层读取文件
  2. 计算层解析文件内容,运行各种计算算子
  3. 计算层输出结果,或者把结果写入存储层

1. 行存 vs 列存

数据格式层

  • 数据格式层:定义了存储层文件内部的组织格式,计算引擎通过格式层的支持来读写文件
  • 严格意义上,并不是一个独立的层级,而是运行在计算层的一个Library

img

分层视角下的数据形态

  • 存储层:File,Blocks
  • 格式层:File 内部的数据布局 (Layout + Schema)
  • 计算引擎:Rows + Columns

OLTP vs OLAP

  • OLTP 和 OLAP 作为数据查询和分析领域两个典型的系统类型,具有不同的业务特征,适配不同的业务场景

OLTP——行存

  • 每一行 (Row) 的数据在文件的数据空间里连续存放的
  • 读取整行的效率比较高,一次顺序 IO 即可
  • 典型应用:MySQL、Oracle、RocksDB

OLAP——列存

  • 每一列 (Column) 的数据在文件的数据空间里连续存放的
  • 同列的数据类型一致,压缩编码的效率更好
  • 典型系统:Hive、Spark,数据湖

总结

  • 格式层定义了数据的布局,连接计算引擎和存储服务
  • OLTP和OLAP场景使用数据存储格式不同,业务场景决定技术实现。OLTP——行存、OLAP——列存

2. Parquet 详解

  • 大数据分析领域使用最广泛的列存格式

数据模型

基于Dremel,Protocol Buffer 定义;支持可选和重复字段、嵌套类型。

文件布局

img

Footer+RowGroup+ColumnChunk+Page

数据编码Encodeing

page粒度,Plain/RLE、Dictionary

  • Run Length Encoding (RLE):适用于列基数不大,重复值较多的场景,例如:Boolean、枚举、固定的选项等

  • Bit-Pack Encoding: 对于 32位或者64位的整型数而言,并不需要完整的 4B 或者 8B 去存储,高位的零在存储时可以省略掉。适用于最大值非常明确的情况下。

    • 一般配合 RLE 一起使用
  • Dictionary Encoding:适用于列基数 (Column Cardinality) 不大的字符串类型数据存储;

    • 构造字典表,用字典中的 Index 替换真实数据
    • 替换后的数据可以使用 RLE + Bit-Pack 编码存储

压缩Compression

  • 发生时机:Page完成Encoding之后进行压缩

  • 多种压缩算法:

    • snappy: 压缩速度快,压缩比不高,适用于热数据
    • gzip:压缩速度慢,压缩比高,适用于冷数据
    • zstd:新引入的压缩算法,压缩比和 gzip 差不多,而且压缩速度略低于 Snappy
  • 建议选择 snappy 或者 zstd,根据业务数据类型充分测试压缩效果,以及对查询性能的影响

索引index和排序Ordering

  • 和传统的数据库相比,索引支持非常简陋。主要依赖 Min-Max Index 和 排序 来加速查找。

bloom filter索引

  • 使用场景:对于列基数比较大的场景,或者非排序列的过滤,Min-Max Index 很难发挥作用

排序Ordering

  • 类似聚集索引的概念

过滤下推Predicate PushDown

  • ParquetFileFormat 向量读
  • Dremel数据模型:Repetition Level

3. ORC

数据模型

基于Dremel

文件布局

img

  • 类似 Parquet,Rooter+Stripe+Column+Page
  • Encoding / Compression / Index 支持上和 Parquet 几乎一致

ACID

  • 支持 Hive Transactions 实现,目前只有 Hive 本身集成
  • 类似 Delta Lake / Hudi / Iceberg
  • 基于 Base + Delta + Compaction 的设计

AliORC

  • 索引增强,支持Clusterd Index,更快的主键查找;

  • 支持 Bitmap Index,更快的过滤

    • Roaring Bitmap
  • 小列聚合,减少小 IO;重排 ColumnChunk

  • 异步预取优化,计算逻辑和数据读取并行化

Parquet vs ORC 对比

  • 原理:最大的差别就是对于 NestedType 和复杂类型处理上

  • 算法:

    • Parquet 的算法上要复杂很多,带来的 CPU 的开销比 ORC 要略大
    • ORC 的算法上相对简单,但是要读取更多的数据

4.列存演进

  • 在ClickHouse数仓中的MergeTree引擎也是基于列存构建的,支持更丰富的索引方式
  • 存储侧下推,越接近数据,下推过滤的效率越高
  • Column Family支持,只更新需要修改的列