1. 存储引擎定位与设计目标
Apache Doris 是一个 MPP 架构的实时 OLAP 数据库,其存储引擎需同时满足:
- 高吞吐写入(支持 Kafka、Routine Load、Broker Load 等)
- 低延迟查询(亚秒级响应)
- 强一致性与高可用
- 高效压缩与 I/O 优化
- 自动运维(Compaction、副本修复、负载均衡)
为此,Doris 存储引擎采用 LSM-Tree 思想 + 列式存储 + 多版本并发控制(MVCC) 的混合架构,在 写性能、读性能、存储效率 之间取得平衡。
2. 整体架构:分层与核心组件
Doris 存储引擎运行在 BE(Backend)节点 上,核心模块如下:

2.1. StorageEngine(存储引擎入口)
- 定义于 be/src/olap/storage_engine.h
- 负责管理所有 Tablet 生命周期、数据目录映射、Compaction 调度
- 单例模式,是 BE 存储层的“中枢神经系统”
2.2. Tablet(数据分片)
- 最小物理存储单元,也是副本管理的基本单位
- 一个 Partition 被划分为 N 个 Bucket,每个 Bucket = 1 个 Tablet(多副本 = 多 Replica)
- 每个 Tablet 包含多个 Rowset(版本化数据集合)
2.3. Rowset(版本化数据集)
- 一次导入(Load)或 Compaction 生成一个 Rowset
- 具有 版本号(Version),如 [10-10], [11-11], [10-11](后者为合并结果)
- 内部由 1~N 个 Segment 文件 组成
- 支持状态机管理:UNLOADED → LOADED → UNLOADING
2.4. Segment(物理文件)
- 默认大小 256MB(可配置)
- 采用 自研列存格式 Segment V2
- 包含:Data Region(数据页)、Index Region(索引页)、Footer(元数据)
3. 数据组织模型:从逻辑到物理
Doris 采用 四级数据组织模型:
|
层级 |
说明 |
示例 |
|
Table |
逻辑表 |
user_behavior |
|
Partition |
逻辑分区(RANGE/LIST) |
p202501, p202502 |
|
Bucket/Tablet |
物理分片(Hash 分桶) |
Bucket=10 → 10 个 Tablet |
|
Replica |
副本(默认 3 副本) |
Tablet_123 在 BE1/BE2/BE3 各存一份 |
📌 关键点:
- 查询时,FE 根据 WHERE 条件做 分区裁剪 + 桶裁剪,仅下发相关 Tablet;
- BE 并行扫描本地 Tablet,实现 MPP 执行。
4. 写入流程:基于 LSM-Tree 的优化实践
Doris 写入借鉴 LSM-Tree,但针对 OLAP 场景深度定制:
4.1. 写入路径

