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

314 阅读5分钟

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

数据格式层

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

分层视角下的数据形态

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

OLTP vs OLAP

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

  • 理解两者的区别可以帮助更好的理解行存和列存的设计背景

OLTPOLAP
典型场景在线业务系统,例如:订单、交易、社交、评论等数据仓库或者大数据分析系统,例如:决策分析、BI系统、推荐系统等
访问特征- 事务- 实时性- 低延时- 高并发- 高可用- 弱事务性- 近实时、离线分析- 大吞吐- 并发相对不高- 可用性可以有一定的妥协
数据模型特征- Schema 相对简单- 数据维度不多- 数据规模较小- Schema 复杂- 数据维度很多,几百个Column 很常见- 数据规模巨大

OLTP:行式存储格式 (行存)

  • 每一行 (Row) 的数据在文件的数据空间里连续存放的
  • 读取整行的效率比较高,一次顺序 IO 即可
  • 在典型的 OLTP 型的分析和存储系统中应用广泛,例如:MySQL、Oracle、RocksDB 等

OLAP:列式存储格式 (列存)

  • 每一列 (Column) 的数据在文件的数据空间里连续存放的
  • 读取整列的效率较高
  • 同列的数据类型一致,压缩编码的效率更好
  • 在典型的 OLAP 型分析和存储系统中广泛应用,例如:
    • 大数据分析系统:Hive、Spark,数据湖分析
    • 数据仓库:ClickHouse,Greenplum,阿里云 MaxCompute

Parquet详解

Parquet简介

  • 大数据分析领域使用最广的列存格式
  • Spark推荐存储格式

数据布局

  • rowgroup:每一行组包含一定数量或固定大小的行集合
  • columnchunk:rowgroup按照列切分成多个columnchunk
  • page:columnchunk内切分为page,一般建议8kb大小,压缩和编码的基本单元
  • footer:保存文件元信息

编码 encoding

  • plain 直接存储原始数据
  • Run Length Encoding(RLE):适用于列基数不大,重复值较多的场景
    • Bit-Pack Encoding:配合RLE使用,让整形数字存储更紧凑
  • 字典编码 Dictionary Encoding:适用于列基数不大的场景,构造字典表,写入到Dictionary Page,把数据用字典index替换然后用RLE编码
  • 默认parquet-mr会根据数据特征进行选择,也可以根据业务自定义

压缩 copression

  • page完成encoding后进行压缩
  • 多种算法
    • snappy压缩快、压缩比不高、适用于热数据
    • gzip:压缩慢、压缩比高、适用于冷数据
    • zstd压缩比跟gzip差不多,而且压缩速度比肩snappy
    • 建议选择snappy或zstd,根据业务数据类型充分测试压缩效果,以及对查询性能的影响

索引 index

  • 索引支持非常简陋
  • min-max index:记录page内column的min_value和max_value
  • column index:记录footer里column metadata包含columnchunk全部page的min-max value
  • offset index:记录page在文件中的offset和page的row range
  • bloom-filter
    • 对于列基数比较大、非排序列的过滤,min-max难发挥作用
    • bloom-filter加速过滤匹配判断
    • columnchunk头部保存bloom filter数据
    • footer记录filter的page offset

排序 ordering

  • 聚集索引
  • 帮助更好的过滤掉无关rowgroup或page,对少量数据seek有帮助
  • parquet format支持sorting columns
  • 依赖业务侧根据查询特征保证顺序

过滤下推 predicate pushdown

  • 依赖parquet-mr库实现,实现高效过滤机制
  • 引擎侧传入Filter Expression
  • parquet-mr转换成具体column的条件匹配
  • 查询footer内column index,定位到具体行号
  • 返回有效的数据给引擎侧

Spark集成-向量化读

  • ParquetFileFormat类
  • 主流大数据分析引擎的标准实践,可以极大提升查询性能
  • 以batch的方式从parquet读取,下推逻辑也适配batch形式

ORC详解

ORC简介

  • 大数据分析领域使用最广的列存格式之一
  • 出自于Hive 模型

数据模型

  • ORC会给包括根节点在内的中间节点都创建一个column
  • 嵌套类型或者集合类型与parquet差别较大
  • optional和repeated字段依赖父节点记录额外信息来重新assemble数据

数据布局

  • 类似parquet
  • rooter+stripe+column+page(rowgroup)结构
  • encoding/compression/index支持上与parquet基本一致

ACID特性

  • 支持Hive Transactions实现,只有Hive本身集成
  • 类似数据湖三剑客
  • 基于Base+Delta+compaction设计

AliORC

  • ORC在阿里云计算广泛应用
  • AliORC是ORC深度定制版
  • 索引增强
    • 支持clustered index,更快的主键查找
    • 支持bitmap index,更快过滤
      • roaring index
  • 小列聚合
    • 小列聚合,减少小IO
    • 重排chunk
  • 异步预取
    • 异步预取数据,计算逻辑和数据读取并行化

Parquet vs ORC 对比

  • 从原理层面,最大的差别就是对于 NestedType 和复杂类型处理上
  • Parquet 的算法上要复杂很多,带来的 CPU 的开销比 ORC 要略大
  • ORC 的算法上相对简单,但是要读取更多的数据
  • 因此,这个差异的对业务效果的影响,很难做一个定性的判定,更多的时候还是要取决于实际的业务场景

如何选择

  • 当前项目使用的??
  • 性能上很多情况下依赖于数据集和测试环境,不能迷信 Benchmark 结果
  • 根据实际业务做充分的测试调优
  • Spark 生态下 Parquet 比较普遍
  • Hive 生态下 ORC 有原生支持
  • 整体上,Spark 比 Hive 更加有优势,所以大部分情况下,Parquet 可能是个更好的选择