数据_数据格式_Parquet存储文件格式原理
应用三阶段
01.初步了解如何使用这种格式?
02.进一步如何优化这种格式
03.再然后是在面对新的问题时候,如何解决问题
格式具体是如何设计的,以及为什么这样设计?
这个系统为了解决什么问题?为此提供了什么功能?
数据持久化 是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称.
据持久化对象的基本操作有:保存、更新、删除、加载、查询等
二进制持久化
--序列化和反序列化 Parquet文件格式选用 thrift完成文件元数据的序列化和反序列化
--索引
数据模型
Parquet 的 数据模型 也是 schema 表达方式, Parquet文件格式选用 thrift完成文件元数据的序列化和反序列化。
在parquet-format项目的thrift目录下,文件parquet.thrift详细定义了parquet文件的元数据类型 用关键字 message 表示
schema协议
采用类似于Protobuf 协议来描述,每个字段有三个属性:重复性(Repetition)、类型 (Type)和名称 (Name)
optional 可选,required 必需和 repeated 重复字段
Parquet的设计者引入了两个新的概念:
repetition level 和 definition level。这两个值会保存额外的信息,可以用来重构出数据原本的结构
repetition level主要用来表达数组类型字段的长度,但它并不直接记录长度,而是通过记录嵌套层级的变化来间接地表达长度
repetition level主要用来表达数组的长度
definition level主要用来表达null的位置
对非数组类型的值不保存repetition level”,“对必填字段不保存definition level”等,真正存储这两个level时,也使用的是bit-packing + RLE编码
工程实现
Parquet 的 存储模型 主要由行组(Row Group)、列块(Column Chuck)、页(Page)组成
这个系统为了解决什么问题?为此提供了什么功能?
实质:列式存储一个类型包含嵌套结构的数据集。
Header data index Footer
data: Row-group
ColumnChunk ColumnChunk ColumnChunk
page page page page page
01.存储的对象是一个数据集,而这个数据集往往包含上亿条record,所以我们会进行一次水平切分,把这些record切成多个“分片”,每个分片被称为Row Group
02.水平切分之后,就轮到列式存储标志性的垂直切分
repetition level 和 definition level。
把一个嵌套结构打平以后拆分成多列,其中每一列的数据所构成的分片就被称为Column Chunk
03.Page是Parquet文件最小的读取单位,同时也是压缩的单位
Column Chunk,Parquet会进行最后一次水平切分,分解成为一个个的Page。每个Page的默认大小为1m
Header的内容很少,只有4个字节,本质是一个magic number,用来指示文件类型
“PAR1”代表的是普通的Parquet文件,
“PARE”代表的是加密过的Parquet文件。
Index是Parquet文件的索引块,主要为了支持“谓词下推”(Predicate Pushdown)功能
Parquet的索引有两种 一种是Max-Min统计信息,一种是BloomFilter
Footer是Parquet元数据的大本营,包含了诸如schema,Block的offset和size,Column Chunk的offset和size等所有重要的元数据。
另外Footer还承担了整个文件入口的职责
元数据信息存储在数据之后,包含了所有列块元数据信息的起始位置。
读取的时候首先从文件末尾读取文件元数据信息,再在其中找到感兴趣的 Column Chunk 信息,并依次读取
Block-File Parquet 是以二进制存储数据
Parquet 不使用任何分隔符来分隔数据。相反,它依赖于编码和压缩方案来有效地存储和检索数据
Parquet 常用的编码技术包括:
字典编码(dictionary encoding)
Run-length encoding(RLE):用来优化具有重复值的列
位打包(bit packing):用来优化具有小整数值的列
Parquet 中常用的压缩算法有 Snappy、Gzip 和 LZO
序列化阶段
1.使用编程语言内置的序列化机制
2.使用一种广泛支持的、与语言无关的格式,比如 JSON (或者 XML
3.使用Thrift, Protocol Buffers 或 Avro 高效的跨语言数据序列化和代码生成
Thrift、ProtoBuf 和 Avro 都支持模式演进--用于接口和数据升级
Avro 和 ProtoBuf 标准化了单一的二进制编码,
而 Thrift 则 包含 了各种不同的序列化格式(它称之为“协议”)
Iceberg数据存储格式
Iceberg 是一个分布式列式存储库
开放式表格式则充当元数据抽象层
1.Iceberg表结构
Table Tablet Snapshot
Manifest Partition Block
表(Table):存储数据的逻辑单元 Tablet(分片 Snapshot(快照):代表一个Table在某个时间点的数据状态,由一份或多份Tablet组成
Manifest(清单):描述Table状态的元数据,包括Table的Schema(模式)、Partition Spec(分区规范)和Current Snapshot ID(当前快照ID)等信息。
Partition(分区):将数据按照指定规则分隔成的逻辑单元,
Block(块):其中存储的是Partition的数据,每个块都有一个唯一的ID,块的大小可以在表级别进行配置
每一个 snapshot 对应一组 manifest,每一个 manifest 再对应具体的数据文件
2. Iceberg数据文件 是指实际存储表格数据的文件,通常以Parquet格式存储
3. Snapshot 表快照 :记录了表格在某个特定时间点的状态和元数据信息,包括架构、分区规则、数据文件等等。
data files 数据文件 是实际存储表格数据的文件,通常以Parquet格式存储
Manifest 清单列表 :是Iceberg表格的所有数据文件的列表,包括数据文件的元数据信息,如大小、数据量、创建时间、分区信息等等。
CyberRT_Recorder和ROS_Bag
Bag 的设计思路
消息的保存和读取 就涉及到一个广义上的问题序列化和反序列化
序列化 :
反序列化; 通过消息类型名称(字符串)来生成对象,这在很多语言中叫做反射(reflection
何快速的查找-索引
把一个包拆分为几个块(Chunk),而chunk中有消息的时间段
index data则更进一步,直接索引了不同类型的消息在块中的时间戳和偏移
1.消息的持久化
01.序列化和反序列化
02.消息索引
2. 序列化和反序列化
Rosbag的序列化和反序列化是自己实现的,ros是单个消息序列化,apollo是整个chunk序列化
apollo record则采用了protobuf来进行序列化和反序列化
3.消息索引
4.功能
Bag header 头信息放在文件首部,
Chunk info 块的索引和消息元信息的索引都是放在文件的末尾-2个统计record都会保存在文件末尾。
Index data
具体示例
Rosbag storage format
概念:
Bag
header_len/header/data_len/data
header/Chunk/Connection/Message data/Index data/Chunk info
Rosbag 文件由许多的record组成,每个record由header和data组成, header和data,还需要保存header_len和data_len
六种 record
Bag header(op=0x03) Message data(op=0x02) Index data(op=0x04) Chunk(op=0x05) Chunk info(op=0x06) Connection(op=0x07)
Chunk 用来存储链接(connection)和消息数据(message data)
信息头(Headers)。每个记录头包含一系列 name=value 字段 Op 码所有的信息头必须包含Op码字段
record0 Bag header 主要存放bag包整体的信息,必须是第一个 record
record1:
Message data 块的结构之一,消息序列化之后以二进制存储,
通过Connection获取消息格式后进行反序列化
Connection 块的结构之一,存放信息的格式信息,有了消息的格式,才能解析消息
Chunk 主要的数据结构,可以被压缩,可以理解为把N个消息打包为一个块(Chunk) 一个块中可能有多种不同的消息
Chunk info 块的结构之一,主要描述块的信息,例如消息的起始和结束时间等
Index data 索引数据,因为一个块比较大,索引消息在块中的位置
数据结构的读取顺序为:
先解析 Bag header,获取到 index_pos
然后跳到 index_pos 读取 Connection
接着读取 Chunk info,上述2个步骤相当于建立起了整个Bag包,块的索引
接着根据 Chunk info 逐个读取 Chunk ,先解析Chunk,获取压缩类型和数据大小
接着跳到 Chunk 尾部解析 Index data ,这里是一个消息对应一个 index
最后根据 index data 实例化消息(通过接口 instantiateBuffer )
CyberRT Record文件由许多的 Section 组成
Header
Section Type: ChunkHeader ChunkBoady RecordInfo Index Channel
Section 0:第一个Section 0为HEADER类型。Header中指明了索引区Index的位置
Section 1:
Index Data 包含一个SingleIndex类型数组,作为Section的索引,保存了Channel、ChunkHeader、ChunkBody三种Section的位置和简要数据。
record.proto中并不存在Chunk这个结构,而是用ChunkHeader和ChunkBody两部分来表示。
现代数据湖仓架构
Apache Iceberg 其定义特性之一是元数据与数据的分离,允许高效的基于快照的隔离和规划。
三个关键组件之上:存储层、开放式表格式和计算引擎
引入了 Iceberg 来支持模式演进、特征回填和并发读写
最开始反序列化为 Arrow ,后续的操作就完全基于 Arrow 进行,从而降低了序列化和反序列化开销,进一步提升训练速度
Parquet 并不支持数据回填
开放式表格式和对象存储正在重新定义组织构建其数据系统
ADS:applicationData Service应用数据服务
DW DWD,DWB,DWS DWD:data warehouse details DWB:data warehouse base 数据基础层 DWS:data warehouse service 数据服务层
ODS:Operation Data Store 数据准备区
基于 Protobuf 定义的半结构化数据
比较典型的就是小文件问题和存储成本问题
小文件问题是怎么产生的
如何解决小文件问题
小文件合并的核心是
如何把一个分区下的多个 Parquet 小文件合并成一个,
由于 Parquet 格式具有特殊的编码规则,文件内部被划分为多个功能子模块,我们不能直接把 2 个 Parquet 文件首尾拼接进行合并
借鉴了 Parquet 社区所提供的 merge 工具
一类是被压缩和编码后的实际数据,而另一类则是记录了数据是如何被编码和排列的元数据。
快速合并 相比于 普通合并
参考
详解Parquet文件格式原理 https://zhuanlan.zhihu.com/p/538163356
Cyber_数据解析—Apollo_Record&rosbag保存格式
Rosbag格式分析 https://zhuanlan.zhihu.com/p/494474804
字节跳动基于Iceberg的海量特征存储实践 https://www.163.com/dy/article/HNF0BBCR0511CUMI.html
分类:
数据存储和消息系统
, Python_Java_数据开发
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
2021-01-13 Spark开发-Spark中的设计模式_创建型模式大类
2021-01-13 数据开发_工程化UML以及设计模式