4.2. 关键优化
- Delta Writer 机制:批量写入、按列组织,提升吞吐;
- MemTable 排序:提前按 Sort Key 排序,利于后续 ZoneMap 和 Compaction;
- 两阶段提交(2PC):确保多副本原子可见;
- 异步 Flush:不阻塞前端写入。
5. 读取流程:多级缓存 + 按需加载
5.1. 读取路径
5.2. 多级缓存体系
|
缓存类型 |
内容 |
默认大小 |
作用 |
|
Page Cache |
Data Page / Index Page |
机器内存 30% |
减少磁盘 I/O |
|
Metadata Cache |
Segment Footer / Schema |
1GB |
加速元数据访问 |
|
PK Index Cache(MoW) |
主键索引 |
可配 |
加速 Unique Key 更新 |
6. Compaction 机制:消除写放大,优化查询
6.1. 为什么需要 Compaction?
- 频繁写入产生大量小 Rowset;
- 查询需扫描多个文件,I/O 放大;
- 删除/更新留下无效数据(MoR 模型)。
6.2. 两类 Compaction
|
类型 |
触发条件 |
合并范围 |
频率 |
|
Cumulative Compaction |
小 Rowset 数量 > 阈值 |
合并最近 N 个 Delta Rowset |
高频(分钟级) |
|
Base Compaction |
Base Rowset 太旧或太大 |
合并 Base + 所有 Delta |
低频(小时级) |
6.3. 调度与资源控制
- 通过 CompactionPermitLimiter 控制并发(令牌桶);
- 配置示例(be.conf):
cumulative_compaction_num_threads = 4
base_compaction_num_threads = 2
max_compaction_permits = 10000
✅ 效果:减少文件数、清理无效数据、提升查询性能。
7. 列存格式:Segment V2 设计
Segment V2 是 Doris 自研列存格式,采用 三段式结构:
7.1. 结构组成
|
区域 |
内容 |
说明 |
|
Data Region |
列数据页(Data Page) |
按列连续存储,支持 PLAIN/RLE/DICT/BIT_SHUFFLE |
|
Index Region |
索引页(Shortkey, BloomFilter, Bitmap) |
与数据分离,便于快速过滤 |
|
Footer |
元数据 |
包含行数、各列偏移、编码/压缩算法、统计信息 |
7.2. Page 管理
- 默认 Page 大小:64KB
- 每列的 Page 按行号顺序排列;
- Footer 中的 Ordinal Index 记录行号 → Page 映射,作为“一级导航”。
8. 行存
8.1. 行存简介
Doris 默认的列式存储:不适用点查场景SELECT *:需要读取所有列,每个列都要一次 IO 导致 IOPS 成为瓶颈,特别是宽表(比如上百列),尤为明显
为解决点查场景 IOPS 的瓶颈问题:Doris 2.0.0 版本开始支持行列混存
- 用户建表时指定开启行存后,点查每一行只需要一次 IO,在宽表列很多的情况下性能有数量级提升。
- 原理:是在存储时增加了一个额外的列,这个列将对应行的所有列拼接起来采用特殊的二进制格式存储
8.2. 使用语法
建表时,在表的PROPERTIES中指定
PROPERTIES (
"store_row_column" = "true" — 是否开启行存:默认false,不开启
— 哪些列开启行存:若开启行存,则默认针对所有列,若需要指定部分列,则设置
"row_store_columns" = "column1,column2,column3"
"row_store_page_size" = "16384"
);
8.3. 行存命中条件
行存命中条件分成两种情况
-
- MOW 表:"enable_unique_key_merge_on_write" = "true"
- 开启行存
- 查询的时候注意where条件中,需要所有的主键等值并且是AND
-
- 表模型,满足以下一种即可:
-
-
- DUPLICATE 表
- 开启"enable_unique_key_merge_on_write" = "true"(MOW 表)且"store_row_column" = "true"
-
-
- 符合TopN查询模式:SELECT * FROM tble [WHERE XXXXX] ORDER BY XXX LIMIT N 方括号中的是可选查询条件,注意目前只能是SELECT *,且需要命中 TopN 的延迟物化优化
8.4. 注意事项
9. 事务与一致性模型
9.1. 事务语义
- 单表原子性:一次导入要么全成功,要么全失败;
- 多版本隔离(MVCC):查询基于 publish version 快照;
- 线性一致性:通过 2PC + Version Publish 保证。
9.2. Unique Key 模型演进
- Merge-on-Read(MoR):读时合并,性能差;
- Merge-on-Write(MoW)(Doris 2.0+):
-
- 写时覆盖,物理只存最新版;
- 引入 主键索引(RocksDB/MemIndex);
- 支持 Partial Update + Sequence Column。
10. 容错与高可用
10.1. 副本机制
- 每个 Tablet 默认 3 副本,分布在不同 BE;
- FE 监控副本健康,自动触发 Clone 修复;
- 支持 Colocation Group:强制同分片副本共置,加速 Join。
10.2. 故障恢复
- BE 宕机 → FE 标记 unavailable,查询自动路由到其他副本;
- 磁盘损坏 → FE 触发副本迁移;
- 元数据由 FE 通过 BDBJE 保证强一致。
11. 性能调优关键点
|
方向 |
建议 |
|
Tablet 设计 |
单 Tablet 1~10GB,总 Tablet 数 ≈ BE 数 × 10 |
|
Sort Key |
高频过滤字段 + 高基数放前,提升 Shortkey + ZoneMap 效果 |
|
Compaction |
根据写入频率调整线程数,避免积压 |
|
编码压缩 |
数值列用 BIT_SHUFFLE + LZ4,低基数字符串用 DICT_ENCODING |
|
缓存 |
增大 Page Cache(page_cache_limit )提升热数据查询性能 |
|
Unique Key |
启用 MoW(enable_unique_key_merge_on_write=true) |
12. 未来演进方向





