type
Post
status
Published
date
Mar 31, 2021 10:58
slug
summary
本文以图书馆类比深入浅出地介绍 Druid 分布式分析型数据存储系统。首先阐述 Druid 的定位与技术特点(高吞吐摄入、低延迟查询、列存储、按时间切分),然后详解五类核心节点架构(Broker 接查询、Indexer 导入、Historical 存储段、Coordinator 调度、外部依赖 ZooKeeper/MetaStore/Deep Storage),并介绍核心概念 DataSource、Event、Segment。数据摄入部分覆盖批处理(本地文件、HDFS、CSV)与实时摄入(Tranquility Server/Kafka、Kafka Indexing Service),对比 Realtime 节点与 Kafka Indexing Service 的优劣。查询部分介绍 REST API 的常用查询类型(Timeseries、TopN、GroupBy、Scan 等)以及 Druid SQL 的启用与使用要点。全文通过生动类比与实战配置帮助读者快速上手 Druid。
tags
Druid
Big Data
ETL
category
Data Engineering
icon
password
wordCount
1987
前言
Druid 是面向大规模时序数据的分布式分析型数据存储与查询系统。它擅长在海量明细上做低延迟聚合,并支持数据实时摄入后“写入即查询”。
适用场景
- 指标看板与实时分析(PV/UV、广告投放、监控告警)
- 需要高并发、低延迟聚合查询的 OLAP 场景
- 数据以时间为主轴,查询以时间范围过滤为主
1. 什么是 Druid
Druid 的核心定位是:
- 面向时序事件(event)数据的在线分析平台
- 支持批处理与流式摄入
- 数据进入集群后可以快速被查询
- 数据一旦落盘后整体上趋于“不可变”,追加新数据比原地更新更常见
2. 技术特点(你会为什么用它)
- 高吞吐摄入:批处理与流式都能跑得动
- 低延迟查询:聚合、TopN、GroupBy 等典型 OLAP 查询响应快
- 面向列存储 + 压缩:成本更可控
- 按时间切分:天然适配按时间窗口检索与汇总
Druid 更像是“分析引擎”,不是事务数据库。需要频繁更新单行数据、强事务语义的场景,通常不适合直接用 Druid。
3. 总体架构(五类核心节点)
先抓住一句话:Broker 接查询,Indexer 负责导入,Historical 负责“拿着段数据回答问题”,Coordinator 负责“指挥段数据放哪儿”,ZooKeeper/MetaStore/Deep Storage 负责“记账与仓库”。
把 Druid 想成一座图书馆(类比记忆)
- 事件数据:新到的书
- Segment:按时间分箱打包的一摞书(一箱就是一个 Segment)
- Deep Storage:总仓库(书的存放地)
- Historical:阅览室,把常用箱子搬到桌上,供读者翻
- Coordinator:馆长,决定哪些箱子该放到哪些阅览室
- Broker:前台,接待读者提问,把问题分发给合适的阅览室再汇总答复
- MetaStore:目录卡(记录每箱书是什么、在哪)
- ZooKeeper:广播系统(谁在线、哪些箱子可借阅)
一条“从写入到查询”的主流程
- 数据导入(Indexer / Realtime)把数据写进 Druid,并生成 Segment
- Segment 落到 Deep Storage,同时元信息写到 MetaStore
- Coordinator 根据规则让 Historical 加载对应 Segment
- 查询到来时,Broker 同时问 Historical(历史段)与实时摄入侧(若有),汇总后返回
3.1 Historical(历史节点)
- 加载已经生成好的 Segment 数据文件
- 提供查询服务
- 启动后会先检查本地缓存是否已有 Segment。
- 本地有就直接加载
- 本地没有就从 Deep Storage 下载,再加载到内存后对外提供查询
3.2 Realtime(实时节点 / 摄入侧)
- 负责实时摄入数据并生成 Segment
- 通常只响应 Broker 的查询请求,把结果返回给 Broker
- 旧数据会按周期 build 成 Segment 并迁移到 Historical
- 常见依赖 Kafka 来提升实时摄入的可用性
3.3 Segment 的制造与传播
- 实时节点生成 Segment,并上传到 Deep Storage
- Segment 元信息写入 MetaStore(常用 MySQL)
- Coordinator 读取元信息,按规则把 Segment 分配给合适的 Historical
- Historical 下载 Segment 并通过 ZooKeeper 声明可查询
- 实时节点丢弃该 Segment,并声明不再提供该 Segment 的查询
3.4 Coordinator(协调节点)
- 负责 Historical 的负载均衡
- 通过规则管理数据源生命周期(加载、下线、复制等)
- 借助 ZooKeeper 发现节点拓扑
- 通过 MetaStore 追踪 Segment 元信息,确保可用与可复制
3.5 Broker(查询入口)
- 对外提供统一查询入口
- 会向实时节点与历史节点发起查询
- 合并结果后返回给调用方
3.6 Indexer(索引 / 导入服务)
- 负责导入数据,支持 batch 与 streaming
- 可通过 API 操作 Segment(合并、删除等)
- 常见组件:
- Peon:执行具体任务
- Middle Manager:管理多个 Peon
- Overlord:接收任务并分配给 Middle Manager
3.7 Router(可选)
- 统一的 API 网关层
- 为 Broker、Overlord、Coordinator 提供统一入口
4. 外部依赖(Druid 不孤单)
- MetaStore(MySQL):存储元数据、规则、配置等
- Deep Storage:存放 Segment(本地磁盘、NFS、HDFS、S3 等)
- ZooKeeper:服务发现与集群状态协调(Segment 可用性声明、节点拓扑等)
5. 概念速记:DataSource 与 Segment
三句话记住三个词
- DataSource:逻辑上的“表”(业务上你看到的数据集名称)
- Event:表里的一行明细(一次点击、一次请求、一条日志)
- Segment:按时间分片后打包存储的一块数据(查询时的主要扫描单元)
5.1 DataSource
类似于关系型数据库里的“表”,是逻辑概念。
DataSource 结构常见由三类列组成:
- 时间列(Timestamp):每行事件发生时间(默认 UTC,精确到毫秒)
- 维度列(Dimension):类别字段,用于分组筛选
- 指标列(Metric):可聚合字段,用于求和、计数、最大最小等
5.2 Segment
物理存储单元。Druid 通过 Segment 对数据做“横切 + 纵切”。
- 横向切割:按时间范围把数据拆成多个段(由
segmentGranularity决定)
- 纵向切割:面向列存储并压缩,提高扫描与聚合效率
6. 数据摄入(Batch 与 Streaming)
6.1 批处理摄入
示例数据(JSON)
本地文件摄入(要点)
- 准备
pageviews_index_local_json_task.json
- 提交任务到 Overlord
HDFS 文件摄入(要点)
- 上传数据到 HDFS
- 将 task 的
ioConfig改为 hadoop 输入
- 提交任务同上
CSV 文件导入(要点)
关键是parseSpec里指定format: "csv"并提供columns。
6.2 实时数据摄入:Pull vs Push
- Pull:启动 Realtime Node,通过 Firehose 从数据源拉取
- Push:通过 Tranquility 或 Kafka Indexing Service 把数据推入
经验上:Realtime Node 的高可用与伸缩能力有限。对生产重要链路,通常更偏向 Tranquility 或 Kafka Indexing Service。
7. Tranquility(Push 摄入)
7.1 Tranquility Server
- 下载并解压 Tranquility
- 使用
server.json配置数据源
- 后台启动服务
发送数据示例:
7.2 Tranquility Kafka
- 先把数据写入 Kafka
- Tranquility Kafka 按配置消费 Kafka 并写入 Druid
时间戳格式注意:时间戳列常用
yyyy-MM-ddTHH:mm:ssZ。格式不对可能导致数据无法解析。8. Kafka Indexing Service
8.1 与 Realtime 节点对比(更直观)
对比项 | Realtime 节点 | Kafka Indexing Service |
重启影响 | 重启慢可能丢窗口外数据 | 重启后仍能继续消费,通常更稳 |
Offset 处理 | 依赖实现与窗口策略 | 通常不会从 beginning 重新读,避免重复 |
定位 | 更偏早期方案或轻量实时 | 生产常用的实时导入方案之一 |
9. 查询(REST API)
9.1 查询入口
对 Broker、Historical 或 Realtime 发起 HTTP REST 风格请求,查询体为 JSON。
9.2 常用查询类型(按场景记)
- Timeseries:按时间窗口聚合
- TopN:取某维度 Top N
- GroupBy:多维分组聚合(功能强,但通常更重)
- Scan / Select:查明细(Scan 常比 Select 更快,且更适合不分页的情况)
- Search:类似模糊匹配
10. 支持 SQL 查询(Druid SQL)
Druid SQL 基于 Apache Calcite,会把 SQL 转成原生查询在 Broker 上执行。除了解析与规划的轻微开销外,性能通常不会比原生查询差。
- 确保在
common.runtime.properties或 Broker 的runtime.properties中设置: druid.sql.enable = true
注:这点和版本、配置、查询路径有关,建议以你当前集群版本与官方文档为准。
参考
- Druid 官网:https://druid.apache.org/
- Querying / Filters / Aggregations 文档(按版本查看):https://druid.apache.org/docs/
