【Druid】架构原理

911 阅读6分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

一、概述

如图: 2021-05-0521-23-11.png

Druid 总体包含以下 6 类节点:

  1. Coordinator node: 主要负责历史节点的数据负载均衡, 以及通过规则管理数据的生命周期。协调节点告诉历史节点加载新数据、卸载过期数据、复制数据、 和为了负载均衡移动数据。
Coordinator 是周期性运行的(由 druid.coordinator.period 配置指定,默认执行间隔为 60s);
Coordinator 需要维护和 ZooKeeper 的连接, 以获取集群的信息。Segment 和 Rule 的信息保存在元数据库中, 所以也需要维护与元数据库的连接。
  1. Overlord node: 进程监视 MiddleManager 进程, 并且是 Druid 数据摄入的主节点。负责将提取任务分配给 MiddleManagers 并协调 Segement 发布, 包括接受、拆解、分配 Task, 以及创建 Task 相关的锁, 并返回 Task 的状态。

  2. Historical node: 加载生成好的数据文件, 以供数据查询。Historical node 是整个集群查询性能的核心所在, Historical 会承担绝大部分的 segment 查询。

Historical 进程从 Deep Storage 中下载 Segment,并响应有关这些 Segment 的查询请求(这些请求来自 Broker 进程);
Historical 进程不处理写入请求;
Historical 进程采用了无共享架构设计,它知道如何去加载和删除 Segment,以及如何基于 Segment 来响应查询。
即便底层的深度存储无法正常工作,Historical 进程还是能针对其已同步的 Segments,正常提供查询服务。
  1. MiddleManager node: 及时摄入实时数据, 生成 Segment 数据文件。
MiddleManager 进程是执行提交任务的工作节点。MiddleManagers 将任务转发给在不同 JVM 中运行的 Peon 进程。MiddleManager、Peon、Task 的对应关系是,每个 Peon 进程一次只能运行一个Task 任务, 但一个MiddleManager 却可以管理多个 Peon 进程。
  1. Broker node: 接收客户端查询请求, 并将这些查询转发给 HistoricalsMiddleManagers。当 Brokers 从这些子查询中收到结果时, 它们会合并这些结果并将它们返回给调用者。
Broker 节点负责转发 Client 查询请求的;
Broker 通过 zookeeper 能够知道哪个 Segment 在哪些节点上, 将查询转发给相应节点;
所有节点返回数据后, Broker 会将所有节点的数据进行合并, 然后返回给 Client;
  1. Router node(可选的): 负责将请求路由到 BrokerCoordinatorsOverlords
Router 进程可以在 Brokers、Overlords 和 Coordinators 进程之上,提供一层统一的 API网关。Router 进程是可选的, 如果集群数据规模已经达到了 TB 级别, 需要考虑启用(druid.router.managementProxy.enabled=true)。

一旦集群规模达到一定的数量级, 那么发生故障的概率就会变得不容忽视, 而 Router 支持将请求只发送给健康的节点, 避免请求失败。同时, 查询的响应时间和资源消耗, 也会随着数据量的增长而变高, 而 Router 支持设置查询的优先级和负载均衡策略, 避免了大查询造成的队列堆积或查询热点等问题。

Druid 的进程可以被任意部署, 为了理解与部署组织方便。这些进程分为了三类:

  • Master: CoordinatorOverlord 负责数据可用性和摄取

  • Query: Broker and Router, 负责处理外部请求

  • Data: Historical and MiddleManager, 负责实际的 Ingestion 负载和数据存储

Druid 还包含 3 类外部依赖:

  1. Deep Storage: 存放生成的 Segment 数据文件, 并供历史服务器下载, 对于单节点集群可以是本地磁盘, 而对于分布式集群一般是 HDFS
Druid 使用 deep storage来做数据的备份, 也作为在Druid进程之间在后台传输数据的一种方式。
当响应查询时,Historical首先从本地磁盘读取预取的段,这也意味着需要在deep storage和加载的数据的Historical中拥有足够的磁盘空间。
  1. Metadata Storage:存储 Druid 集群的元数据信息, 如 Segment 的相关信息, 一般使用 MySQL
表名作用
druid_dataSource存储DataSources,以便 Kafka Index Service查找
druid_pendingSegments存储 pending 的 Segments
druid_segments存储每个 Segments 的metadata 信息
druid_rules关于 Segment 的 load / drop 规则
druid_config存放运行时的配置信息
druid_tasks为Indexing Service 保存 Task 信息
druid_tasklogs为Indexing Service 保存 Task 日志
druid_tasklocks为Indexing Service 保存 Task 锁
druid_supervisors为Indexing Service保存 SuperVisor 信息
druid_audit记录配置、Coordinator规则的变化
  1. Zookeeper: 为 Druid 集群提供以执行协调服务。如内部服务的监控, 协调和领导者选举。
Coordinator 节点的 Leader 选举
Historical 节点发布 Segment 的协议
Coordinator 和 Historical 之间 load / drop Segment 的协议
Overlord 节点的 Leader 选举
Overlord 和 MiddleManager 之间的 Task 管理

二、架构演进

Apache Druid 初始版本架构图 ~ 0.6.0(2012~2013),如图:

2021-05-0617-13-50.png

Apache Druid 旧架构图——数据流转 0.7.0 ~ 0.12.0(2013~2018),如图:

2021-05-0617-15-11.png

Apache Druid 旧架构图——集群管理,如图:

2021-05-0617-15-22.png

0.13.0 ~ 当前版本(2018~now),如图:

2021-05-0617-15-31.png

Lambda 架构

从大的架构上看, Druid 是一个 Lambda 架构。

Lambda 架构是由 Storm 的作者 Nathan Marz 提出的一个实时大数据处理框架。

Lambda 架构设计是为了在处理大规模数据时, 同时发挥流处理和批处理的优势:

  • 通过批处理提供全面、准确的数据
  • 通过流处理提供低延迟的数据

从而达到平衡延迟、吞吐量和容错性的目的, 为了满足下游的即席查询, 批处理和流处理的结果会进行合并。

Lambda 架构包含三层:

  • Batch Layer: 批处理层。对离线的历史数据进行预计算, 为了下游能够快速查询想要的结果。由于批处理基于完整的历史数据集, 准确性可以得到保证。批处理层可以用 HadoopSparkFlink 等框架计算

  • Speed Layer: 加速处理层。处理实时的增量数据, 这一层重点在于低延迟。加速层的数据不如批处理层那样完整和准确, 但是可以填补批处理高延迟导致的数据空白。加速层可以用 StormSpark streamingFlink 等框架计算

  • Serving Layer: 合并层。将历史数据、实时数据合并在一起, 输出到数据库或者其他介质, 供下游分析

如图:

2021-05-0617-18-51.png

流式数据的链路为: Row dataKafkaStreaming processor (Optional, 实时 ETL) → Kafka(Optional) → DruidApplication / User

批处理数据的链路为: Raw dataKafka(Optional) → HDFSETL process(Optional) → DruidApplication / User