赞
踩
基于Apache Doris在读写流程、副本一致性机制、存储机制、高可用机制等概念进行整理:
Doris 支持两层数据划分:
也可以仅使用一层分区,建表时如果不写分区的语句即可,此时 Doris会生成一个默认的分区,对用户是透明的。示意如下:
多个Tablet在逻辑上归属于不同的分区(Partition),一个 Tablet 只属于一个 Partition,而一个 Partition 包含若干个 Tablet。因为 Tablet 在物理上是独立存储的,所以可以视为 Partition 在物理上也是独立。从逻辑上来讲,分区和分桶最大的区别就是分桶随机分割数据库,分区是非随机分割数据库。
为了提高保存数据的可靠性和计算时的性能,Doris 对每个表复制多份进行存储。数据的每份复制就叫做一个副本。Doris 按 Tablet 为基本单元对数据进行副本存储,默认一个分片有3个副本。建表时可在 PROPERTIES
中设置副本的数量:
- PROPERTIES
- (
- "replication_num" = "3"
- );
下图示例,有两个表分别导入 Doris,表 1 导入后按 3 副本存储,表 2 导入后按 2 副本存储。数据分布如下:
为了分桶裁剪,并且避免数据倾斜,同时也为了分散读 IO,提升查询性能,可以将 Tablet 的不同副本分散在不同机器上,查询时可以充分发挥不同机器的 IO 性能。
Doris的每次导入可视为一个事务,会生成一个RowSet。而 RowSet 又包括多个 Segment,即Tablet --> RowSet -->Segment,那BE是如何存储这些文件的呢?
Doris 通过 storage_root_path
进行存储路径配置,Segment 文件存放在 tablet_id
目录下按 SchemaHash 管理。Segment 文件可以有多个,一般按照大小进行分割,默认为256M。存储目录以及Segment文件命名规则为: ${storage_root_path}/data/${shard}/${tablet_id}/${schema_hash}/${rowset_id}_${segment_id}.dat
进入 storage_root_path
目录,可以看到如下存储结构:
${shard}
:即上图中的 0、1。是存储目录下 BE 自动创建的,是随机的。会随着数据的增多而增多。${tablet_id}
:即上图中的 15123、27003 等,即上面提到的 Bucket 的 ID。${schema_hash}
:即上图中的 727041558、1102328406 等。因为一个表的结构可能会被变更,所以对每个 Schema 的版本生成一个 SchemaHash
,来标识该版本下的数据。${segment_id}.dat
:其中前面的为 rowset_id
,即上图中的 02000000000000e3ba4924368a21695d8cc3cf8525f80789;${segment_id}
为当前 RowSet 的 segment_id
,从 0 开始递增。Segment 整体的文件格式分为数据区域、索引区域、Footer三个部分,如下图所示:
1)如果是使用聚合类的表模型(AGGREGATE、UNIQUE),Delete 操作只能指定 Key 列上的条件;
2)该操作会同时删除和此 Base Index 相关的 Rollup Index 的数据。
简单来讲,Merge on Write(写时合并)的处理流程是:
下面介绍一下写入流程和读取流程的实现。
写入流程:写入数据时会先创建每个Segment的主键索引,再更新 Delete Bitmap。
读取流程:Bitmap 的读取流程如下图所示,从图片中我们可知:
UNIQUE模型Update过程本质上是 Select+Insert。
目前 Doris 主要支持两类索引:
其中ZoneMap索引是在列存格式上,对每一列自动维护的索引信息,包括 Min/Max,Null 值个数等等。这种索引对用户透明。
doris 中将各个列的index数据统一存储在 segment文件的 index region,这里的数据会按照列粒度进行加载,所以跟列的数据信息分开存储。这里以short key index 前缀索引为例进行介绍。
short key index 前缀索引,是在key(aggregate key、uniq key 和 duplicate key)排序的基础上,实现的一种根据给定前缀列,快速查询数据的索引方式。这里 short key index 前缀索引也采用了稀疏索引结构,在数据写入过程中,每隔一定行数,会生成一个索引项。这个行数为索引粒度默认为 1024 行,可配置。该过程如下图所示:
其中,KeyBytes 中存放了索引项数据,OffsetBytes 存放了索引项在 KeyBytes 中的偏移。
Short Key Index 采用了前 36 个字节,作为这行数据的前缀索引。当遇到 VARCHAR 类型时,前缀索引会直接截断。 Short Key Index 采用了前 36 个字节,作为这行数据的前缀索引。当遇到 VARCHAR 类型时,前缀索引会直接截断。
在查询一个 Segment 中的数据时,根据执行的查询条件,会对首先根据字段加索引的情况对数据进行过滤。然后在进行读取数据,整体的查询流程如下:
row_bitmap
中。row_bitmap
求交过滤。row_bitmap
求交过滤。row_bitmap
之后,批量通过每个Column 的 OrdinalIndex 找到到具体的 Data Page。Doris 通过 Compaction将增量聚合RowSet文件提升性能,RowSet的版本信息中设计了有两个字段 Start、End 来表示 Rowset 合并后的版本范围。未合并的Cumulative RowSet 的版本Start 和 End 相等。Compaction时相邻的 RowSet 会进行合并,生成一个新的 RowSet,版本信息的 Start、End 也会进行合并,变成一个更大范围的版本。另一方面,Compaction流程大大减少RowSet文件数量,提升查询效率。
如上图所示,Compaction 任务分为两种,Base Compaction(基线合并) 和 Cumulative Compaction(增量合并),cumulative _point
是分割两种策略关键。
可以这样理解:
cumulative_point
右边是从未合并过的增量 RowSet,其每个 RowSet 的Start 与 End 版本相等;cumulative_point
左边是合并过的 RowSet,Start 版本与 End 版本不等。Compaction是按照什么 Key 来的?
为了实现跨集群数据复制功能,Doris 引入了 Binlog机制。通过 Binlog 机制自动记录数据修改记录和操作,以实现数据的可追溯性,同时还可以基于Binlog回放机制来实现数据的重放和恢复。
在开启 Binlog属性后,FE 和 BE 会将 DDL/DML 操作的修改记录持久化成 Meta Binlog 和 Data Binlog。
rowset_meta
为前缀的 KV 中,并持久化到 Meta 存储中,提交后会把导入的 Segment Files 链接到 Binlog 文件夹下。元数据层面,Doris 采用 Paxos 协议以及 Memory + Checkpoint + Journal 的机制来确保元数据的高性能及高可靠。
元数据的数据流具体过程如下:
key-value
的形式写入 BDBJE。其中 Key 为连续的整型,作为 log id
,Value 即为序列化后的操作日志。解释:
参考文章:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。