• 数据库
  • OLAP
  • 大数据
  • 后端

【免费下载链接】druid

Apache Druid: a high performance real-time analytics database.

项目地址: https://gitcode.com/gh_mirrors/druid6/druid
点击查看 免费下载

本文基于 Apache Druid 仓库中 dev/intellij-setup.md 整理扩充,面向需要在本地使用 IntelliJ IDEA 运行、调试和测试 Druid 的开发者。文章覆盖 Project SDK 命名约定、代码风格导入、JaCoCo 覆盖率本地验证、可选的 Git Checkstyle 钩子、元数据存储与 ZooKeeper 前置依赖、初始构建命令,以及通过 Remote Debug 与 XML App Def 两种方式在 IDEA 中调试 Druid 服务与 Peon 的完整方案。读完本文,你将能搭建出一套与 Druid CI 行为对齐的本地开发环境,并具备对 Historical、Coordinator 等服务进行断点调试的实战能力。

前置依赖:MySQL 元数据存储与 ZooKeeper

在开始构建和调试之前,需要先准备好 Druid 运行所依赖的外部组件。Druid 使用元数据存储保存段、任务等状态信息,并使用 ZooKeeper 进行服务发现与协调。

元数据存储(Metadata Store)

本文档默认采用 MySQL 作为元数据存储,其搭建说明详见 docs/development/extensions-core/mysql.md。按照该文档操作后,环境中应存在:

  • 一个名为 druid 的数据库;
  • 一个名为 druid 且具有相应权限的用户,密码为 diurd

这些凭据会直接出现在下文 Coordinator.xml 运行配置-Ddruid.metadata.storage.* 参数中。除 MySQL 外,使用 PostgreSQL 或 Derby 等数据库也完全可行,但需要自行完成对应扩展(如 postgresql-metadata-storage)的配置,本文不再展开。

ZooKeeper

ZooKeeper 需要在本机运行,通常只需下载 ZooKeeper 发行版、在 conf/ 目录做少量配置(大多数默认值即可),然后在 ZooKeeper 目录下执行:

./bin/zkServer.sh start

在 macOS 上可以通过 Homebrew 简化安装与启动:

brew install zookeeper
brew services start zookeeper

从源码看,Druid 的 Coordinator/Overlord 等服务启动时会依赖 ZooKeeper 进行领导选举与目录协调,相关实现集中在 server/src/main/java/org/apache/druid/curator 中,因此本地调试前确保 ZooKeeper 可用是必要前提。

Project SDK 命名约定:必须叫 1.8

在 IDEA 中导入 Druid 项目后,项目配置的 SDK 必须命名为 1.8。这并非要求物理 JDK 必须是 1.8,而是一个约定:避免 .idea/misc.xml 文件因 SDK 名称不同而产生无谓的 diff,从而混入你的提交(该文件不应被提交到版本库)。

操作路径为:FileProject Structure...Platform SettingsSDKs

IntelliJ SDK 配置界面

如果没有名为 1.8 的 SDK,可以:

  1. 将已有的某个 SDK 重命名为 1.8
  2. 或新建一个名为 1.8 的 SDK,其文件路径可以指向与已有 SDK 相同的目录——即使底层实际是 JDK 9+ 也可以,因为 1.8 在这里只是别名。

Historical.xml 运行配置 中可以看到 ALTERNATIVE_JRE_PATH 的值正是 1.8,与该约定保持一致。

导入代码风格:druid_intellij_formatting.xml

Druid 的代码风格以 XML 形式提供在 dev/druid_intellij_formatting.xml,可以在 IDEA 的 Settings → Editor → Code Style 中导入。

该风格文件(Druid Java and Scala style)定义了项目统一的排版约定,例如:

  • Java 缩进为 2 空格(INDENT_SIZE=2),续行缩进 4 空格;
  • 类与方法的花括号采用 NextLine 风格(CLASS_BRACE_STYLE=2METHOD_BRACE_STYLE=2);
  • 方法调用链、二元运算、三元运算、throws 列表等多行对齐(ALIGN_MULTILINE_* 系列选项);
  • 二元运算符换行时符号置于下一行(BINARY_OPERATION_SIGN_ON_NEXT_LINE=true);
  • if/while/for/do-while 强制使用花括号(*_BRACE_FORCE=3);
  • 同时包含 Groovy、Scala、XML、Markdown 语言子集的独立设置。

导入后,Reformat CodeCtrl+Alt+L)即可产出与仓库风格一致的代码。更多无法用格式化器自动约束的约定(如日志与异常消息的 [占位符] 插值规范)可参考 dev/style-conventions.md。仓库同时也提供了 dev/eclipse_formatting.xmldev/eclipse.importorder 供 Eclipse 用户使用。

