Apache Druid 是一款高性能的实时分析数据库,其核心特性之一是数据汇总(Rollup),它能在数据摄入阶段进行预聚合,显著减少存储空间并提升查询性能。本文将深入讲解 Druid 的 Rollup 机制、示例及实用技巧。通过实际案例,您将学会如何利用 Rollup 优化 Druid 数据存储和查询性能。
1. Druid Rollup 的核心概念
Rollup 是 Druid 在数据摄入时进行的预聚合操作,它会将具有相同维度值和时间戳(经过 queryGranularity
截断)的行合并为一行,并对指标列(如 sum
、max
等)进行聚合计算。
关键优势:
✅ 减少存储空间:汇总后数据量大幅降低。
✅ 提升查询性能:扫描的数据量减少,查询速度更快。
✅ 节省计算资源:减少 I/O 和内存消耗。
适用场景:
- 日志分析(如访问日志、点击流)
- IoT 数据(如传感器数据)
- 时序数据(如监控指标)
不适用场景:
- 需要查询原始事件(如审计日志)
- 需要对某些列进行
GROUP BY
或WHERE
查询
2. 如何配置 Rollup?
Druid 支持多种数据摄入方式,不同方式的 Rollup 配置略有不同。
2.1 Native Batch 摄入(离线数据)
在 ingestionSpec
中,通过 granularitySpec
的 rollup
参数控制是否启用汇总:
{
"type": "index_parallel",
"spec": {
"dataSchema": {
"dataSource": "rollup_example",
"granularitySpec": {
"type": "uniform",
"segmentGranularity": "DAY",
"queryGranularity": "HOUR", // 时间粒度(1小时)
"rollup": true, // 启用 Rollup
"intervals": ["2024-01-01/2024-01-02"]
},
"dimensionsSpec": {
"dimensions": ["country", "city", "user_type"] // 维度列
},
"metricsSpec": [
{"type": "count", "name": "count"},
{"type": "sum", "name": "total_sales", "fieldName": "sales"} // 指标列
],
"parser": {
"type": "json",
"parseSpec": {
"format": "json",
"timestampSpec": {
"column": "timestamp",
"format": "auto"
},
"dimensionsSpec": {
"dimensions": ["country", "city", "user_type"]
}
}
}
},
"ioConfig": {
"type": "index_parallel",
"inputSource": {
"type": "local",
"baseDir": "/path/to/data",
"filter": "*.json"
},
"inputFormat": {
"type": "json"
}
},
"tuningConfig": {
"type": "index_parallel"
}
}
}
关键配置说明:
queryGranularity: "HOUR"
:时间戳按小时截断,相同小时的数据会被汇总。rollup: true
:启用 Rollup(默认值)。metricsSpec
:定义如何聚合指标(如sum
、count
)。
2.2 Kafka 实时摄入(流式数据)
Kafka 索引服务默认使用 最佳努力汇总(Best-effort Rollup),无法保证完全聚合。如果需要完美汇总,可以使用 Tranquility 或 Kafka Supervised Indexing(高级配置)。
{
"type": "kafka",
"spec": {
"dataSchema": {
"dataSource": "kafka_rollup_example",
"granularitySpec": {
"type": "uniform",
"segmentGranularity": "DAY",
"queryGranularity": "HOUR",
"rollup": true, // 启用 Rollup(但 Kafka 默认是 Best-effort)
"intervals": ["2024-01-01/2024-01-02"]
},
"dimensionsSpec": {
"dimensions": ["country", "city", "user_type"]
},
"metricsSpec": [
{"type": "count", "name": "count"},
{"type": "sum", "name": "total_sales", "fieldName": "sales"}
],
"parser": {
"type": "string",
"parseSpec": {
"format": "json",
"timestampSpec": {
"column": "timestamp",
"format": "auto"
},
"dimensionsSpec": {
"dimensions": ["country", "city", "user_type"]
}
}
}
},
"tuningConfig": {
"type": "kafka"
},
"ioConfig": {
"topic": "kafka_topic",
"consumerProperties": {
"bootstrap.servers": "kafka-broker:9092"
},
"taskCount": 1,
"replicas": 1
}
}
}
注意: Kafka 默认是 Best-effort Rollup,如果需要完美汇总,需使用 Tranquility 或 Kafka Supervised Indexing(高级配置)。
3. 如何计算 Rollup 比率(Rollup Ratio)?
Rollup 比率 = Druid 存储的行数 / 摄入的事件总数
,比率越高,说明汇总效果越好。
SQL 示例:
-- 计算 Rollup 比率
SELECT
SUM("num_rows") / (COUNT(*) * 1.0) AS rollup_ratio
FROM "rollup_example";
结果解读:
- 如果
rollup_ratio = 1.0
,说明没有汇总(每行数据独立存储)。 - 如果
rollup_ratio = 10.0
,说明数据被汇总了 10 倍(存储效率提升 10 倍)。
4. 优化 Rollup 的实用技巧
4.1 减少维度数量 & 降低基数
- 避免高基数维度(如
user_id
),改用 Sketches(如HyperLogLog
)。 - 合并相似维度(如
country + city
→region
)。
4.2 调整 queryGranularity
- 增大时间粒度(如从
1分钟
→5分钟
),增加时间戳匹配概率。
4.3 多数据源策略
- 完整数据源(禁用 Rollup):用于查询原始事件。
- 精简数据源(最大化 Rollup):用于常规分析查询。
5. 完美汇总 vs 最佳努力汇总
对比项 | 完美汇总(Perfect Rollup) | 最佳努力汇总(Best-effort Rollup) |
---|---|---|
数据一致性 | 保证完全聚合 | 可能存在重复数据 |
适用摄入方式 | Native Batch (SQL)、Hadoop | Kafka、Kinesis |
实现方式 | 预处理阶段确定分区 | 并行摄入,无全局协调 |
适用场景 | 离线数据分析 | 实时流式处理 |
如何选择?
- 如果业务需要完全聚合(如财务数据),使用 Native Batch + SQL。
- 如果业务需要实时性(如日志分析),使用 Kafka + 最佳努力汇总。
6. 总结
Druid 的 Rollup 功能是优化存储和查询性能的关键技术,适用于日志分析、IoT 数据、时序监控等场景。本文介绍了:
- Rollup 的工作原理(预聚合、时间粒度、维度匹配)。
- 如何配置 Rollup(Native Batch & Kafka 示例)。
- 如何计算 Rollup 比率(SQL 示例)。
- 优化 Rollup 的技巧(减少维度、调整时间粒度)。
- 完美汇总 vs 最佳努力汇总的对比与选择建议。
下一步行动:
- 在您的 Druid 集群上测试 Rollup 配置。
- 监控 Rollup 比率,优化 schema 和查询策略。
- 根据业务需求选择合适的汇总模式(完美 vs 最佳努力)。
通过合理使用 Rollup,您可以显著提升 Druid 的存储效率和查询性能! 🚀