doris的使用
doris的使用
初步概念
doris是一款具有大规模并行处理(mpp)架构,支持存算一体,存算分离,具有特有的查询引擎和存储引擎的实时分析型数据库。doris的衍生产品有starrocks,同种类似产品有clickhouse。
FE,BE的具体作用:
在存算一体的模型中:
FE:响应用户请求,查询解析,表元数据的管理,节点管理等;划分了leader,follower,observer三种角色
BE:数据存储,任务的执行,数据会被切分成数据分片(Shard),在 BE 中以多副本方式存储。
doris的数据模型,存储引擎,查询引擎
存储引擎(借鉴apache orcfile)
3.0版本开始支持存算分离,之前为存算一体。
采用 Segment v2 的形式来存储数据,其结构主要分为数据区、索引区和页脚三个部分。数据区存储各列的数据,按需分页加载;索引区存储列的索引数据,按列粒度加载;页脚包含文件的元数据信息,如SegmentFooterPB、校验和以及FileFooterPB 的长度
apache doris文件分布:
plaintext表(Table) ├── 分区(Partition) -- 第一级:按业务维度划分(如时间) │ ├── 分桶(Bucket) -- 第二级:按哈希均匀分布(如用户ID) │ │ ├── RowSet -- 第三级:写入时的逻辑单元(内存/临时) │ │ │ └── Segment -- 第四级:持久化的物理文件(磁盘) │ │ └── ... │ └── ... └── ...
每张表可以创建不同的分区,但是doris只能创建一级分区,每个分区下按照不同列取hash或者random打散创建不同的桶,也称为tablet;每个tablet划分不同的rowset;依托列式存储的概念,rowset划分不同segment,segment是最小的数据单元;
数据模型(借鉴google masa)
参考:doris数据模型介绍
数据模型中明细模型,主键模型,聚合模型的排序键作用: 明细模型中排序键只具有排序的功能;在主键模型和聚合模型同时具有排序,聚合的功能
-
分区策略 分区类型:
- range分区:按照分区列的值范围将数据划分到对应的分区,Range 分区支持的列类型 DATE, DATETIME, TINYINT, SMALLINT, INT, BIGINT, LARGEINT
- list分区:按照分区列的具体值划分到对应分区,类型支持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, VARCHAR ,枚举类型 的数据类型
分区模式:
- 手动分区 用户手动创建分区(如建表时指定或通过
ALTER语句增加 - 自动分区 系统根据时间调度规则自动创建分区,但写入数据时不会按需创建分区
- 动态分区 数据写入时,系统根据需要自动创建相应的分区,使用时注意脏数据生成过多的分区
-
分桶策略
- hash 通过计算分桶列值的
crc32哈希值,并对分桶数取模,将数据行均匀分布到分片中 - random 随机分配数据行到分片中
分桶数量的设置: 主要坚持大小原则:建议一个 tablet 的大小在 1-10G 范围内,即分桶的大小,通常选择4-5G。合理预估存量数据和未来数据的增长趋势得出一定时间范围总量,结合分桶在分区的存储下,再根据 每个分桶4-5G的选择预估分桶数
目前,Doris 仅支持修改新增分区的分桶数量,对于以下操作暂不支持:
-
不支持修改分桶类型
-
不支持修改分桶键
-
不支持修改已创建的分桶的分桶数量
- hash 通过计算分桶列值的
-
支持的数据类型
doris支持常用的绝大部分类型,其中BITMAP,HLL为比较新颖的数据类型
-
数据压缩 doris默认采用LZ4的压缩编码,可以根据各自的场景选择不同的压缩算法,实现存储优化和加速查询。 影响压缩比的主要因素有:
- 数据排序性 数据有序一般比无序更好压缩
- 数据重复性
- 数据的类型
- ......
LSM-tree 与 B-Tree 的设计及应用对比
1. 问题背景:写放大 (Write Amplification)
- 定义: 写放大是指存储系统物理层面实际写入的数据量与应用程序逻辑层面请求写入的数据量之间的比值。该比值大于1即表示存在写放大。
- 成因: 主要源于存储介质(特别是NAND Flash SSD)的物理特性。SSD以页(Page)为单位写入,以块(Block)为单位擦除。更新页内一小部分数据,必须将包含该页的整个块读取到内存,修改数据,然后将整个更新后的块写回一个新的空闲位置。这个“读-改-写”(Read-Modify-Write)的循环是写放大的主要来源。,比如HDFS
- 负面影响:
- 降低I/O吞吐量: 占用了额外的I/O带宽,限制了系统的写入性能。
- 缩短硬件寿命: 加速了闪存介质的磨损,因为其擦写次数(P/E Cycles)有限。
2. 解决方案:LSM-tree (Log-Structured Merge-Tree)
- 核心思想: 将离散的、随机的写入请求转化为批量的、顺序的写入操作,从根本上规避了存储介质的“读-改-写”惩罚。
- 架构组件:
- MemTable: 位于内存中的数据结构(通常是平衡树或跳表),用于缓冲新的写入操作(Insert, Update, Delete)。所有写请求首先进入此处,响应速度极快。
- Immutable MemTable: 当MemTable达到预设阈值时,会转化为一个不可修改的副本,准备持久化。
- SSTable (Sorted String Table): 持久化在磁盘上的、不可变且内部有序的数据文件。Immutable MemTable会通过顺序I/O被刷写(Flush)成一个新的SSTable。
- Compaction (合并): 后台进程,周期性地将多个层级的SSTable文件进行归并。此过程会清理冗余数据(被覆盖的旧值、已删除的记录),并生成新的、更大的SSTable,以优化存储空间和读取性能。
3. LSM-tree的权衡:读放大 (Read Amplification)
- 定义: 为响应单个逻辑读取请求,存储系统需要执行多次物理读取操作的现象。
- 成因: 由于数据的最新版本可能分布在内存的MemTable以及磁盘上多个层级的SSTable中,一次查询必须从新到旧(从MemTable到高层级SSTable,再到低层级SSTable)依次查找,直到找到目标数据。
- 优化手段:
- 布隆过滤器 (Bloom Filter): 一种概率型数据结构,能快速判断一个SSTable中“绝对不包含”某个键,从而避免不必要的磁盘I/O。
- 索引块 (Index Block): 在SSTable内部存储稀疏索引,帮助快速定位数据大致所在的块。
4. 对比数据结构:B-Tree
- 核心思想: 始终维持数据全局有序的平衡多路搜索树。数据更新采用“就地更新”(In-place Update)策略。
- 写入机制: 插入或更新数据时,需要先通过树的遍历定位到目标叶子节点,然后执行修改。如果节点空间不足,会引发节点分裂(Split)和树的再平衡(Rebalancing),这些操作可能级联向上传播,导致多次随机I/O。这正是B-Tree产生较高写放大的原因。
- 读取机制: 读取路径非常高效。由于全局有序,从根节点开始,仅需几次磁盘寻道(通常与树的高度成对数关系)即可精确定位数据。
5. 两种核心策略的对决:Merge-on-Write vs. Merge-on-Read
| 策略模型 | 核心机制 | 写入路径 | 读取路径 | 写放大 | 读放大 | 适用场景 | 代表 |
|---|---|---|---|---|---|---|---|
| 写时归并 (Merge-on-Write) | 写入数据时立即合并/更新,保证存储数据始终是最新、最规整的单一版本。 | 复杂且慢,涉及随机读写和数据重组。 | 简单且快,直接读取最终版本。 | 高 | 低 | 读密集型 (Read-Intensive) | B-Tree |
| 读时归并 (Merge-on-Read) | 写入时只进行追加(Append-only),将数据合并的复杂性推迟到读取时或后台处理。 | 简单且快,主要是顺序写入。 | 复杂且慢,需要读取多个版本并动态归并。 | 低 | 高 | 写密集型 (Write-Intensive) | LSM-tree |
6. 实例分析:LSM-tree 在 Apache Doris 中的应用
Doris 通过类似 LSM-Tree 的结构写入数据,在后台通过 Compaction 机制不断将小文件合并成有序的大文件,同时也会处理数据的删除、更新等操作,解决写放大问题,Doris 主键 (unique) 模型,从 Doris 2.0 开始,除了原来的 Merge-on-Read(MoR),也引入了 Merge-on-Write(MoW)的存储方式,MoR 是为了写入做优化,而 MoW 是为了更快的分析性能做优化
查询引擎(借鉴apache impala)
采用大规模并行处理(MPP)架构,支持节点间和节点内并行执行,以及多个大型表的分布式 Shuffle Join;Doris 查询引擎是向量化引擎,所有内存结构均按列式布局等
索引
doris为查询加速引入了索引的设计。常用索引如下
-
倒排索引
-
前缀索引
-
BloomFilter 索引
不同的索引对不同的运算符和触发条件有不同的要求:
行列混存
doris的使用列式存储数据,对于条件过滤,排序,分区性能很好,但是对于点查(select * from table)需要需要读取全部的列,每个列的读取都需要一次IO,对于宽表(比如上百列的DWS表)影响较大;
故使用行列混存(行存的原理是在存储时增加了一个额外的列,这个列将对应行的所有列拼接起来采用特殊的二进制格式存储),应对点查的场景
store_row_column 设置是否开启行列混存,以及一些额外混存的参数设置
物化视图
物化视图是既包含计算逻辑也包含数据的实体。它不同于视图,因为视图仅包含计算逻辑,本身不存储数据。
其中一个使用场景
物化视图的优点:
-
数据同步:拥有自动或手动的刷新机制,可以与基表(如图中的维表1-4)保持数据同步。刷新可以是全量的,也可以是增量的
-
查询优化:具备智能的查询改写能力。当用户查询基表时,数据库可以自动判断并“智能地”重定向查询到物化视图,从而利用预计算的结果加速查询,这个过程对用户透明
版权声明