配置 JaCoCo 覆盖率运行器

Druid 的 CI 使用 JaCoCo 强制代码覆盖率检查:新增代码的行覆盖与分支覆盖率低于设定阈值时,PR 将无法被合并。覆盖率检查基于 PR 与 master 的 diff 过滤,相关说明见 dev/code-review/code-coverage.md。因此,提交前应在本机运行测试确认达到阈值。

在 IDEA 中:

  1. 打开 RunEdit Configurations...
  2. 修改 JUnit 测试运行模板(Defaults → JUnit);
  3. 在 Code Coverage 选项卡选择使用 JaCoCo 作为覆盖率运行器。

之所以必须切换为 JaCoCo,是因为 IDEA 默认的覆盖率运行器只统计行覆盖,而 JaCoCo 提供分支覆盖,与 Druid CI 的检查口径一致。

配置完成后,对正在修改的模块 src/test/java 目录右键 → Run with Coverage,即可生成覆盖率报告。报告会展示整个模块的覆盖率情况(而非仅你的改动),方便判断是否达到阈值。

代码覆盖率运行配置 1 代码覆盖率运行配置 2

另外,也可以在终端中直接对 PR diff 计算覆盖率:先用 npm install @connectis/diff-test-coverage 安装工具,再运行模块单测并生成报告,最后对 diff 做覆盖率检查:

mvn -pl <MODULE_TO_CHECK> test jacoco:report
git diff master...HEAD | diff-test-coverage --coverage "**/target/site/jacoco/jacoco.xml" --type jacoco --log-template "full" --

安装 Git Checkstyle 预提交钩子(可选)

Druid 仓库在 hooks 目录提供了 Git 钩子脚本,可安装后自动在提交前运行 checkstyle 校验,避免等到 CI 阶段才发现风格问题,节省反复提交的迭代成本。

安装方式是在仓库根目录执行:

./hooks/install-hooks.sh <DRUID_ROOT>

其中 <DRUID_ROOT> 为仓库根目录。该脚本会把以下内容复制到 .git/hooks/ 下(目标已存在时会报错退出):

  • run-all-in-dir.py:遍历指定钩子目录、逐个执行非 _ 开头脚本的 Python 工具;
  • pre-commitpre-push 两个入口钩子;
  • pre-commits/pre-pushes/ 两个钩子目录。

入口逻辑参见 hooks/pre-commit(执行 pre-commits 目录下所有钩子)与 hooks/pre-push(执行 pre-pushes 目录下所有钩子并透传 push 参数)。pre-pushes/checkstyle-check 即负责 checkstyle 校验。checkstyle 规则本身定义在 codestyle/checkstyle.xml(含 codestyle/checkstyle-suppressions.xml 抑制规则),并在根 pom.xml 中通过 maven-checkstyle-plugin 接入构建生命周期。

初始构建:mvn clean install -Pdist

在运行或调试任何 Druid 应用之前,需要先完成一次初始构建,以正确填充目录结构:

mvn clean install -Pdist -DskipTests

其中:

  • -Pdist必须的:该 profile 会把所有核心扩展复制到 distribution/target/extensions 目录,下文 runConfigurations 中的 -Ddruid.extensions.directory 即从该目录加载扩展(distribution 模块的 assembly 定义见 distribution/src/assembly);
  • 若你只关注后端服务而非前端工程,可追加 -Dweb.console.skip=true,可显著缩短构建时间。

使用 IntelliJ IDEA 调试运行中的 Druid 集群

IDEA 调试器可以附加(attach)到本地或远程的 Java 进程(即 Druid 进程)。整体流程分三步:在 Druid 进程中开启调试端口 → 找到端口 → 在 IDEA 中创建 Remote 配置并附加。

步骤 1:在 Druid 进程中开启 JPDA 调试

Druid 服务(如 Overlord、Coordinator、Historical 等):在 JVM 启动参数中加入:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=<PORT>

其中 <PORT> 为任一可用端口,且每个 Druid 服务应选用不同的端口值。Druid 各服务的主入口统一为 services/src/main/java/org/apache/druid/cli/Main.java(对应 org.apache.druid.cli.Main),通过 server <service> 子命令启动对应服务。

Peon(MiddleManager 上的工作进程):在 MiddleManager 的运行属性 druid.indexer.runner.javaOpts 中加入:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0

这里 address=0 表示由调试器分配临时端口(ephemeral port)。Peon 进程是由 MiddleManager 根据任务动态拉起的工作进程,其 JVM 参数由 druid.indexer.runner.javaOpts 控制,相关实现可参见 indexing-service 下的任务运行器代码。

