这是我参与「第四届青训营 」笔记创作活动的第13天
数据格式层
- 数据格式层:定义了存储层文件内部的组织格式,计算引擎通过格式层的支持来读写文件
- 严格意义上,并不是一个独立的层级,而是运行在计算层的一个Library
分层视角下的数据形态
- 存储层:File,Blocks
- 格式层:File 内部的数据布局 (Layout + Schema)
- 计算引擎:Rows + Columns
OLTP vs OLAP
-
OLTP 和 OLAP 作为数据查询和分析领域两个典型的系统类型,具有不同的业务特征,适配不同的业务场景
-
理解两者的区别可以帮助更好的理解行存和列存的设计背景
| OLTP | OLAP | |
|---|---|---|
| 典型场景 | 在线业务系统,例如:订单、交易、社交、评论等 | 数据仓库或者大数据分析系统,例如:决策分析、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 可能是个更好的选择