Druid 是一个实时OLAP分布式时序数据库,它的架构保证了它稳定性强、易部署、易维护以及具有广受好评的实时并发查询能力

Apache Druid (incubating) is a real-time analytics database designed for fast slice-and-dice analytics ("OLAP" queries) on large data sets. Druid is most often used as a database for powering use cases where real-time ingest, fast query performance, and high uptime are important. As such, Druid is commonly used for powering GUIs of analytical applications, or as a backend for highly-concurrent APIs that need fast aggregations. Druid works best with event-oriented data.

它有这些组件

  1. broker:响应外部查询,通过zookeeper中的信息将查询请求拆分为对segments的查询,分别转发给Historical和Peon结点,再将查询结果汇总;
  2. router:可以将查询路由到不同的broker,以实现查询的冷热分离。这个组件是可选的;
  3. historical:负责存储和查询历史segments,它将segments从deep storage(如hdfs)中加载并查询结果。它会在本地缓存部分segments;
  4. coordinator-overlord:可以认为是主结点
    1. coordinator:协调历史结点进行数据的加载、卸载、复制segments,连接Zookeeper来同步集群信息,连接MySQL来存储更详细的元信息;
    2. overlord:创建索引任务,写到Zookeeper中,并从Zookeeper中读取任务的执行状态;
  5. middleManager:读取overlord写入到Zookeeper中的任务,创建Peon(Indexing Service的最小工作单元)去执行,Peon在执行过程中会把状态写回Zookeeper。

Druid实现机制总结

  1. 基于segments的时序数据管理系统,以时间和数据量为分片条件,对新数据执行索引任务,建立segments,将已经建立好的不可变segments作为历史数据存储到deep storage(如hdfs);
  2. 索引任务管理流程,包括任务的生成(overlord)、分发(overload->zookeeper->middleManager)、执行(middleManager->Peon)、反馈(Peon->Zookeeper->Overlord),以Zookeeper为存储介质;
  3. 数据查询流程,可选的查询分类、隔离(router),以及对历史数据和索引任务中数据查询的拆分和结果汇总(broker)。

# 问题排查

  1. 启动、停止重启服务

    没有找到官方提供的控制脚本

    启动

    nohup ./bin/supervise -c conf/supervise/cluster/master-no-zk.conf >var/sv/output.log 2>&1 &
    nohup ./bin/supervise -c conf/supervise/cluster/data.conf >var/sv/output.log 2>&1 &
    nohup ./bin/supervise -c conf/supervise/cluster/query.conf >var/sv/output.log 2>&1 &
    
    1
    2
    3

    停止

    # 查看 supervise 进程,获得进程 pid
    ps -few | grep supervise | grep -v grep
    # kill
    kill <supervise pid>
    # 确保已经没有 druid 相关进程
    ps -few | grep druid | grep -v grep
    
    1
    2
    3
    4
    5
    6
  2. 版本 0.16.0 Rest Api 返回结果中的空值被自动省略

    issues #8631中大佬asdf2014定位到了问题,是在版本修改中加上了null的过滤

    row[i] != null in ResultRow#toMap

    在发新版之前先使用0.15版本吧

  3. 找不到日志

    Druid的日志在 var/sv/<组件名>.log,注意这里的 var 是 Druid 目录下的,不是系统的

    修改日志配置需要修改conf/druid/cluster/_common/log4j2.xml

    如下配置为按天和文件大小分割日志

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn" name="Imply" packages="">
    <Appenders>
        <RollingFile name="RollingFile" fileName="var/sv/druid-service.log"
                     filePattern="var/sv/druid-service-%d{yyyy-MM-dd}.%i.log.bak">
        <PatternLayout>
            <Pattern>%d{ISO8601} %p [%t] %c - %m%n</Pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            <SizeBasedTriggeringPolicy size="100 MB"/>
        </Policies>
        <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="info">
        <AppenderRef ref="RollingFile"/>
        </Root>
    </Loggers>
    </Configuration>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
  4. Druid重启导致索引任务失败,索引任务中的segments丢失

    重启 middleManager 后,之前它创建的 Peon 没有启动,对应的 task 是失败状态

    根据官方文档,需要配置参数druid.indexer.task.restoreTasksOnRestart=true

    这个参数是对 overlord 和 middleManager 生效的

    • 没有配置这个参数时,任务出现问题认为会被标记为 failed 状态,这时再修改参数也会无效;配置后,overlord 不会主动修改任务状态,而是一直试图与相应任务重连,过程中任务虽然没有正常工作,状态也是 Running(似乎加一个状态表示比较好)
    • 在 middleManager 的结点的 var/druid/task/ 目录下,可以看到当前正在工作的任务,配置参数后,结点会加载 restore.json,其中有任务的声明
    • 注意这个等待不是无限的,通过参数druid.indexer.task.gracefulShutdownTimeout定义超时时间,默认值为PT5M,5分钟

    更多相关参数见文档

  5. Druid无法写入HDFS

    检查配置是否完整

    • conf/druid/cluster/_common 中有 hdfs-site.xml
    • druid.storage.type = hdfs
    • druid.storage.storageDirectory = hdfs://ns/druid/segments
    • druid.indexer.logs.type = hdfs
    • druid.indexer.logs.directory = hdfs://ns/druid/indexing-logs

    有时hadoop需要指定写入用户

    export HADOOP_USER_NAME=hadoop
    
    1

    注意:其中 ns 为 hdfs-site.xml 中 dfs.nameservices 的值

    <property>
        <name>dfs.nameservices</name>
        <value>ns</value>
    </property>
    
    1
    2
    3
    4
  6. 提示 Expected Replicants[2]

    默认配置中 segment 需要一个副本,可以再启动一个 historical 结点来解决

  7. 网络问题、服务器宕机等问题导致数据丢失

    官方已经不建议使用 Tranquillity 和 Druid 进行交互了
    实际上如果使用 Tranquillity 不管是作为 Server 还是嵌入到 Spark/Flink 等都可能因为服务的短暂不可用丢失数据

    建议使用 Kafka Indexing Service 作为实时数据摄取机制

d.processing.buffer.sizeBytes or enable disk spilling by setting druid.query.groupBy.maxOnDiskStorage to a positive number.或者Not enough disk space to execute this query. Try raising druid.query.groupBy.m axOnDiskStorage.``` 都需要启用磁盘溢出(disk spilling)功能

```
druid.query.groupBy.maxOnDiskStorage=4000000000
```