搜 索

Doris/StarRocks从入门到放弃:实时 OLAP 的新选择

  • 16阅读
  • 2023年05月06日
  • 0评论
首页 / AI/大数据 / 正文

一、前言:OLAP 江湖新势力

如果说 ClickHouse 是 OLAP 界的"老炮儿",那 Doris 和 StarRocks 就是正在崛起的"新生代"。

timeline title OLAP引擎发展史 2008 : Vertica (商业) 2012 : Druid (Apache) 2016 : ClickHouse (Yandex开源) 2017 : Doris (百度Palo开源) 2020 : StarRocks (Doris分支) 2023 : 三足鼎立时代

关系图谱:

graph TB A[Doris] -->|分支| B[StarRocks] A -->|原名| C[Palo] C -->|百度开源| A A -->|进入| D[Apache孵化] B -->|独立发展| E[商业化公司] style A fill:#4ecdc4 style B fill:#ff6b6b

本文核心问题:

Doris/StarRocks 比 ClickHouse 好在哪?又差在哪?

二、架构对比:从根源理解差异

2.1 ClickHouse 架构回顾

graph TB subgraph "ClickHouse架构" Client[客户端] --> Node1[CH Node 1] Client --> Node2[CH Node 2] Client --> Node3[CH Node 3] Node1 & Node2 & Node3 --> ZK[(ZooKeeper)] Node1 --> Disk1[(本地磁盘)] Node2 --> Disk2[(本地磁盘)] Node3 --> Disk3[(本地磁盘)] end style ZK fill:#ffa502

ClickHouse 特点:

  • Shared-Nothing(完全无共享)
  • 依赖 ZooKeeper 协调
  • 运维复杂度高

2.2 Doris/StarRocks 架构

graph TB subgraph "Doris/StarRocks架构" Client[客户端] --> FE1[FE Leader] Client --> FE2[FE Follower] Client --> FE3[FE Observer] FE1 & FE2 & FE3 --> BE1[BE Node 1] FE1 & FE2 & FE3 --> BE2[BE Node 2] FE1 & FE2 & FE3 --> BE3[BE Node 3] BE1 --> Disk1[(本地磁盘)] BE2 --> Disk2[(本地磁盘)] BE3 --> Disk3[(本地磁盘)] end style FE1 fill:#4ecdc4 style FE2 fill:#45b7d1 style FE3 fill:#96ceb4

核心组件:

组件全称职责
FEFrontend元数据管理、SQL解析、查询规划
BEBackend数据存储、查询执行

2.3 架构差异总结

