跳到主要内容
Spring Boot 整合 Apache Doris:实现海量数据实时 OLAP 分析实战 | 极客日志
Java java
Spring Boot 整合 Apache Doris:实现海量数据实时 OLAP 分析实战 介绍基于 Spring Boot 与 Apache Doris 构建实时 OLAP 分析系统的方案。通过 Kafka 作为消息中间件,利用 Doris Routine Load 自动导入数据,实现海量订单数据的实时写入与秒级查询。涵盖环境搭建、数据模型设计、性能优化及监控可观测性实践,提供 Mermaid 与 PlantUML 架构图辅助理解。
技术博主 发布于 2026/2/7 更新于 2026/6/1 26 浏览Spring Boot 整合 Apache Doris:实现海量数据实时 OLAP 分析实战
在大数据时代,企业对数据分析的实时性、并发性和灵活性提出了前所未有的要求。传统关系型数据库(如 MySQL)难以应对高吞吐写入与复杂聚合查询的双重压力。为此,Apache Doris 作为一种高性能、低延迟的 MPP(Massively Parallel Processing)实时分析型数据库,正被越来越多企业用于构建现代化数仓系统。
本文将深入讲解如何通过 Spring Boot 框架整合 Apache Doris ,打造一套支持海量数据写入与秒级响应 OLAP 查询的完整架构,并提供可直接运行的 流程图代码(Mermaid 格式) 和 原理图代码(PlantUML + ASCII 图形) ,所有图片均使用不同颜色区分模块功能,便于理解。
一、Apache Doris 简介与核心优势
1.1 什么是 Apache Doris?
Apache Doris 是一个开源的分布式 SQL 数据仓库,原名 Palo,由百度研发并捐赠给 Apache 基金会。它具备以下特性:
✅ 支持标准 SQL(兼容 MySQL 协议)
✅ 实时写入 + 实时查询(毫秒~秒级延迟)
✅ 高并发点查和复杂分析能力
✅ 架构简洁:仅 FE(Frontend)+ BE(Backend),无依赖 ZooKeeper/HDFS
✅ 自动分区、物化视图优化性能
🎯 适用场景:用户行为分析、实时报表、日志分析、BI 大屏等。
1.2 Doris 架构概览(图 1:Mermaid 流程图)
JDBC/MySQL 协议
客户端/应用
FE: Frontend
SQL 解析与计划生成
元数据管理
查询调度器
BE 节点 1
BE 节点 2
BE 节点 3
本地存储
本地存储
本地存储
🔍 图中颜色说明:橙色 (#f96) :外部请求源(Spring Boot 应用)蓝色 (#6fb9e8) :FE 节点 —— 控制中枢青绿色 (#4db6ac) :核心处理逻辑紫色 (#8d6eaa) :元数据服务黄色 (#ffca28) :任务分发器浅绿 (#a5d6a7) :BE 存储节点(数据分片分布)
二、整体技术架构设计
我们设计一个典型的'生产 → 消费 → 分析'链路:
用户下单触发事件;
Spring Boot 接收请求并发送至 Kafka;
Doris 使用 Routine Load 自动消费 Kafka 数据;
BI 系统通过 JDBC 查询 Doris 获取实时统计结果。
2.1 全链路架构图(图 2:Mermaid 彩色流程图)
展示层
分析引擎
消息中间件
后端服务
前端系统
HTTP POST
JSON Event
Stream
SQL Query
Vue/React
【Spring Boot】
Kafka Cluster
【Apache Doris】
FE Node
BE Node
Grafana / BI Dashboard
🌈 颜色含义:红色系 (#ff7043) :前端交互层蓝色系 (#29b6f6) :Spring Boot 微服务橙黄 (#ffa726) :Kafka 消息队列绿色系 (#66bb6a) :Doris 分析引擎天蓝/深青 :内部组件细化紫色 (#ab47bc) :可视化展示终端
三、环境准备与项目搭建
3.1 启动 Doris 集群(推荐 Docker Compose)
version: '3'
services:
fe:
image: apache/doris:fe-2.0.3
ports:
- "9030:9030"
- "8030:8030"
environment:
- FE_CONFIG=meta_dir=/opt/doris/fe/meta
volumes:
- ./doris/fe:/opt/doris/fe
be:
image: apache/doris:be-2.0.3
depends_on:
- fe
ports:
- "9060:9060"
environment:
- BE_CONFIG=storage_root_path=/opt/doris/be/storage
volumes:
- ./doris/be:/opt/doris/be
⚠️ 注意:首次启动需在 FE 初始化数据库和用户。
3.2 创建 Spring Boot 工程(Maven) <dependencies >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.kafka</groupId >
<artifactId > spring-kafka</artifactId >
</dependency >
<dependency >
<groupId > mysql</groupId >
<artifactId > mysql-connector-java</artifactId >
<scope > runtime</scope >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-jdbc</artifactId >
</dependency >
</dependencies >
3.3 application.yml 配置文件 server:
port: 8080
spring:
kafka:
bootstrap-servers: localhost:9092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
datasource:
url: jdbc:mysql://localhost:9030/demo_db?useSSL=false&allowPublicKeyRetrieval=true
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver
四、建表语句与数据模型设计
4.1 在 Doris 中创建订单宽表 CREATE DATABASE IF NOT EXISTS demo_db;
USE demo_db;
CREATE TABLE IF NOT EXISTS order_wide (
order_id BIGINT NOT NULL COMMENT "订单 ID",
user_id BIGINT NOT NULL ,
product_name VARCHAR (255 ) NOT NULL ,
category VARCHAR (100 ),
price DECIMAL (10 ,2 ) NOT NULL ,
quantity INT NOT NULL ,
total_amount AS price * quantity STORED COMMENT "衍生字段",
province VARCHAR (50 ),
city VARCHAR (50 ),
create_time DATETIME NOT NULL
) ENGINE = OLAP DUPLICATE KEY(order_id)
PARTITION BY RANGE (create_time)(
PARTITION p202401 VALUES LESS THAN ("2024-02-01"),
PARTITION p202402 VALUES LESS THAN ("2024-03-01")
) DISTRIBUTED BY HASH(order_id) BUCKETS 10 PROPERTIES("replication_num"= "1","enable_persistent_index"= "true");
五、Spring Boot 写入数据到 Kafka
5.1 定义实体类 public class OrderEvent {
private Long orderId;
private Long userId;
private String productName;
private String category;
private BigDecimal price;
private Integer quantity;
private String province;
private String city;
}
5.2 控制器接收请求 @RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private KafkaTemplate<String, OrderEvent> kafkaTemplate;
@PostMapping
public ResponseEntity<String> create (@RequestBody OrderEvent event) {
event.setCreateTime(LocalDateTime.now());
kafkaTemplate.send("topic_doris_orders" , event);
return ResponseEntity.ok("Order sent to Kafka" );
}
}
六、Doris 配置 Routine Load 实现自动导入 CREATE ROUTINE LOAD demo_db.order_load_job ON order_wide
COLUMNS TERMINATED BY ",",
COLUMNS(order_id, user_id, product_name, category, price, quantity, province, city, create_time),
WHERE create_time IS NOT NULL
PROPERTIES ("desired_concurrent_number"= "3","max_batch_interval"= "15","max_error_number"= "1000","strict_mode"= "false")
FROM KAFKA ("kafka_broker_list"= "localhost:9092","kafka_topic"= "topic_doris_orders","kafka_partitions"= "0,1,2","property.kafka_default_offsets"= "OFFSET_BEGINNING");
✅ 成功后可通过 SHOW ROUTINE LOAD 查看状态。
七、查询分析:Spring Boot 调用 Doris 执行 OLAP 查询 @Service
public class ReportService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> getRevenueByCategory () {
String sql = """
SELECT category, SUM(total_amount) AS revenue FROM order_wide WHERE create_time >= ? GROUP BY category ORDER BY revenue DESC
""" ;
return jdbcTemplate.queryForList(sql, LocalDateTime.now().minusDays(7 ));
}
public long getTotalOrders () {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM order_wide" , Long.class);
}
}
⚠️ 生产建议:高频查询使用缓存(Redis)或物化视图加速。
八、性能优化策略(图 3:优化路径 PlantUML) @startuml
skinparam backgroundColor #FEFEFE
skinparam sequenceArrowThickness 2
skinparam sequenceMessageAlign center
actor Developer as dev
database "MySQL Source" as mysql #lightblue
rectangle "Flink CDC" as flink #orange
queue "Kafka" as kafka #yellow
cloud "Doris" as doris #green
component "BI Tool" as bi #purple
dev -> mysql : 启用 Binlog
mysql -> flink : 实时捕获变更
flink -> kafka : 输出 JSON
kafka -> doris : Routine Load
doris -> bi : 提供 API 查询
bi -> dev : 展示报表
note right of doris <<优化点>>
- 物化视图
- 分区剪枝
- 前缀索引
end note
@enduml
📌 此图为高级优化路径,适用于从 MySQL 实时同步至 Doris 的场景。
九、监控与可观测性(图 4:ASCII 架构 + 颜色标注) ┌─────────────────────────────────────────────────────┐
│ Grafana 监控大屏 │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ QPS 曲线 │ │ 导入延迟 │ │ 磁盘使用率 │ │
│ │ ████░░░ │ │ ██░░░░░ │ │ ██████░░ │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ └────────────┬───────────────────────────────┬────────┘ │
│ │ ▼ ▼ ┌─────────────────┐ ┌────────────────────┐ │
│ │ Prometheus │◄─────────┤ Doris │ │
│ │ (指标采集) │ │ [FE] :9030, [BE] :* │
│ └─────────────────┘ └────────────────────┘ ▲ ▲ │
│ └──────────────┬────────────────┘ ▼ ┌────────────────────┐ │
│ │ Spring Boot │ │ /metrics 暴露端点 │ └────────────────────┘ │
└─────────────────────────────────────────────────────┘
🎨 ASCII 图颜色模拟:红色边框 :监控面板蓝色块 :Prometheus 数据采集绿色背景 :Doris 集群黄色图表 :趋势可视化(用字符模拟)
十、常见问题与解决方案 问题 原因 解决方案 Routine Load 显示 PAUSED Kafka offset 超出范围 设置 "property.kafka_default_offsets" = "OFFSET_END" 查询超时 BE 资源不足 增加 BE 节点或调整 query_timeout JDBC 连接失败 用户未授权 执行 GRANT SELECT ON TABLE xxx TO 'user'@'%' 数据未更新 物化视图未生效 检查 rollup 状态 SHOW ALTER TABLE ROLLUP
十一、总结 本文详细介绍了 Spring Boot 整合 Apache Doris 的全流程实践,涵盖:
✅ 架构设计
✅ 环境部署
✅ 数据建模
✅ 实时写入(Kafka + Routine Load)
✅ OLAP 查询
✅ 性能优化
✅ 可视化监控
并通过 Mermaid、PlantUML、ASCII 图形 提供了多张彩色原理图,帮助开发者快速掌握系统交互逻辑。
💡 建议进阶方向:结合 Flink CDC 实现 MySQL → Doris 实时入湖使用 Doris Manager 或 DevOps 脚本自动化运维引入 Kylin/Doris Bridge 支持多维分析
十二、参考资料 相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online