Article
第一章:Druid 概述与核心概念
1.1 什么是 Apache Druid
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Apache Druid | 一个开源的、高性能的列式分布式 OLAP 数据库,专为实时分析和低延迟查询设计,支持高并发、亚秒级响应。 | 不适用于事务处理(OLTP)或复杂 JOIN 场景;强调写入后快速可查。 |
| 实时分析能力 | 支持从 Kafka、Kinesis 等流式源实时摄入数据,并在秒级内提供查询能力。 | 流式摄入需配置 Supervisor,依赖 MiddleManager 和 Peon 进程。 |
| 列式存储 | 数据按列存储,利于压缩和向量化计算,提升聚合查询性能。 | 高基数维度可能导致 Segment 膨胀,需合理建模。 |
| 时间序列优先 | 所有数据必须包含时间戳字段(__time),查询围绕时间窗口展开。 | 时间字段不可为空,且必须为 ISO8601 或毫秒时间戳格式。 |
1.2 Druid 的架构组成
| 组件名称 | 说明 | 注意事项 |
|---|---|---|
| Coordinator | 负责 Segment 的生命周期管理,包括加载、卸载、复制和均衡。 | 依赖 Metadata Storage(如 MySQL/PostgreSQL)和 Deep Storage(如 HDFS/S3)。 |
| Overlord | 管理数据摄入任务(Ingestion Tasks)的调度与分配。 | 与 MiddleManager 协同工作;可运行在本地模式(local mode)或远程模式。 |
| Broker | 接收客户端查询请求,路由到 Historical 和 Real-time 节点,并合并结果返回。 | 可启用缓存(Cache)提升重复查询性能;支持 SQL 和原生 JSON 查询。 |
| Historical | 存储并提供已提交的 Segment 查询服务,数据来自 Deep Storage。 | 启动时从 Deep Storage 加载 Segment;内存映射(MMAP)或堆外内存加载。 |
| MiddleManager | 负责启动 Peon 任务进程,执行数据摄入(批处理或流式)。 | 每个任务由独立 Peon 进程执行,资源隔离但开销较大。 |
| Router(可选) | 路由请求到 Broker 或 Coordinator/Overlord 的 UI/API,用于统一入口。 | 非必需组件,适用于多集群或简化客户端配置场景。 |
| Metadata Storage | 存储 Segment 元数据、任务状态、规则等(通常为关系型数据库)。 | 必须持久化;不存储实际数据,仅元信息。 |
| Deep Storage | 持久化存储原始 Segment 文件(如 S3、HDFS、本地文件系统)。 | 所有 Historical 节点从此处加载数据;是容灾恢复的关键。 |
1.3 核心概念解析(DataSource、Segment、Ingestion、Query 等)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| DataSource | 类似传统数据库中的”表”,是逻辑数据集合的名称,由多个 Segment 构成。 | 一个 DataSource 可包含不同时间范围的多个 Segment;命名需全局唯一。 |
| Segment | 数据物理存储单元,按时间分区(如每小时一个 Segment),包含列式数据、索引和元数据。 | 默认最大行数约 500 万;过大影响查询性能,过小增加管理开销。 |
| Ingestion Spec | 描述如何摄入数据的 JSON 配置,包含 input source、parser、transform、tuning config 等。 | 分为 batch 和 streaming 两类;可通过 POST /druid/indexer/v1/task 提交。 |
| GranularitySpec | 定义数据的时间粒度(如 HOUR、DAY)和查询 rollup 行为。 | queryGranularity 控制写入时聚合粒度;segmentGranularity 控制 Segment 切分周期。 |
| Rollup | 写入时对相同维度+时间桶的数据进行预聚合(如 SUM、COUNT),减少存储和提升查询速度。 | 开启后原始明细丢失;需确保维度组合不会导致高基数爆炸。 |
| Query Types | 包括 Timeseries、TopN、GroupBy、Scan、Search 等,每种针对特定分析场景优化。 | GroupBy 功能最全但资源消耗大;TopN 在高基数维度上更高效。 |
__time | 特殊时间戳字段,所有数据必须包含,作为主时间维度。 | 必须为 long(毫秒)或 ISO8601 字符串;Druid 自动识别并索引。 |
1.4 Druid 与其他 OLAP 系统对比(如 ClickHouse、Pinot、Doris)
| 对比维度 | Apache Druid | ClickHouse | Apache Pinot | Apache Doris |
|---|---|---|---|---|
| 数据模型 | 宽表 + 时间序列,强时间导向 | 宽表,无强制时间字段 | 类似 Druid,支持时间序列 | 宽表,支持主键模型(Unique Key) |
| 实时摄入 | 原生支持 Kafka/Kinesis,秒级可见 | 需通过 MaterializedView 或外部工具 | 原生支持 Kafka/Pulsar | 支持 Routine Load(Kafka)、Stream Load |
| 查询语言 | 原生 JSON API + SQL(兼容 ANSI) | 自研 SQL(功能强大) | 原生 PQL + SQL | 高度兼容 MySQL 协议和语法 |
| 列式存储 | 是 | 是 | 是 | 是 |
| 预聚合(Rollup) | 支持写入时 Rollup | 不支持(需物化视图模拟) | 支持 | 支持(Aggregate Key 模型) |
| JOIN 支持 | 有限(仅 lookup join) | 支持本地字典 JOIN,分布式 JOIN 弱 | 不支持 | 支持 Shuffle Join / Broadcast Join(较新版本) |
| 部署复杂度 | 中高(多组件) | 低(单进程) | 中(类似 Druid) | 中(FE/BE 架构) |
| 适用场景 | 实时监控、用户行为分析、IoT 时序分析 | 日志分析、BI 报表、大规模聚合 | 实时仪表盘、低延迟查询 | 统一 OLAP、替代 Hive + MySQL 场景 |
第二章:Druid 安装与部署
2.1 单机快速启动(micro-quickstart)
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 下载 Druid 发行包 | 从官网 https://druid.apache.org/downloads.html 下载最新 tar.gz 包(如 apache-druid-26.0.0-bin.tar.gz) | 推荐使用稳定版本;需 JDK 8/11/17 |
| 解压并进入目录 | tar -xzf apache-druid-*.tar.gz && cd apache-druid-* | 确保磁盘有至少 4GB 可用空间 |
| 启动 micro-quickstart | 执行 bin/start-micro-quickstart | 该脚本自动启动所有必要服务(Coordinator、Overlord、Broker、Historical、MiddleManager、Router) |
| 验证服务状态 | 访问 http://localhost:8888(Web Console)或检查日志 var/sv/*.log | 首次启动可能需 30~60 秒;确保 8081、8082、8083 等端口未被占用 |
| 停止服务 | 在启动终端按 Ctrl+C,或执行 bin/stop-micro-quickstart | 强制 kill 可能导致临时文件残留 |
2.2 分布式集群部署(基于 Docker / Kubernetes / 原生部署)
| 部署方式 | 操作细节 | 注意事项 |
|---|---|---|
| Docker Compose 部署 | 使用官方 docker-compose.yml(位于 distribution/docker/)执行 docker-compose up -d | 仅用于开发测试;不适用于生产;需预先配置 metadata DB 和 deep storage |
| Kubernetes Helm 部署 | 使用社区 Helm Chart(如 https://github.com/apache/druid/tree/master/distribution/k8s)执行 helm install druid ./chart | 需提前创建 PVC、ConfigMap、Secret;建议启用 StatefulSet 管理 Historical 节点 |
| 原生分布式部署 | 在多台机器上分别启动各角色服务:Coordinator+Overlord(主节点)、Broker(查询节点)、Historical(存储节点)、MiddleManager(摄入节点) | 所有节点需共享同一 common.runtime.properties;依赖外部 ZooKeeper、Metadata DB、Deep Storage |
| 共享依赖配置 | ZooKeeper:用于服务发现;Metadata DB:MySQL/PostgreSQL;Deep Storage:S3/HDFS/本地 NFS | 必须确保网络互通;ZooKeeper 集群建议 3 节点;Metadata DB 需建表(运行 extensions-core/mysql-metadata-storage 中的 DDL) |
2.3 配置文件详解(common.runtime.properties、jvm.config 等)
| 配置文件 | 关键参数 | 用途说明 | 注意事项 |
|---|---|---|---|
conf/druid/single-server/micro-quickstart/_common/common.runtime.properties | druid.zk.service.host=localhost、druid.metadata.storage.connector.connectURI=jdbc:derby://...、druid.storage.type=local、druid.extensions.loadList=["druid-hdfs-storage", "mysql-metadata-storage"] | 定义 ZooKeeper 地址、元数据存储、Deep Storage 类型、扩展插件 | 生产环境必须替换 Derby 为 MySQL/PostgreSQL;local storage 仅用于单机 |
conf/druid/*/runtime.properties | druid.server.http.numThreads=30、druid.processing.numThreads=2 | 控制 HTTP 线程池和查询处理线程数 | 根据 CPU 核心数调整;避免过度分配 |
jvm.config | -server、-Xms4g、-Xmx4g、-XX:MaxDirectMemorySize=6g | JVM 启动参数,控制堆内存和堆外内存 | Historical 节点需较大 DirectMemory;MiddleManager 每个 Peon 有独立 jvm.config |
log4j2.xml | <Configuration><Appenders><File name="fileAppender">...</File></Appenders></Configuration> | 日志输出格式与路径 | 默认日志位于 var/sv/*.log;可配置滚动策略避免磁盘占满 |
2.4 启动与停止服务的命令行操作
| 操作名称 | 命令示例 | 说明 | 注意事项 |
|---|---|---|---|
| 启动单个服务(原生部署) | java -cp "conf/druid/coordinator:/lib/*" org.apache.druid.cli.Main server coordinator | 手动启动 Coordinator 服务 | 需先设置 CLASSPATH;建议使用 bin/run-druid.sh 封装脚本 |
使用 run-druid.sh 启动 | bin/run-druid.sh coordinator conf/druid/coordinator | 官方推荐方式,自动加载 jvm.config 和 classpath | 脚本位于 bin/ 目录;需赋予执行权限 |
| 停止单个进程 | kill -TERM <pid> 或 pkill -f "Main server coordinator" | 平滑终止服务 | 避免使用 kill -9,可能导致 Segment 状态不一致 |
| 查看运行服务 | ps aux | grep druid 或 jps -l | grep Main | 检查各角色是否运行 | |
| 重启服务 | 先 stop,再 start;或使用 systemd(若配置) | 适用于配置变更后生效 | 修改 common.runtime.properties 后通常需全集群重启 |
| 查看端口占用 | netstat -tuln | grep :8081 | 验证服务监听状态 | 默认端口:Coordinator: 8081、Overlord: 8090、Broker: 8082、Historical: 8083、MiddleManager: 8091 |
第三章:数据摄入(Ingestion)
3.1 数据摄入方式概览(本地文件、Kafka、HDFS、S3 等)
| 摄入源类型 | 支持方式 | 说明 | 注意事项 |
|---|---|---|---|
| 本地文件(Local File) | Batch Ingestion | 通过 local input source 读取本地 JSON/CSV 文件 | 仅适用于单机或所有 MiddleManager 节点可访问该路径;不适用于分布式集群生产环境 |
| Kafka | Streaming Ingestion | 使用 kafka input source + Supervisor 实现实时摄入 | 需启用 Kafka Indexing Service;支持 Exactly-Once 语义(需配置 transactional.id) |
| HDFS | Batch Ingestion | 通过 hdfs input source 读取 HDFS 上的文件 | 需加载 druid-hdfs-storage 扩展;确保所有节点有 Hadoop 配置(core-site.xml 等) |
| Amazon S3 | Batch / Streaming | 使用 s3 input source(Batch)或从 S3 读取 Checkpoint(Streaming) | 需配置 AWS 凭据(accessKey/secretKey 或 IAM Role);加载 druid-s3-extensions |
| HTTP | Batch Ingestion | 通过 http input source 从 URL 下载文件 | 适用于临时调试;不推荐用于大文件或高频率摄入 |
| Kinesis | Streaming Ingestion | 类似 Kafka,使用 kinesis input source | 需加载 druid-kinesis-indexing-service 扩展;依赖 AWS SDK |
3.2 批量摄入(Batch Ingestion)命令行操作
| 操作名称 | 命令/步骤 | 说明 | 注意事项 |
|---|---|---|---|
| 准备摄入规范(ingestion spec) | 编写 JSON 文件(如 wikiticker-index.json),包含 type: "index_parallel" 或 "index" | 定义 inputSource、inputFormat、dimensionsSpec、metricsSpec、granularitySpec 等 | 使用 index_parallel 可并行处理;index 为单线程(仅 micro-quickstart) |
| 提交批量任务 | curl -X POST -H "Content-Type: application/json" --data-binary @wikiticker-index.json http://localhost:8090/druid/indexer/v1/task | 向 Overlord 提交任务 | 确保 Overlord 正在运行(默认端口 8090) |
| 本地文件示例 inputSource | "inputSource": { "type": "local", "baseDir": "quickstart/tutorial/", "filter": "wikiticker-2015-09-12-sampled.json.gz" } | 读取本地目录下的文件 | 文件路径相对于 MiddleManager 工作目录;压缩格式(.gz/.zip)自动解压 |
| HDFS 示例 inputSource | "inputSource": { "type": "hdfs", "uris": ["hdfs://namenode:9000/data/wikiticker.json"] } | 从 HDFS 读取 | 需在 common.runtime.properties 中启用 druid.extensions.loadList += "druid-hdfs-storage" |
| 验证数据是否加载 | 查询 DataSource 列表:curl http://localhost:8082/druid/v2/datasources | 检查新 DataSource 是否出现 | 数据通常在任务成功后 1~2 分钟内可查 |
3.3 流式摄入(Streaming Ingestion)配置与管理
| 配置项 | 语法/值 | 用途 | 注意事项 |
|---|---|---|---|
| Supervisor Spec 类型 | "type": "kafka" 或 "type": "kinesis" | 定义流式数据源 | 必须部署对应扩展(如 druid-kafka-indexing-service) |
| topic / stream 名称 | "topic": "my-topic"(Kafka)"stream": "my-stream"(Kinesis) | 指定数据流 | Kafka 需提前创建 topic;Kinesis 需存在 stream |
| Task Count 与 Replicas | "taskCount": 2, "replicas": 1 | 控制并行消费者数量 | taskCount 决定分区分配数;replicas 用于高可用(>=2) |
| Start Offset | "useEarliestOffset": true 或 "specificOffsets": {"0": 1000} | 控制消费起始位置 | 首次启动建议设为 useEarliestOffset: true |
| 提交 Supervisor | curl -X POST -H "Content-Type: application/json" --data-binary @supervisor-spec.json http://localhost:8090/druid/indexer/v1/supervisor | 启动流式摄入 | 成功返回 Supervisor ID |
| 停止 Supervisor | curl -X POST http://localhost:8090/druid/indexer/v1/supervisor/<supervisor_id>/shutdown | 停止并清理任务 | 会终止所有关联的 indexing task |
| 查看 Supervisor 状态 | curl http://localhost:8090/druid/indexer/v1/supervisor?full | 获取详细状态(包括 lag、task 状态) | lag 字段反映消费延迟 |
3.4 摄入任务提交与状态查询(使用 curl / CLI)
| 操作名称 | 命令示例 | 用途 | 注意事项 |
|---|---|---|---|
| 提交任意 ingestion task | curl -X POST -H "Content-Type: application/json" --data-binary @task.json http://<OVERLORD_HOST>:8090/druid/indexer/v1/task | 通用任务提交接口 | task.json 中 type 决定任务类型(index、index_parallel、kafka 等) |
| 查询所有任务列表 | curl http://<OVERLORD_HOST>:8090/druid/indexer/v1/tasks | 查看当前运行/完成的任务 | 返回 JSON 数组,含 id、type、status、dataSource 等字段 |
| 查询特定任务状态 | curl http://<OVERLORD_HOST>:8090/druid/indexer/v1/task/<task_id>/status | 获取任务状态(RUNNING/SUCCESS/FAILED) | 可用于自动化脚本判断任务结果 |
| 取消运行中任务 | curl -X POST http://<OVERLORD_HOST>:8090/druid/indexer/v1/task/<task_id>/shutdown | 终止任务 | 仅对 RUNNING 状态有效;已提交的 Segment 不会回滚 |
| 查看任务日志 | curl http://<MIDDLEMANAGER_HOST>:8091/druid/worker/v1/chat/<task_id>/log | 获取 Peon 进程日志 | 需知道任务所在 MiddleManager 地址;日志也可在 var/task/ 目录查看 |
| 重试失败任务 | 重新提交相同的 task spec(或修改后) | 手动恢复失败摄入 | 建议先分析失败原因(如 schema mismatch、网络超时) |
第四章:数据查询(Query)
4.1 查询类型介绍(Timeseries、TopN、GroupBy、Scan、Search)
| 查询类型 | 语法结构要点 | 用途 | 注意事项 |
|---|---|---|---|
| Timeseries | 必须包含 "queryType": "timeseries"、"granularity"(如 "hour")、"aggregations" | 按时间粒度聚合指标(如每小时总点击量) | 不支持维度分组;仅返回时间桶 + 聚合值;性能最优 |
| TopN | "queryType": "topN"、"dimension"(排序维度)、"threshold"(返回前 N)、"metric"(排序依据) | 获取某维度下指标最高的 Top N 记录(如热门商品) | 仅支持单维度排序;比 GroupBy 更高效(尤其高基数场景) |
| GroupBy | "queryType": "groupBy"、"dimensions"(数组)、"limitSpec"(可选) | 多维分组聚合(类似 SQL GROUP BY) | 资源消耗大;结果集大时需配置 maxResults;支持 post-aggregations |
| Scan | "queryType": "scan"、"columns"(可选字段列表)、"batchSize" | 扫描原始数据(类似 SELECT *) | 不做聚合;用于数据导出或调试;性能较差,避免高并发使用 |
| Search | "queryType": "search"、"searchDimensions"、"query"(含 "type": "insensitive_contains" 等) | 在维度值中模糊搜索(如查找包含 “admin” 的用户) | 仅适用于低基数维度;不支持指标字段;已标记为 deprecated(推荐用 SQL 替代) |
4.2 使用 HTTP API 发起查询(curl 示例)
| 查询类型 | curl 命令示例 | 说明 | 注意事项 |
|---|---|---|---|
| Timeseries | curl -X POST http://localhost:8082/druid/v2/ -H "Content-Type: application/json" --data-binary '{"queryType":"timeseries","dataSource":"wikiticker","intervals":["2015-09-12/2015-09-13"],"granularity":"hour","aggregations":[{"type":"count","name":"rows"},{"type":"longSum","name":"added","fieldName":"added"}]}' | 每小时统计行数和 added 总和 | intervals 必须指定;时间格式为 ISO8601 |
| TopN | curl -X POST http://localhost:8082/druid/v2/ -H "Content-Type: application/json" --data-binary '{"queryType":"topN","dataSource":"wikiticker","intervals":["2015-09-12/2015-09-13"],"dimension":"channel","threshold":5,"metric":"edits","aggregations":[{"type":"longSum","name":"edits","fieldName":"count"}],"granularity":"all"}' | 获取编辑次数最多的前 5 个 channel | metric 可为聚合字段名或预定义排序规则 |
| GroupBy | curl -X POST http://localhost:8082/druid/v2/ -H "Content-Type: application/json" --data-binary '{"queryType":"groupBy","dataSource":"wikiticker","intervals":["2015-09-12/2015-09-13"],"dimensions":["countryName","regionName"],"aggregations":[{"type":"count","name":"rows"}],"granularity":"all"}' | 按国家和地区分组统计行数 | 结果可能很大,建议加 limitSpec 控制返回数量 |
| Scan | curl -X POST http://localhost:8082/druid/v2/ -H "Content-Type: application/json" --data-binary '{"queryType":"scan","dataSource":"wikiticker","intervals":["2015-09-12/2015-09-13"],"columns":["__time","channel","cityName"],"resultFormat":"compactedList","batchSize":10000}' | 导出指定字段的原始数据 | batchSize 控制每批返回行数;避免全表扫描生产环境 |
| SQL 查询 | curl -X POST http://localhost:8082/druid/v2/sql/ -H "Content-Type: application/json" --data-binary '{"query":"SELECT channel, COUNT(*) AS cnt FROM wikiticker WHERE __time >= ''2015-09-12'' GROUP BY channel ORDER BY cnt DESC LIMIT 5"}' | 使用 SQL 语法查询 | 需 Broker 启用 SQL 支持(默认开启);字符串需转义单引号 |
4.3 使用 druid-cli 或其他命令行工具执行查询
| 工具名称 | 使用方式 | 说明 | 注意事项 |
|---|---|---|---|
| druid sql CLI | bin/druid.sh sql --host localhost:8082(进入交互模式后输入 SQL) | 官方提供的 SQL 命令行客户端 | 需 Druid 0.16+;依赖 Java;自动处理连接和结果格式化 |
| 直接调用 Avatica JDBC(通过 sqlline) | ./sqlline,然后 !connect jdbc:avatica:remote:url=http://localhost:8082/druid/v2/sql/avatica/ | 利用 Apache Calcite Avatica 协议 | 需下载 sqlline 和 avatica driver;适用于 JDBC 兼容工具链 |
| 自定义脚本(bash + curl) | 编写 shell 脚本封装 curl 命令,传入参数动态生成 JSON | 适用于自动化监控或 ETL 流程 | 需处理 JSON 转义(可用 jq 工具辅助构造 payload) |
| 使用 dsql(社区工具) | dsql --broker http://localhost:8082 "SELECT COUNT(*) FROM wikiticker" | 第三方轻量 CLI(非官方) | 需单独安装;简化 SQL 调用,但功能有限 |
4.4 查询性能调优参数说明
| 参数名称 | 所在配置文件/位置 | 作用 | 注意事项 |
|---|---|---|---|
druid.processing.numThreads | runtime.properties(各节点) | 控制每个节点用于查询处理的线程数 | 建议设为 CPU 核心数 -1;过高导致上下文切换开销 |
druid.processing.buffer.sizeBytes | runtime.properties | 单个处理缓冲区大小(默认 500MB) | 大查询(如 GroupBy)需增大;受 DirectMemory 限制 |
druid.query.groupBy.maxResults | common.runtime.properties | GroupBy 查询最大返回行数(默认 500,000) | 超限会报错;可根据内存调整,但避免过大 |
druid.broker.cache.useCache / druid.broker.cache.populateCache | broker/runtime.properties | 启用/写入查询结果缓存 | 需配置 cache.type(如 local、memcached);对重复查询有效 |
druid.historical.cache.useCache | historical/runtime.properties | Historical 节点启用缓存 | 与 Broker 缓存协同工作;减少重复计算 |
druid.sql.planner.maxSubqueryRows | common.runtime.properties | SQL 子查询最大行数限制 | 防止爆炸性中间结果;默认 100,000 |
| query context 参数(运行时) | 在查询 JSON 中添加 "context": {"priority": 10, "timeout": 30000} | 动态控制单次查询行为 | timeout 单位毫秒;priority 影响调度顺序(高优先级先执行) |
第五章:命令行工具与运维操作
5.1 常用 CLI 工具介绍(druid.sh、indexer.sh、router.sh 等)
| 工具名称 | 调用方式 | 功能说明 | 注意事项 |
|---|---|---|---|
druid.sh | bin/druid.sh <role> <config_dir>,例如:bin/druid.sh coordinator conf/druid/coordinator | 启动任意 Druid 角色服务(coordinator、overlord、broker 等) | 是 run-druid.sh 的封装;自动加载 jvm.config 和 classpath;推荐用于开发调试 |
indexer.sh | bin/indexer.sh --configFile conf/druid/middleManager/runtime.properties --task task.json | 本地运行 ingestion task(无需 Overlord) | 仅用于测试 ingestion spec;不适用于生产流式摄入 |
router.sh | bin/router.sh conf/druid/router | 启动 Router 服务,统一 API 入口 | 非必需组件;适用于多集群路由或简化客户端配置 |
query.sh | bin/query.sh --url http://localhost:8082 --query @query.json | 执行原生 JSON 查询(实验性工具) | 官方未正式维护;建议优先使用 curl 或 SQL CLI |
sql.sh | bin/sql.sh --host localhost:8082 | 启动交互式 SQL CLI(Druid 0.20+ 内置) | 支持历史命令、自动补全;等价于 druid sql 子命令 |
5.2 Segment 管理(加载、卸载、删除、复制)
| 操作名称 | 命令/HTTP 请求示例 | 说明 | 注意事项 |
|---|---|---|---|
| 手动加载 Segment | curl -X POST "http://<COORDINATOR>:8081/druid/coordinator/v1/datasources/<DATASOURCE>/segments/<SEGMENT_ID>/load" | 强制 Historical 加载指定 Segment | Segment 必须已存在于 Deep Storage;通常由 Coordinator 自动管理 |
| 卸载 Segment | curl -X DELETE "http://<COORDINATOR>:8081/druid/coordinator/v1/datasources/<DATASOURCE>/segments/<SEGMENT_ID>" | 从集群中卸载 Segment(内存释放) | 数据仍保留在 Deep Storage;可重新加载 |
| 删除 Segment(彻底) | curl -X DELETE "http://<COORDINATOR>:8081/druid/coordinator/v1/datasources/<DATASOURCE>/segments?kill=true"(或针对单个:curl -X DELETE ".../<SEGMENT_ID>?kill=true") | 从 Metadata Storage 和 Deep Storage 中永久删除 | 危险操作;确保无查询依赖;需 Coordinator 配置 druid.coordinator.kill.on 相关参数启用 |
| 复制 Segment(增加副本) | 在 Coordinator UI 或通过规则(Rule)配置:{"type": "loadForever", "tieredReplicants": {"_default_tier": 2}} | 提高可用性或查询吞吐 | 通过 Rule 管理,非直接命令;副本数由 tieredReplicants 控制 |
| 查看所有 Segments | curl http://<COORDINATOR>:8081/druid/coordinator/v1/datasources/<DATASOURCE>/segments | 列出 DataSource 下所有 Segment 元数据 | 返回包含 ID、大小、时间范围、副本状态等信息 |
5.3 任务管理(查看、取消、重试 ingestion 任务)
| 操作名称 | 命令/HTTP 请求示例 | 说明 | 注意事项 |
|---|---|---|---|
| 查看所有任务 | curl http://<OVERLORD>:8090/druid/indexer/v1/tasks | 列出当前系统中所有 ingestion 任务(运行中/已完成) | 返回 JSON 数组,含 id、type、status、dataSource、runnerStatus 等 |
| 查看特定任务详情 | curl http://<OVERLORD>:8090/druid/indexer/v1/task/<TASK_ID> | 获取任务完整 spec 和状态 | 可用于审计或调试失败原因 |
| 取消运行中任务 | curl -X POST http://<OVERLORD>:8090/druid/indexer/v1/task/<TASK_ID>/shutdown | 终止正在运行的任务 | 仅对 RUNNING 状态有效;已写入的 Segment 不会回滚 |
| 重试失败任务 | 重新提交原始 task spec(或修正后):curl -X POST ... --data-binary @fixed-task.json ... | 手动恢复失败摄入 | 建议先检查日志定位失败原因(如 schema mismatch、网络超时) |
| 查看任务日志(远程) | curl http://<MIDDLEMANAGER_HOST>:8091/druid/worker/v1/chat/<TASK_ID>/log | 获取 Peon 进程的标准输出日志 | 需知道任务所在 MiddleManager 地址;也可在 var/task/<TASK_ID>/log 查看本地文件 |
| 清理已完成任务记录 | curl -X DELETE http://<OVERLORD>:8090/druid/indexer/v1/tasks?state=SUCCESS&olderThan=PT24H | 删除 24 小时前的成功任务元数据 | 减少 Metadata Storage 负担;不影响实际数据 |
5.4 监控与日志查看(通过命令行定位问题)
| 操作名称 | 命令示例 | 说明 | 注意事项 |
|---|---|---|---|
| 查看服务日志 | tail -f var/sv/coordinator.log、grep "ERROR" var/sv/broker.log | 实时跟踪或过滤错误日志 | 日志路径为 var/sv/<service>.log;也可按日期滚动(如 .log.2026-02-01) |
| 查看任务日志 | cat var/task/index_parallel_xxx/log | 检查 ingestion 任务执行细节 | 每个任务独立目录;包含 stdout、stderr 和 taskStatus.json |
| 检查 JVM 状态 | jstat -gc <PID>、jstack <PID> > thread_dump.txt | 分析 GC 压力或线程阻塞 | 需安装 JDK 工具;Historical 节点常因 DirectMemory 不足 OOM |
| 查看端口监听 | netstat -tuln | grep :8082 | 验证 Broker 是否正常监听 | 默认端口:Coordinator: 8081、Overlord: 8090、Broker: 8082、Historical: 8083 |
| 检查磁盘使用 | du -sh var/、df -h | 监控 Segment 缓存和日志占用 | Historical 节点的 var/druid/segment-cache 可能快速增长 |
| 使用 status API | curl http://<BROKER>:8082/status、curl http://<COORDINATOR>:8081/druid/coordinator/v1/leader | 获取服务健康状态和角色信息 | status API 返回版本、内存、模块等基本信息 |
| 检查 ZooKeeper 注册 | echo dump | nc localhost 2181 | grep druid | 验证各服务是否成功注册到 ZK | 需安装 netcat;路径通常为 /druid/discovery |
第六章:安全与权限控制(可选)
6.1 启用基本认证(Basic Auth)
| 操作名称 | 配置步骤 / 参数 | 说明 | 注意事项 |
|---|---|---|---|
启用 druid-basic-security 扩展 | 在 common.runtime.properties 中添加:druid.extensions.loadList=["druid-basic-security", ...] | 加载基础安全模块 | 必须在所有节点(Coordinator、Broker 等)统一配置 |
| 配置用户凭证 | 在 conf/druid/*/basic-security.json 中定义:{ "users": { "admin": { "password": "secret", "roles": ["admin"] } } } | 声明用户名、密码(明文或 SHA256)、角色 | 密码建议使用 SHA256(如 echo -n "secret" | sha256sum);文件需对 Druid 进程可读 |
| 启用认证过滤器 | 在各服务 runtime.properties 中添加:druid.auth.authenticatorChain=["MyBasicAuthenticator"]、druid.auth.basic.passwordValidator.type=sha256 | 指定认证器链和密码校验方式 | authenticator 名称(如 MyBasicAuthenticator)需与配置文件中一致 |
| 为 Coordinator/Overlord 启用 | 在 coordinator/runtime.properties 添加:druid.auth.authorizer.type=basic | 启用基于角色的授权 | 需配合 authorizer 配置(见 6.3 节) |
| 测试认证 | curl -u admin:secret http://localhost:8081/druid/coordinator/v1/datasources | 验证是否返回数据而非 401 | 若未授权,返回 HTTP 401 Unauthorized |
6.2 配置 TLS/SSL
| 操作名称 | 配置步骤 / 参数 | 说明 | 注意事项 |
|---|---|---|---|
| 生成 Keystore(自签名) | keytool -genkeypair -alias druid -keyalg RSA -keystore druid.keystore.jks -storepass changeit | 创建服务器证书存储 | 用于 HTTPS 服务端;生产环境应使用 CA 签发证书 |
| 配置 Broker 启用 HTTPS | 在 broker/runtime.properties 添加:druid.server.https.port=8282、druid.server.https.keyStorePath=/path/to/druid.keystore.jks、druid.server.https.keyStorePassword=changeit | 启用 HTTPS 监听 | HTTP 仍可同时启用;建议禁用 HTTP(设 druid.server.http.port=-1) |
| 配置客户端信任(如 Overlord 访问 Broker) | 在调用方(如 Overlord)配置:druid.client.https.trustStorePath=/path/to/truststore.jks、druid.client.https.trustStorePassword=changeit | 使内部服务间通信支持 TLS | 若使用自签名证书,需将公钥导入 truststore:keytool -importcert -file druid.crt -keystore truststore.jks |
| 启用 ZooKeeper SSL(可选) | 在 common.runtime.properties 设置 druid.zk.service.host=zookeeper1:2181,zookeeper2:2181 并配置 JVM 参数:-Dzookeeper.client.secure=true -Dzookeeper.ssl.trustStore.location=... | 加密 ZK 通信 | 需 ZooKeeper 3.5+ 支持 TLS |
| 强制重定向 HTTP → HTTPS(Router) | 在 Router 配置中启用:druid.router.http.redirectToHttps=true | 自动升级连接 | 仅当 Router 同时监听 HTTP/HTTPS 时生效 |
6.3 基于角色的访问控制(RBAC)配置
| 配置项 | 配置位置与语法 | 用途 | 注意事项 |
|---|---|---|---|
| 定义角色权限 | 在 basic-security.json 的 authorizers 部分配置,资源类型包括 DATASOURCE、CONFIG、STATE、SERVICE | 控制角色对资源的操作权限 | 示例:{"resource": {"type": "DATASOURCE", "name": "sales"}, "action": "READ"} |
| 绑定用户到角色 | 在 basic-security.json 的 users 部分:"admin": { "password": "...", "roles": ["MyRole"] } | 用户继承角色权限 | 一个用户可拥有多个角色 |
| 启用 Authorizer | 在各服务 runtime.properties 添加:druid.auth.authorizer.type=basic、druid.auth.basic.authorizer.name=MyAuthorizer | 激活 RBAC 授权检查 | 必须与 basic-security.json 中的 authorizer 名称一致 |
| 权限粒度说明 | DATASOURCE: 控制查询/写入特定 DataSource、CONFIG: 控制修改 ingestion spec/rules 等、STATE: 控制查看集群状态(如 segments/tasks)、SERVICE: 控制访问 Coordinator/Overlord API | 精细化权限管理 | action 取值:READ、WRITE、ALL |
| 验证权限 | curl -u analyst:pass -X POST http://localhost:8090/druid/indexer/v1/task --data-binary @task.json | 测试是否拒绝无权限操作 | 若用户无 CONFIG WRITE 权限,将返回 403 Forbidden |
第七章:性能调优与最佳实践
7.1 数据模型设计建议(维度 vs 指标、Rollup 优化)
| 概念/策略 | 说明 | 注意事项 |
|---|---|---|
| 维度(Dimensions) | 用于过滤、分组的字符串或低基数字段(如 country、status) | 避免将高基数字段(如 user_id、trace_id)设为维度,否则导致 Bitmap 和字典膨胀,显著增加内存和磁盘占用 |
| 指标(Metrics) | 用于聚合计算的数值字段(如 count、sum、max) | 支持 longSum、doubleSum、hyperUnique、thetaSketch 等;预聚合可大幅提升查询性能 |
| 启用 Rollup | 在 ingestion spec 中设置 "rollup": true,对相同时间桶+维度组合的数据进行写入时聚合 | 开启后原始明细数据丢失;适用于监控、日志汇总等场景;不适用于需保留每条事件的分析 |
| 时间粒度选择 | queryGranularity 控制写入聚合粒度(如 "minute"),segmentGranularity 控制 Segment 切分周期(如 "HOUR") | 更粗的 queryGranularity 提升压缩率但损失精度;segmentGranularity 过小导致 Segment 数量爆炸 |
| 使用 Sketch 近似去重 | 对高基数去重使用 thetaSketch 或 hyperUnique 而非 exact count distinct | 显著降低存储和计算开销;误差可控(通常 <2%);需加载对应扩展(如 datasketches extension) |
7.2 Segment 大小与分区策略
| 策略项 | 推荐配置 | 说明 | 注意事项 |
|---|---|---|---|
| 单个 Segment 行数 | 300 万 ~ 700 万行 | 平衡查询性能与管理开销;过小导致任务碎片化,过大影响 Historical 加载速度和内存使用 | |
| Segment 文件大小 | 300 MB ~ 700 MB(压缩后) | 可通过 tuningConfig.maxRowsPerSegment 或 maxTotalRows 控制 | 实际大小受列数、基数、压缩算法影响;建议监控生产环境实际值 |
| 分区类型(Partitioning) | 批处理推荐 hashed 或 single_dim;流式使用 dynamic | hashed 均匀分布;single_dim 按某维度(如 tenant_id)分片,利于局部查询 | 流式摄入默认 dynamic partitioning,自动控制 Segment 大小 |
| 时间切分粒度 | 根据数据量选择:小数据量 DAY、中等 HOUR、高吞吐 FIVE_MINUTE | 由 segmentGranularity 控制 | 过细(如 MINUTE)导致元数据压力大;过粗(如 MONTH)影响查询裁剪效率 |
| 避免小文件问题 | 设置 tuningConfig.maxRowsInMemory ≥ 500,000;启用 forceGuaranteedRollup=true(批处理) | 减少生成大量微小 Segment | 小 Segment 会显著增加 Coordinator 和 Historical 负担 |
7.3 历史节点与 MiddleManager 资源调优
| 组件 | 关键参数 | 推荐值 / 说明 | 注意事项 |
|---|---|---|---|
| Historical 节点 | druid.processing.numThreads | CPU 核心数 - 1 | 控制并行查询线程;过高导致上下文切换 |
druid.processing.buffer.sizeBytes | 536870912(500MB)或更高 | 单个缓冲区大小;大 GroupBy 查询需增大 | |
druid.server.maxSize | 总内存的 70%(如 30GB) | 控制 Segment 缓存上限;超过则触发淘汰 | |
druid.segmentCache.locations | 指向高速 SSD 目录 | 加速 Segment 加载;避免使用机械盘 | |
| MiddleManager | druid.worker.capacity | CPU 核心数 / 2(如 4) | 控制并发 Peon 任务数;每个任务独占资源 |
druid.indexer.runner.javaOptsArray | ["-Xmx4g", "-XX:MaxDirectMemorySize=6g"] | 单个 Peon 的 JVM 配置 | |
druid.indexer.task.baseTaskDir | 指向大容量磁盘 | 存放中间文件;摄入期间可能临时占用数倍原始数据空间 | |
| 共同注意 | 所有节点需配置足够堆外内存(-XX:MaxDirectMemorySize) | 建议 ≥ numThreads × bufferSize | 不足会导致 OOM 或性能骤降 |
7.4 查询缓存与 Broker 配置优化
| 优化项 | 配置参数 | 说明 | 注意事项 |
|---|---|---|---|
| 启用本地缓存 | 在 broker/runtime.properties 设置:druid.broker.cache.useCache=true、druid.broker.cache.populateCache=true、druid.cache.type=local | 缓存查询结果(基于查询 JSON 哈希) | 仅对确定性查询有效(无 NOW()、RANDOM());缓存命中返回更快 |
| 缓存大小控制 | druid.cache.sizeInBytes=2147483648(2GB) | 限制本地缓存最大内存 | 过大会挤占查询处理内存;建议 ≤ 20% 堆内存 |
| 使用分布式缓存 | 配置 druid.cache.type=memcached 并设置 druid.cache.memcached.hosts=localhost:11211 | 多 Broker 共享缓存 | 需部署 Memcached 集群;网络延迟可能抵消收益 |
| Broker 查询队列 | druid.broker.http.numConnections=20、druid.broker.http.maxQueuedBytes=104857600 | 控制下游连接和排队 | 防止突发查询压垮 Historical |
| 查询超时与优先级 | 在查询 context 中设置:"context": {"timeout": 60000, "priority": 5} | 动态控制单次查询行为 | timeout 单位毫秒;priority 越高越优先调度(默认 0) |
| 结果合并优化 | druid.broker.merge.useParallelMerge=true | 并行合并多节点结果 | 适用于宽表或大结果集;需足够 CPU 资源 |
| 禁用昂贵操作 | druid.sql.planner.metadataQueryMaxBytesPerDimension=100000 | 限制 metadata 查询开销 | 防止 SELECT * FROM INFORMATION_SCHEMA 导致 OOM |
第八章:集成与生态
8.1 与 Superset / Grafana 集成
| 集成工具 | 配置步骤 / 连接参数 | 说明 | 注意事项 |
|---|---|---|---|
| Apache Superset | 1. 在 Superset 中添加 Database;2. SQLAlchemy URI 填写:druid://<BROKER_HOST>:8082/druid/v2/sql/;3. 测试连接 | 使用内置 Druid SQLAlchemy 方言 | 需 Superset ≥ 1.0;Druid 必须启用 SQL(默认开启);不支持所有 SQL 功能(如 JOIN 有限) |
| Grafana | 1. 安装 druid-plugin;2. 添加 Data Source → URL: http://<BROKER_HOST>:8082;3. 支持原生 JSON 查询或 SQL | 支持时间序列面板(Timeseries、Bar gauge) | 插件需手动安装;SQL 模式更易用;不支持复杂 GroupBy 可视化 |
| 连接验证 | 在 Superset 执行:SELECT __time, COUNT(*) FROM wikiticker GROUP BY TIME_FLOOR(__time, 'PT1H');在 Grafana 使用 Explore 输入相同 SQL | 验证时间序列查询是否返回数据 | 时间字段必须为 __time;Grafana 要求结果含时间列和数值列 |
| 认证配置(如启用 Basic Auth) | Superset URI 示例:druid://admin:secret@broker:8082/druid/v2/sql/;Grafana 在 Data Source 设置中填写用户名/密码 | 传递凭证到 Druid Broker | 明文密码存在风险;生产环境建议配合 TLS |
8.2 与 Flink / Spark / Kafka Connect 集成
| 集成系统 | 集成方式 | 配置要点 | 注意事项 |
|---|---|---|---|
| Apache Flink | 使用 Flink SQL + Druid Sink 或自定义 RichSinkFunction 发送 JSON 到 Kafka(由 Druid 消费) | 推荐路径:Flink → Kafka → Druid(流式摄入) | 官方无原生 Flink Sink;直写可靠性低;Kafka 中间层提供缓冲和重试 |
| Apache Spark | 使用批处理写入 HDFS/S3,再由 Druid 批量摄入;或通过 spark-druid-connector(社区项目) | 示例:df.write.format("druid").option("druid.overlord.url", "http://overlord:8090")... | 官方不维护 Spark Connector;生产推荐”Spark → Parquet → Druid Batch Ingestion”链路 |
| Kafka Connect | 使用 Druid Kafka Indexing Service(非 Connect)或第三方 Sink Connector(如 Landoop/kafka-connect-druid) | 官方方案:Druid Supervisor 直接消费 Kafka,无需 Connect | 不推荐通过 Kafka Connect 写 Druid;Supervisor 更高效、Exactly-Once 支持更好 |
| 数据格式要求 | 所有上游系统输出需为 JSON 或 CSV,含 __time 字段 | 时间字段示例:{"__time": "2026-02-01T12:00:00Z", "user": "alice", "count": 1} | 时间格式必须为 ISO8601 或毫秒时间戳;Druid 不做 ETL 转换 |
8.3 使用 SQL 查询 Druid(通过 Avatica 或内置 SQL)
| 查询方式 | 连接方法 / 示例 | 说明 | 注意事项 |
|---|---|---|---|
| 内置 HTTP SQL API | curl -X POST http://<BROKER>:8082/druid/v2/sql/ -H "Content-Type: application/json" --data-binary '{"query":"SELECT channel, SUM(added) FROM wikiticker WHERE __time >= '\''2015-09-12'\'' GROUP BY channel LIMIT 5"}' | 最简 SQL 调用方式 | 字符串需转义单引号(' → '\'');支持 EXPLAIN 查看逻辑计划 |
| JDBC via Avatica | JDBC URL:jdbc:avatica:remote:url=http://<BROKER>:8082/druid/v2/sql/avatica/,Driver: org.apache.calcite.avatica.remote.Driver | 兼容标准 JDBC 应用(如 DBeaver、Tableau) | 需添加 avatica-client 依赖;连接池建议设置 keep-alive |
| SQL 功能限制 | 不支持跨 DataSource JOIN、子查询有限(maxSubqueryRows 控制)、不支持窗口函数(如 ROW_NUMBER) | 功能对标 ANSI SQL-92 + 部分扩展 | 复杂分析建议预聚合或导出到 Spark |
| 启用/验证 SQL | 默认已启用;检查 Broker 日志含:SqlLifecycleFactory initialized | 无需额外配置(除非显式关闭) | 可通过 druid.sql.enable=true 强制开启(common.runtime.properties) |
| 查询上下文传递 | 在 SQL 请求中附加 context:{ "query": "...", "context": {"priority": 10, "timeout": 30000} } | 控制单次查询行为 | 支持 timeout、priority、useCache 等参数 |