步骤 2:找到进程对应的调试端口

  • 对 Druid 服务:端口即为步骤 1 中 JVM 参数里选定的值,也可在每个 Druid 服务日志的第一行中查看;
  • 对 Peon:可在任务日志的第一行查看系统分配的临时端口。

步骤 3:创建 Remote 配置并附加

  1. 在 IDEA 的 Run/Debug Configurations 对话框中创建 Remote 类型配置;
  2. 将 Host 设为 Druid 进程所在主机,Port 设为步骤 2 得到的端口;
  3. 启动(Debug)该 Remote 配置,即可在 IDEA 中对运行中的 Druid 进程设置断点调试;
  4. 如需同时调试多个服务/Peon,重复步骤 3 的 1~3 即可,每个进程对应一个 Remote 配置。

该方案特别适合调试「在集群真实环境下复现、但难以在单测中构造」的问题,例如 Coordinator 的调度逻辑、MiddleManager 与 Peon 之间的任务分发等。

XML App Def:在 IDEA 内直接运行 Druid 服务

除附加调试外,还可以把应用定义(App Def)配置成 XML,导入 IDEA 后直接以 Application 方式运行某个 Druid 服务,断点调试同样生效。这些 XML 文件应放在 Druid 源码根目录的 .idea/runConfigurations 下。

下文两个示例的要点:主类均为 org.apache.druid.cli.Main,模块为 druid-services,通过 PROGRAM_PARAMETERS 传入 server <service> 子命令,通过 VM_PARAMETERS 注入系统属性完成本地运行所需配置(时间区、扩展目录、ZooKeeper、元数据存储、缓存与段缓存路径等)。

Historical.xml

<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Historical" type="Application" factoryName="Application">
    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
    <option name="MAIN_CLASS_NAME" value="org.apache.druid.cli.Main" />
    <option name="VM_PARAMETERS" value="-server -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Xmx2G -XX:MaxJavaStackTraceDepth=9999 -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy -XX:+PrintReferenceGC -verbose:gc -XX:+PrintFlagsFinal -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -Dorg.jboss.logging.provider=slf4j -Dlog4j.configurationFile=$PROJECT_DIR$/core/src/main/resources/log4j2.debug.xml -Ddruid.host=localhost -Ddruid.service=historical -Ddruid.processing.buffer.sizeBytes=100000000 -Ddruid.extensions.hadoopDependenciesDir=$PROJECT_DIR$/distribution/target/hadoop-dependencies/ -Ddruid.extensions.directory=$PROJECT_DIR$/distribution/target/extensions/ -Ddruid.extensions.loadList=[\&quot;druid-s3-extensions\&quot;,\&quot;druid-histogram\&quot;,\&quot;mysql-metadata-storage\&quot;] -Ddruid.historical.cache.useCache=false -Ddruid.historical.cache.populateCache=false -Ddruid.segmentCache.locations=&quot;[{\&quot;path\&quot;:\&quot;/tmp/druid/indexCache\&quot;,\&quot;maxSize\&quot;:10000000000}]&quot; -Ddruid.zk.service.host=localhost -Ddruid.processing.numThreads=1 -Ddruid.server.http.numThreads=50 -Ddruid.serverview.type=http -Ddruid.emitter=logging" />
    <option name="PROGRAM_PARAMETERS" value="server historical" />
    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
    <option name="ALTERNATIVE_JRE_PATH" value="1.8" />
    <option name="ENABLE_SWING_INSPECTOR" value="false" />
    <option name="ENV_VARIABLES" />
    <option name="PASS_PARENT_ENVS" value="true" />
    <module name="druid-services" />
    <envs />
    <method />
  </configuration>
</component>

关键参数解读:

参数含义
-Dlog4j.configurationFile=$PROJECT_DIR$/core/src/main/resources/log4j2.debug.xml使用调试日志配置。仓库中该文件位于 processing/src/main/resources/log4j2.debug.xml,将 org.apache.druid 包日志级别设为 debug,便于跟踪内部逻辑
-Ddruid.extensions.directory / -Ddruid.extensions.hadoopDependenciesDir扩展与 Hadoop 依赖加载目录,指向 distribution/target 下由 -Pdist 构建生成的目录
-Ddruid.extensions.loadList本次运行要加载的扩展白名单(S3、Histogram、MySQL 元数据存储)
-Ddruid.segmentCache.locationsHistorical 的段缓存目录与容量上限(此处为 /tmp/druid/indexCache,10GB)
-Ddruid.historical.cache.useCache / populateCache关闭 Historical 查询缓存,便于调试时观察真实查询执行
-Ddruid.processing.numThreads=1处理线程数设为 1,降低本地资源占用、便于单线程跟踪
-Ddruid.serverview.type=http服务视图使用 HTTP 轮询方式(本地调试无需 ZK 之外的额外机制)

