Maestro 移动UI自动化测试入门:10分钟跑通第一条YAML用例
【免费下载链接】druid
Apache Druid: a high performance real-time analytics database.
本文基于 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,从而混入你的提交(该文件不应被提交到版本库)。
操作路径为:File → Project Structure... → Platform Settings → SDKs:
如果没有名为 1.8 的 SDK,可以:
- 将已有的某个 SDK 重命名为
1.8; - 或新建一个名为
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=2、METHOD_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 Code(Ctrl+Alt+L)即可产出与仓库风格一致的代码。更多无法用格式化器自动约束的约定(如日志与异常消息的 [占位符] 插值规范)可参考 dev/style-conventions.md。仓库同时也提供了 dev/eclipse_formatting.xml 与 dev/eclipse.importorder 供 Eclipse 用户使用。
配置 JaCoCo 覆盖率运行器
Druid 的 CI 使用 JaCoCo 强制代码覆盖率检查:新增代码的行覆盖与分支覆盖率低于设定阈值时,PR 将无法被合并。覆盖率检查基于 PR 与 master 的 diff 过滤,相关说明见 dev/code-review/code-coverage.md。因此,提交前应在本机运行测试确认达到阈值。
在 IDEA 中:
- 打开
Run→Edit Configurations...; - 修改 JUnit 测试运行模板(Defaults → JUnit);
- 在 Code Coverage 选项卡选择使用 JaCoCo 作为覆盖率运行器。
之所以必须切换为 JaCoCo,是因为 IDEA 默认的覆盖率运行器只统计行覆盖,而 JaCoCo 提供分支覆盖,与 Druid CI 的检查口径一致。
配置完成后,对正在修改的模块 src/test/java 目录右键 → Run with Coverage,即可生成覆盖率报告。报告会展示整个模块的覆盖率情况(而非仅你的改动),方便判断是否达到阈值。
另外,也可以在终端中直接对 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-commit与pre-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 配置并附加
- 在 IDEA 的
Run/Debug Configurations对话框中创建 Remote 类型配置; - 将 Host 设为 Druid 进程所在主机,Port 设为步骤 2 得到的端口;
- 启动(Debug)该 Remote 配置,即可在 IDEA 中对运行中的 Druid 进程设置断点调试;
- 如需同时调试多个服务/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=[\"druid-s3-extensions\",\"druid-histogram\",\"mysql-metadata-storage\"] -Ddruid.historical.cache.useCache=false -Ddruid.historical.cache.populateCache=false -Ddruid.segmentCache.locations="[{\"path\":\"/tmp/druid/indexCache\",\"maxSize\":10000000000}]" -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.locations | Historical 的段缓存目录与容量上限(此处为 /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=[\"druid-s3-extensions\",\"druid-histogram\",\"mysql-metadata-storage\"] -Ddruid.zk.service.host=localhost -Ddruid.metadata.storage.type=mysql -Ddruid.metadata.storage.connector.connectURI="jdbc:mysql://localhost:3306/druid" -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=PT10S | Coordinator 的调度周期为 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.host、druid.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 的检查口径保持一致。
相关文档与资源
- 本文原始文档:dev/intellij-setup.md
- 代码风格:dev/druid_intellij_formatting.xml、dev/style-conventions.md
- 覆盖率机制:dev/code-review/code-coverage.md
- Git 钩子:hooks/install-hooks.sh、hooks/pre-commit、hooks/pre-push
- 服务入口:services/src/main/java/org/apache/druid/cli/Main.java
- MySQL 元数据存储配置:docs/development/extensions-core/mysql.md
【免费下载链接】druid
Apache Druid: a high performance real-time analytics database.
更多推荐



所有评论(0)