graph LR subgraph "ClickHouse" A1["每个节点既是协调者
也是执行者"] A2["依赖ZK协调"] A3["运维复杂"] end subgraph "Doris/StarRocks" B1["FE负责协调
BE负责执行"] B2["自带元数据管理
无需ZK"] B3["运维简单"] end

三、Doris 深度解析

3.1 Doris 整体架构

graph TB subgraph "Frontend Layer" FE[FE集群
MySQL协议兼容] META[(元数据
BDBJE)] end subgraph "Backend Layer" BE1[BE 1] BE2[BE 2] BE3[BE 3] BE4[BE N...] end subgraph "Storage Layer" T1[Tablet 副本1] T2[Tablet 副本2] T3[Tablet 副本3] end FE --> META FE --> BE1 & BE2 & BE3 & BE4 BE1 --> T1 BE2 --> T2 BE3 --> T3

3.2 数据模型

Doris 支持三种数据模型:

graph TB A[Doris数据模型] --> B[Duplicate
明细模型] A --> C[Aggregate
聚合模型] A --> D[Unique
主键模型] B --> B1["保留所有原始数据
类似日志表"] C --> C1["预聚合
SUM/MAX/MIN等"] D --> D1["按Key去重
保留最新值"]

Duplicate 模型(明细模型)

-- 适用场景:日志、行为数据,需要保留所有明细
CREATE TABLE user_behavior (
    user_id BIGINT,
    event_time DATETIME,
    event_type VARCHAR(50),
    page_url VARCHAR(500),
    duration INT
)
DUPLICATE KEY(user_id, event_time)  -- 允许重复
DISTRIBUTED BY HASH(user_id) BUCKETS 32
PROPERTIES ("replication_num" = "3");

Aggregate 模型(聚合模型)

-- 适用场景:实时汇总,如PV/UV统计
CREATE TABLE page_view_stats (
    page_url VARCHAR(500),
    visit_date DATE,
    -- 聚合字段
    pv BIGINT SUM,           -- 自动SUM
    uv BIGINT BITMAP_UNION,  -- 自动去重
    duration BIGINT MAX      -- 取最大值
)
AGGREGATE KEY(page_url, visit_date)
DISTRIBUTED BY HASH(page_url) BUCKETS 16
PROPERTIES ("replication_num" = "3");

-- 插入时自动聚合
INSERT INTO page_view_stats VALUES 
    ('/home', '2024-01-15', 1, to_bitmap(1001), 30),
    ('/home', '2024-01-15', 1, to_bitmap(1002), 45),
    ('/home', '2024-01-15', 1, to_bitmap(1001), 20);  -- 同一用户

-- 查询结果:pv=3, uv=2(1001去重), duration=45

Unique 模型(主键模型)

-- 适用场景:需要实时更新的维度表
CREATE TABLE user_profile (
    user_id BIGINT,
    name VARCHAR(100),
    age INT,
    city VARCHAR(50),
    update_time DATETIME
)
UNIQUE KEY(user_id)  -- 按user_id去重
DISTRIBUTED BY HASH(user_id) BUCKETS 32
PROPERTIES (
    "replication_num" = "3",
    "enable_unique_key_merge_on_write" = "true"  -- 写时合并,实时更新
);

3.3 物化视图

flowchart LR A[Base表
明细数据] --> B[物化视图1
按天汇总] A --> C[物化视图2
按品类汇总] A --> D[物化视图3
按地区汇总] E[智能查询路由] --> B E --> C E --> D F[用户查询] --> E
-- 基表
CREATE TABLE sales_detail (
    order_id BIGINT,
    order_date DATE,
    product_id BIGINT,
    category_id INT,
    region VARCHAR(50),
    amount DECIMAL(10,2)
)
DUPLICATE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 32;

-- 创建物化视图:按天按品类汇总
CREATE MATERIALIZED VIEW mv_daily_category_sales AS
SELECT 
    order_date,
    category_id,
    SUM(amount) AS total_amount,
    COUNT(*) AS order_count
FROM sales_detail
GROUP BY order_date, category_id;

-- 查询自动路由到物化视图
SELECT category_id, SUM(amount)  -- 自动命中mv
FROM sales_detail 
WHERE order_date = '2024-01-15'
GROUP BY category_id;

3.4 Doris 2.0 新特性

graph TB A[Doris 2.0] --> B[倒排索引] A --> C[Pipeline执行引擎] A --> D[Merge-on-Write] A --> E[异步物化视图] B --> B1["支持全文检索
替代ES部分场景"] C --> C1["查询性能提升
3-10倍"] D --> D1["实时更新
秒级可见"] E --> E1["自动刷新
增量更新"]

四、StarRocks 深度解析

4.1 StarRocks vs Doris 差异

graph TB subgraph "共同点" A1[相同的架构FE/BE] A2[兼容MySQL协议] A3[列式存储] A4[向量化执行] end subgraph "StarRocks独有" B1[CBO优化器更强] B2[Primary Key表更成熟] B3[存算分离架构] B4[更好的JOIN性能] end subgraph "Doris独有" C1[倒排索引全文检索] C2[更活跃的社区] C3[Apache基金会背书] C4[更多国内用户] end

4.2 StarRocks 查询优化器

flowchart TB subgraph "CBO Cost-Based Optimizer" A[SQL语句] --> B[解析器Parser] B --> C[分析器Analyzer] C --> D[逻辑优化] D --> E[物理优化] E --> F[代价估算] F --> G[最优计划] end subgraph "优化规则" D --> D1[谓词下推] D --> D2[列裁剪] D --> D3[常量折叠] D --> D4[子查询展开] E --> E1[Join Reorder] E --> E2[分布式Join] E --> E3[Runtime Filter] end

4.3 存算分离架构(StarRocks 3.0+)

graph TB subgraph "传统存算一体" A1[BE节点] --> A2[(本地磁盘)] A3[BE节点] --> A4[(本地磁盘)] A5["计算和存储绑定
扩缩容成本高"] end
graph TB subgraph "存算分离架构" B1[CN计算节点] --> B3[(对象存储S3/OSS)] B2[CN计算节点] --> B3 B4["计算独立扩缩
存储无限扩展"] end
flowchart LR subgraph "存算分离优势" A["弹性计算
按需扩缩CN节点"] --> B["成本降低
热数据本地缓存
冷数据放对象存储"] B --> C["高可用
计算节点无状态
故障快速恢复"] end

4.4 Primary Key 表深度解析

-- StarRocks Primary Key表:支持实时更新
CREATE TABLE orders (
    order_id BIGINT,
    user_id BIGINT,
    status VARCHAR(20),
    amount DECIMAL(10,2),
    update_time DATETIME
)
PRIMARY KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 32
PROPERTIES (
    "replication_num" = "3",
    "enable_persistent_index" = "true"  -- 持久化索引,加速更新
);

-- 支持实时UPDATE/DELETE
UPDATE orders SET status = 'COMPLETED' WHERE order_id = 10001;
DELETE FROM orders WHERE order_id = 10002;

Primary Key 实现原理:

flowchart TB subgraph "写入流程" A[数据写入] --> B{主键是否存在?} B -->|存在| C[标记旧数据删除] B -->|不存在| D[直接写入] C --> E[写入新数据] D --> E E --> F[内存索引更新] end subgraph "查询流程" G[查询请求] --> H[内存索引过滤] H --> I[只返回最新版本] end

五、实战:构建实时数仓

5.1 典型实时数仓架构

flowchart TB subgraph "数据源" A1[MySQL Binlog] A2[业务日志] A3[Kafka] end subgraph "实时采集" B1[Flink CDC] B2[Logstash] end subgraph "消息队列" C[Kafka] end subgraph "实时计算" D[Flink] end subgraph "OLAP存储" E[Doris/StarRocks] end subgraph "数据应用" F1[实时大屏] F2[BI报表] F3[即席查询] end A1 --> B1 --> C A2 --> B2 --> C A3 --> C C --> D --> E --> F1 & F2 & F3

5.2 Routine Load:从 Kafka 实时入库

-- Doris/StarRocks 支持直接从Kafka消费数据
CREATE ROUTINE LOAD orders_load ON orders
COLUMNS(order_id, user_id, status, amount, update_time),
COLUMNS TERMINATED BY ","
PROPERTIES (
    "desired_concurrent_number" = "3",
    "max_error_number" = "1000",
    "strict_mode" = "false",
    "format" = "json",
    "jsonpaths" = "[\"$.order_id\",\"$.user_id\",\"$.status\",\"$.amount\",\"$.update_time\"]"
)
FROM KAFKA (
    "kafka_broker_list" = "kafka1:9092,kafka2:9092,kafka3:9092",
    "kafka_topic" = "orders_topic",
    "property.group.id" = "doris_consumer_group",
    "property.kafka_default_offsets" = "OFFSET_BEGINNING"
);

-- 查看导入状态
SHOW ROUTINE LOAD FOR orders_load;

5.3 Stream Load:批量导入

# 从文件批量导入
curl --location-trusted -u root:password \
  -H "Expect:100-continue" \
  -H "column_separator:," \
  -H "columns: order_id, user_id, status, amount, update_time" \
  -T orders_data.csv \
  http://fe_host:8030/api/database/orders/_stream_load

# 导入JSON数据
curl --location-trusted -u root:password \
  -H "format: json" \
  -H "strip_outer_array: true" \
  -T orders_data.json \
  http://fe_host:8030/api/database/orders/_stream_load

5.4 Flink 写入 Doris/StarRocks

// Flink SQL 写入 Doris
CREATE TABLE doris_sink (
    order_id BIGINT,
    user_id BIGINT,
    status STRING,
    amount DECIMAL(10,2),
    update_time TIMESTAMP(3)
) WITH (
    'connector' = 'doris',
    'fenodes' = 'fe_host:8030',
    'table.identifier' = 'database.orders',
    'username' = 'root',
    'password' = 'password',
    'sink.properties.format' = 'json',
    'sink.properties.strip_outer_array' = 'true'
);

INSERT INTO doris_sink
SELECT order_id, user_id, status, amount, update_time
FROM kafka_source;

六、高级特性对比

6.1 索引支持

graph TB subgraph "Doris索引" A1[前缀索引Prefix] A2[Bloom Filter] A3[Bitmap索引] A4[倒排索引2.0新增] end subgraph "StarRocks索引" B1[前缀索引] B2[Bloom Filter] B3[Bitmap索引] B4[N-Gram索引] end subgraph "ClickHouse索引" C1[稀疏索引Primary] C2[Bloom Filter] C3[二级索引Skip] C4[全文索引有限] end

6.2 实时更新能力

引擎更新方式时效性实现原理
ClickHouseCollapsingMergeTree最终一致异步Merge
Doris (Unique)Merge-on-Write实时写时合并
StarRocks (Primary Key)Delete+Insert实时持久化索引

6.3 JOIN 性能

flowchart LR subgraph "Join类型" A[Broadcast Join] --> A1["小表广播
适合维表关联"] B[Shuffle Join] --> B1["数据Shuffle
适合大表关联"] C[Colocate Join] --> C1["数据预分布
无需Shuffle"] D[Bucket Shuffle Join] --> D1["部分Shuffle
优化版"] end
-- StarRocks Colocate Join 示例
-- 建表时指定相同的Colocate Group
CREATE TABLE orders (
    order_id BIGINT,
    user_id BIGINT,
    amount DECIMAL(10,2)
)
DISTRIBUTED BY HASH(user_id) BUCKETS 32
PROPERTIES ("colocate_with" = "user_group");

CREATE TABLE users (
    user_id BIGINT,
    name VARCHAR(100)
)
DISTRIBUTED BY HASH(user_id) BUCKETS 32
PROPERTIES ("colocate_with" = "user_group");

-- 相同分桶键的JOIN,数据本地关联,无需Shuffle
SELECT u.name, SUM(o.amount)
FROM orders o JOIN users u ON o.user_id = u.user_id
GROUP BY u.name;

七、运维实战

7.1 集群部署架构

graph TB subgraph "生产环境推荐" subgraph "FE集群 高可用" FE1[FE1 Leader] FE2[FE2 Follower] FE3[FE3 Follower] end subgraph "BE集群 数据节点" BE1[BE1] BE2[BE2] BE3[BE3] BE4[BE4] BE5[BE5] BE6[BE6] end LB[负载均衡] --> FE1 & FE2 & FE3 FE1 & FE2 & FE3 --> BE1 & BE2 & BE3 & BE4 & BE5 & BE6 end

资源规划建议:

组件最小配置生产配置说明
FE3节点 x 8C16G3节点 x 16C32G建议SSD
BE3节点 x 16C64G6+节点 x 32C128G内存越大越好
存储SSD 500G/节点SSD 2T+/节点NVME最佳

7.2 监控指标

graph TB subgraph "关键监控指标" A[FE监控] --> A1["QPS/延迟"] A --> A2["元数据内存"] A --> A3["连接数"] B[BE监控] --> B1["CPU/内存使用率"] B --> B2["磁盘I/O"] B --> B3["Compaction进度"] B --> B4["Tablet数量"] C[查询监控] --> C1["慢查询数量"] C --> C2["查询失败率"] C --> C3["资源队列等待"] end
-- 查看BE节点状态
SHOW BACKENDS;

-- 查看导入任务
SHOW LOAD;

-- 查看慢查询
SELECT * FROM information_schema.slow_query 
WHERE query_time > 10 
ORDER BY query_time DESC 
LIMIT 20;

-- 查看Tablet状态
SHOW TABLET FROM database.table_name;

7.3 常见问题排查

flowchart TD A[问题排查] --> B{查询慢?} B -->|是| B1["检查执行计划
EXPLAIN SQL"] B1 --> B2["是否命中分区?"] B2 --> B3["是否有数据倾斜?"] B3 --> B4["Compaction是否积压?"] A --> C{导入失败?} C -->|是| C1["检查错误日志
be.WARNING"] C1 --> C2["内存是否不足?"] C2 --> C3["磁盘是否满了?"] C3 --> C4["数据格式是否正确?"] A --> D{节点不可用?} D -->|是| D1["检查FE/BE进程"] D1 --> D2["检查网络连通性"] D2 --> D3["检查磁盘状态"]

八、性能调优清单

8.1 建表优化

-- ❌ 不好的建表
CREATE TABLE bad_table (
    id BIGINT,
    name VARCHAR(500),  -- 长度过大
    data TEXT,          -- 避免TEXT
    status VARCHAR(50)  -- 应该用枚举优化
)
DISTRIBUTED BY HASH(id) BUCKETS 10;  -- 分桶数太少

-- ✅ 好的建表
CREATE TABLE good_table (
    id BIGINT,
    name VARCHAR(100),
    data VARCHAR(5000),
    status TINYINT      -- 用数字代替字符串
)
DISTRIBUTED BY HASH(id) BUCKETS 64  -- 合理的分桶数
PROPERTIES (
    "replication_num" = "3",
    "bloom_filter_columns" = "id"  -- 常查询字段加布隆过滤
);

8.2 查询优化

mindmap root((查询优化)) 分区裁剪 WHERE条件包含分区字段 避免分区函数转换 分桶裁剪 WHERE包含分桶字段 Colocate Join 索引利用 前缀索引命中 Bloom Filter SQL改写 避免SELECT * 减少子查询 利用物化视图
-- ❌ 不好的查询
SELECT * FROM orders 
WHERE DATE(order_time) = '2024-01-15';  -- 函数导致无法裁剪分区

-- ✅ 好的查询
SELECT order_id, amount FROM orders 
WHERE order_time >= '2024-01-15 00:00:00' 
  AND order_time < '2024-01-16 00:00:00';

九、选型建议

9.1 场景匹配

graph TD A{你的场景} --> B{需要实时更新?} B -->|频繁更新| C[StarRocks Primary Key
或 Doris Unique MOW] B -->|追加为主| D{需要全文检索?} D -->|是| E[Doris 2.0
倒排索引] D -->|否| F{团队技术栈?} F -->|偏好运维简单| G[Doris/StarRocks
无需ZK] F -->|追求极致性能| H[ClickHouse] A --> I{数据量级?} I -->|PB级| J["考虑存算分离
StarRocks 3.0"] I -->|TB级| K[任选都可以]

9.2 综合对比表

维度ClickHouseDorisStarRocks
易用性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
运维难度高(需ZK)
单表性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
多表JOIN⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
实时更新⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
MySQL兼容部分
社区活跃国际化强国内活跃商业化强
学习成本中等

9.3 最终建议

flowchart TD A["如果你是..."] --> B["国内团队
追求稳定运维
预算有限"] A --> C["追求极致分析性能
团队技术能力强"] A --> D["需要实时更新
复杂JOIN场景多"] A --> E["正在用Doris
想要更强性能"] B --> B1["推荐 Apache Doris"] C --> C1["推荐 ClickHouse"] D --> D1["推荐 StarRocks"] E --> E1["评估迁移 StarRocks"] style B1 fill:#4ecdc4 style C1 fill:#ff6b6b style D1 fill:#ffeaa7 style E1 fill:#96ceb4

十、总结

mindmap root((Doris/StarRocks)) 架构优势 FE/BE分离 无需ZK 运维简单 数据模型 Duplicate明细 Aggregate聚合 Unique/Primary去重 实时能力 Merge-on-Write 实时UPDATE/DELETE 秒级可见 生态集成 Flink Connector Kafka Routine Load MySQL协议兼容

一句话总结:

Doris:Apache 基金会背书,社区活跃,国内用户多,2.0 版本支持全文检索

StarRocks:从 Doris 分支而来,CBO 优化器更强,Primary Key 更成熟,存算分离是亮点

两者都是 ClickHouse 之外的优秀选择,尤其适合追求运维简单、需要实时更新、有复杂 JOIN 需求的场景。

评论区
暂无评论
avatar