注:文档中的 $PROJECT_DIR$/core/src/main/resources/log4j2.debug.xml 为历史路径,当前仓库该文件实际位于 processing 模块,使用时可相应调整。

Coordinator.xml

<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Coordinator" type="Application" factoryName="Application">
    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
    <option name="MAIN_CLASS_NAME" value="org.apache.druid.cli.Main" />
    <option name="VM_PARAMETERS" value="-server -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Xmx256M -Xmx256M -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy -XX:+PrintReferenceGC -verbose:gc -XX:+PrintFlagsFinal -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -Dorg.jboss.logging.provider=slf4j -Ddruid.host=localhost -Ddruid.service=coordinator -Ddruid.extensions.directory=$PROJECT_DIR$/distribution/target/extensions/ -Ddruid.extensions.loadList=[\&quot;druid-s3-extensions\&quot;,\&quot;druid-histogram\&quot;,\&quot;mysql-metadata-storage\&quot;] -Ddruid.zk.service.host=localhost -Ddruid.metadata.storage.type=mysql -Ddruid.metadata.storage.connector.connectURI=&quot;jdbc:mysql://localhost:3306/druid&quot; -Ddruid.metadata.storage.connector.user=druid -Ddruid.metadata.storage.connector.password=diurd -Ddruid.serverview.type=http -Ddruid.emitter=logging -Ddruid.coordinator.period=PT10S -Ddruid.coordinator.startDelay=PT5S" />
    <option name="PROGRAM_PARAMETERS" value="server coordinator" />
    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
    <option name="ALTERNATIVE_JRE_PATH" value="1.8" />
    <option name="ENABLE_SWING_INSPECTOR" value="false" />
    <option name="ENV_VARIABLES" />
    <option name="PASS_PARENT_ENVS" value="true" />
    <module name="druid-services" />
    <envs />
    <method />
  </configuration>
</component>

与 Historical 相比,Coordinator 新增/差异的关键参数:

参数含义
-Ddruid.metadata.storage.type=mysql元数据存储类型为 MySQL,对应 mysql-metadata-storage 扩展
-Ddruid.metadata.storage.connector.connectURI=jdbc:mysql://localhost:3306/druid连接地址与库名,与前置 MySQL 准备一致
-Ddruid.metadata.storage.connector.user=druid / password=diurd连接凭据
-Ddruid.coordinator.period=PT10SCoordinator 的调度周期为 10 秒
-Ddruid.coordinator.startDelay=PT5S启动延迟 5 秒后开始协调工作,便于本地快速进入可调试状态

使用 properties 文件集中管理运行参数

除把全部系统属性写进 VM_PARAMETERS 外,也可以在 .idea/conf 目录放置属性文件来集中管理。例如创建 common.properties,然后在 App Def 的 VM_PARAMETERS 中加入:

-Ddruid.properties.file=$PROJECT_DIR$/.idea/conf/common.properties

这样即可把多个服务共享的通用配置(如 druid.zk.service.hostdruid.extensions.*)抽到同一文件中维护,各服务的 App Def 只保留自身特有的参数。属性文件中的键值对与 -Ddruid.* 系统属性一一对应,Druid 会通过 druid.properties.file 指定的文件加载运行时配置。

常见问题排查要点

  • 扩展加载失败:确认已执行 mvn clean install -Pdist -DskipTests,且 -Ddruid.extensions.directory 指向存在 druid-* 扩展的 distribution/target/extensions
  • 元数据存储连接失败:核对 MySQL 中 druid 库、druid 用户与密码 diurd 是否就绪,以及 connectURI 端口是否正确;
  • ZooKeeper 连接失败:确认本机 zkServer.sh start(或 brew services start zookeeper)已成功,druid.zk.service.host=localhost 与 ZK 监听地址一致;
  • .idea/misc.xml 反复变化:确认 Project SDK 名称严格为 1.8,且不要将该文件纳入提交;
  • 覆盖率不达标:确认 JUnit 模板已切换为 JaCoCo 运行器以得到分支覆盖数据,并与 CI 的检查口径保持一致。

相关文档与资源

  • 数据库
  • OLAP
  • 大数据
  • 后端

【免费下载链接】druid

Apache Druid: a high performance real-time analytics database.

项目地址: https://gitcode.com/gh_mirrors/druid6/druid
点击查看 免费下载
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