Apache Doris 学习文档(面向开发人员)
Doris 是什么?为什么你需要它?
| 数据库类型 | 典型代表 | 特点 | 适用场景 |
|---|---|---|---|
| OLTP(事务型) | MySQL, PostgreSQL | 强一致性、高并发写、行存 | 订单、用户信息等业务系统 |
| OLAP(分析型) | Apache Doris, ClickHouse, StarRocks | 高吞吐查询、列存、MPP 架构 | 报表、BI、日志分析、用户行为分析 |
Apache Doris 是一个开源的、高性能、实时的 MPP 分析型数据库,采用列式存储,兼容 MySQL 协议,专为 OLAP(在线分析处理) 场景设计。
为什么你需要它?
✅ 快:TB 级数据秒级查询(聚合、多维分析)
✅ 实时:支持 Kafka/HTTP 秒级写入,数据即时可见
✅ 简单:无 Hadoop 依赖,部署运维轻量
✅ 易用:标准 SQL + BI 工具直连(如 Tableau、Superset)
✅ 省成本:开源免费,高压缩比降低存储开销
🎯 适用场景:实时数仓、日志分析、BI 报表、用户行为分析。
❌ 不适用:高频点查、强事务、全文检索(这类需求选 MySQL 或 Elasticsearch)。
Apache Doris 整体架构图
doris-meta/)] end subgraph "存储与执行层 (BE - Backend)" B --> F[BE Node 1] B --> G[BE Node 2] B --> H[BE Node N] F --> F1[Tablet 1] F --> F2[Tablet 2] F --> F3[Storage Engine] F3 --> F4[(Data Files
storage_root_path/)] G --> G1[Tablet 3] G --> G2[Tablet 4] G --> G3[Storage Engine] G3 --> G4[(Data Files)] H --> H1[...] H --> H2[Storage Engine] H2 --> H3[(Data Files)] end subgraph "数据源" I[Kafka] -->|Routine Load| B J[Local File] -->|Stream Load| B K[HDFS/S3] -->|Broker Load| B end classDef fe fill:#4CAF50,stroke:#388E3C,color:white; classDef be fill:#2196F3,stroke:#0D47A1,color:white; classDef storage fill:#FFC107,stroke:#FF8F00; classDef client fill:#9E9E9E,stroke:#616161,color:white; class B,B1,B2,B3,B4,B5 fe; class F,G,H,F3,G3,H2 be; class F4,G4,H3 storage; class A,C,D,E,I,J,K client;
只需记住两个角色:
| 组件 | 作用 | 类比理解 | 是否需要你关心? |
|---|---|---|---|
| FE (Frontend) | 接收 SQL、管理元数据、调度查询 | ≈ MySQL Server 层 | ❌(部署好就不用管) |
| BE (Backend) | 真正存数据 + 执行计算 | ≈ InnoDB + 分布式计算引擎 | ✅(扩容加 BE 节点即可) |
💡 关键特点:
-
FE 无状态:可多节点部署,自动选主
-
BE 自动均衡:加机器后数据自动分片
-
你只用连 FE:像连 MySQL 一样简单
Doris 核心能力(开发者最关心的)
常用写入方式
Broker Load(推荐用于大文件批量导入)
-
原理:通过 Doris 内置的 Broker 进程(如 HDFS、S3、OSS、BOS 等)从外部存储系统并行拉取数据。
-
支持格式:CSV、Parquet、ORC
-
特点:
-
异步导入,适合 GB~TB 级大文件
-
自动分片、并行处理
-
支持断点续传(部分失败可重试)
-
-
适用场景:
-
从 HDFS/S3 导入历史数据
-
每天一次的 T+1 批量同步
-
-
示例:
sql
LOAD LABEL broker_load_2022_04_01
(
DATA INFILE("s3://your_bucket_name/brokerload_example.csv")
INTO TABLE test_brokerload
COLUMNS TERMINATED BY ","
FORMAT AS "CSV"
(user_id, name, age)
)
WITH S3
(
"provider" = "S3",
"AWS_ENDPOINT" = "s3.us-west-2.amazonaws.com",
"AWS_ACCESS_KEY" = "<your-ak>",
"AWS_SECRET_KEY"="<your-sk>",
"AWS_REGION" = "us-west-2",
"compress_type" = "PLAIN"
)
PROPERTIES
(
"timeout" = "3600"
);
Stream Load(推荐用于实时/小批量 HTTP 推送)
-
原理:通过 HTTP 协议将本地文件或内存数据直接推送到 Doris。
-
支持格式:CSV、JSON(支持多行 JSON)
-
特点:
-
同步返回结果(成功/失败)
-
低延迟(秒级可见)
-
支持 实时流式写入
-
可通过 Nginx 负载均衡到多个 BE 节点
-
-
适用场景:
-
日志采集(Filebeat → Stream Load)
-
Flink/Spark 实时写入
-
应用程序直接推送数据
-
-
示例(curl):
http
curl --location-trusted -u <doris_user>:<doris_password> \
-H "label:124" \
-H "Expect:100-continue" \
-H "format:json" -H "strip_outer_array:true" \
-H "jsonpaths:[\"$.userid\", \"$.username\", \"$.userage\"]" \
-H "columns:user_id,name,age" \
-T streamload_example.json \
-XPUT http://<fe_ip>:<fe_http_port>/api/testdb/test_streamload/_stream_load
Routine Load(推荐用于 Kafka 实时持续消费)
-
原理:Doris 自动创建后台任务,持续从 Kafka 消费数据并导入。
-
支持格式:CSV、JSON
-
特点:
-
自动容错:Kafka offset 自动管理,失败自动重试
-
Exactly-Once 语义(通过 label 去重)
-
支持 Kafka 多分区并行消费
-
-
适用场景:
-
实时数仓(Kafka → Doris)
-
用户行为日志、交易流水实时入库
-
-
示例:
sql
SHOW ROUTINE LOAD FOR tbl_name;
CREATE ROUTINE LOAD example_db.kafka_load ON tbl1
PROPERTIES(
"desired_concurrent_number"="3",
"max_batch_interval" = "20",
"max_batch_rows" = "200000"
)
FROM KAFKA(
"kafka_broker_list" = "host:9092",
"kafka_topic" = "topic1",
"property.kafka_default_offsets" = "OFFSET_BEGINNING"
);
Insert Into(适合小量数据或 ETL 中转)
-
原理:类似 MySQL 的
INSERT INTO ... SELECT ... -
特点:
-
同步执行,适合 < 100 万行 的小数据量
-
可用于 Doris 内部表间数据转换(如 DWD → DWS)
-
-
限制:
-
不适合高频写入(会触发小文件问题)
-
性能远低于 Stream/Broker Load
-
-
示例:
sql
INSERT INTO tbl_agg
SELECT user_id, sum(pv) FROM tbl_detail GROUP BY user_id;
各导入方式对比总结
| 导入方式 | 实时性 | 吞吐量 | 数据源 | 适用场景 |
|---|---|---|---|---|
| Stream Load | 秒级 | 高 | HTTP(本地/程序) | 实时日志、Flink 写入 |
| Routine Load | 秒级 | 高 | Kafka | 持续实时消费 |
| Broker Load | 分钟级 | 极高 | HDFS/S3/OSS 等 | T+1 批量导入、大文件 |
| Insert Into | 秒级 | 低 | Doris 内部表 | 小量数据、ETL 中转 |
最佳实践建议
-
实时场景 → 优先选 Routine Load(Kafka) 或 Stream Load(Flink/日志)
-
批量离线导入 → 用 Broker Load(HDFS/S3)
-
避免高频 Insert Into → 会导致小文件过多,影响查询性能
-
开启 Routine Load 监控 → 通过
SHOW ROUTINE LOAD查看消费状态 -
合理设置 Label → 避免重复导入(Doris 通过 label 保证幂等)
| 方式 | 适用场景 | 吞吐 | 延迟 | 是否推荐生产 |
|---|---|---|---|---|
| JDBC INSERT | 小量测试、调试 | 低(几千/秒) | 高 | ❌(会出多版本问题!) |
| Stream Load (HTTP) | Kafka 消费、日志导入 | 高(10w+/秒) | 秒级 | ✅ 强烈推荐 |
| Routine Load | 自动消费 Kafka | 高 | 秒级 | ✅(适合简单场景) |
📌 血泪教训:
生产环境禁止直接用 JDBC INSERT 写 Doris!
原因:每次 INSERT 生成新版本 → 多版本堆积 → 查询结果混乱
表模型:选对模型,性能翻倍
| 模型 | 适用场景 | 特点 | 示例 |
|---|---|---|---|
| Duplicate Key | 日志、事件流 | 保留所有明细,不聚合 | 用户点击日志 |
| Unique Key | 需要更新的明细表 | 主键去重,最新覆盖 | 用户画像表 |
| Aggregate Key | 预聚合指标 | 自动 SUM/COUNT/MAX | PV/UV 汇总表 |
✅ 推荐:
-
日志分析 →
Duplicate Key -
用户行为宽表 →
Unique Key -
报表指标 →
Aggregate Key
兼容性:零学习成本
-
协议兼容:直接用
mysql-connector-java -
SQL 兼容:支持 JOIN、子查询、窗口函数
-
工具兼容:Navicat、DBeaver、DataGrip 直接连
🎯 你不需要学新语法,就像操作 MySQL 一样!
Spring Boot 整合实战(避坑版)
依赖配置
xml
xml<!-- 核心:用 MySQL 驱动连 Doris -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 连接池(推荐 Druid) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- Stream Load 需要 HTTP 客户端 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
多数据源配置(主库 + Doris)
yaml
spring:
datasource:
# 主业务库(MySQL)
primary:
url: jdbc:mysql://mysql:3306/order_db
username: root
password: xxx
# Doris 分析库
doris:
url: jdbc:mysql://doris-fe:9030/analysis_db # 注意:端口是 9030!
username: root
password: "" # 默认无密码
Java 配置(手动控制,避免自动配置冲突)
java
// 主启动类:排除 MyBatis 自动配置
@SpringBootApplication(exclude = MybatisAutoConfiguration.class)
public class Application { /* ... */ }
主数据源(MySQL)
java
@Configuration
@MapperScan(basePackages = "com.example.mapper.mysql",
sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class PrimaryDataSourceConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public SqlSessionFactory mysqlSqlSessionFactory(DataSource ds) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
return bean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate mysqlSqlSessionTemplate(SqlSessionFactory sf) {
return new SqlSessionTemplate(sf);
}
}
Doris 数据源
java
@Configuration
@MapperScan(basePackages = "com.example.mapper.doris",
sqlSessionTemplateRef = "dorisSqlSessionTemplate")
public class DorisDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.doris")
public DataSource dorisDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory dorisSqlSessionFactory(DataSource ds) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
return bean.getObject();
}
@Bean
public SqlSessionTemplate dorisSqlSessionTemplate(SqlSessionFactory sf) {
return new SqlSessionTemplate(sf);
}
}
✅ 关键规则:
-
两个
@MapperScan包路径必须不同 -
只有主数据源加
@Primary -
方法名与
@Qualifier保持一致
最佳实践清单(直接抄作业)
表设计
-
分区:按天/月分区(
PARTITION BY RANGE(event_date)) -
分桶:按高基数列(如
user_id)分桶,桶数 = BE 节点数 × 10 -
模型选择:
-
日志 →
Duplicate Key -
宽表 →
Unique Key -
指标 →
Aggregate Key
-
写入规范
| 场景 | 推荐方式 |
|---|---|
| Kafka 消费 | Stream Load(批量) |
| 文件导入 | Broker Load |
| 调试/小量 | JDBC(仅限测试环境) |
查询优化
-
避免
SELECT *→ 只查需要的列 -
大表 JOIN 小表 → 小表用
BROADCASTHint -
时间范围必加 → 利用分区裁剪
监控告警
-
关键指标:
-
Tablet Version Count > 100 → 告警
-
Stream Load 失败率 > 1% → 告警
-
查询 P99 > 5s → 优化
-
总结:Doris 使用口诀
"一兼容、二模型、三写入、四分片"
| 步骤 | 要点 |
|---|---|
| 一兼容 | 用 MySQL 驱动直连,SQL 零学习成本 |
| 二模型 | Duplicate(日志)、Unique(宽表)、Aggregate(指标) |
| 三写入 | 生产只用 Stream Load,禁用 JDBC INSERT |
| 四分片 | 按时间分区 + 按用户分桶,性能翻倍 |