Quick Start -- Spark / MR / Hive Telemetry Deployment Guide¶
Architecture Overview¶
graph TD
SP["Spark Plugin<br/>(--jars)"]
MA["MR Agent<br/>(-javaagent)"]
HH["Hive Hook<br/>(hive.exec.post.hooks)"]
MC["MR Collector<br/>(standalone)"]
OTEL["OTel Collector<br/>(Kafka Export)"]
HS["Hadoop History Server<br/>REST API :19888"]
KAFKA["Kafka"]
FLINK["Flink Consumer<br/>(Kafka -> DB)"]
MYSQL["MySQL"]
CH["ClickHouse"]
GRAFANA["Grafana (13 dashboards)"]
SP -->|"OTLP gRPC :4317"| OTEL
MA -->|"OTLP gRPC :4317"| OTEL
HH -->|"OTLP gRPC :4317"| OTEL
HS -->|"Polling Collection"| MC
MC -->|"OTLP gRPC :4317"| OTEL
OTEL --> KAFKA
KAFKA --> FLINK
FLINK --> MYSQL
FLINK --> CH
MYSQL --> GRAFANA
CH --> GRAFANA
1. Build¶
# Prerequisites: JDK 8, Maven 3.6+
git clone <repo-url> && cd spark-telemetry-listener
# Build Omnipackage (single JAR supporting Spark 2/3/4 + MR Agent/Collector + Hive Hook)
chmod +x build-omni.sh && ./build-omni.sh
# Build output location
ls spark/spark-telemetry-dist-omni/target/spark-telemetry-dist-omni-*.jar
# Build individual components (optional)
mvn clean package -pl hive/hive-telemetry-hook,hive/hive-telemetry-hook-dist -am -DskipTests # Hive Hook
mvn clean package -pl flink/metrics-flink-consumer,flink/metrics-flink-consumer-dist -am -DskipTests # Flink Consumer
2. Infrastructure Deployment¶
2.1 OTel Collector¶
# deploy/otel-collector/config.yaml
extensions:
health_check:
endpoint: 0.0.0.0:13133
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
kafka:
topic: telemetry-metrics
encoding: otlp_proto
brokers:
- kafka:9092
service:
extensions: [health_check]
pipelines:
metrics:
receivers: [otlp]
exporters: [kafka]
# Docker deployment
docker run -d --name otel-collector --network host \
-v $(pwd)/deploy/otel-collector/config.yaml:/etc/otelcol-contrib/config.yaml \
otel/opentelemetry-collector-contrib:0.96.0 \
--config=/etc/otelcol-contrib/config.yaml
Note: Must use
otel/opentelemetry-collector-contrib(not the core version), as the core version does not include the Kafka exporter.
2.2 Kafka¶
# KRaft mode (no ZooKeeper required)
docker run -d --name kafka --network host \
-e KAFKA_NODE_ID=1 \
-e KAFKA_PROCESS_ROLES=broker,controller \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 \
-e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://$(hostname):9092 \
apache/kafka:3.7.0
# Create topic
docker exec kafka /opt/kafka/bin/kafka-topics.sh --create \
--topic telemetry-metrics --bootstrap-server localhost:9092 \
--partitions 3 --replication-factor 1
2.3 MySQL / ClickHouse¶
# MySQL
docker run -d --name mysql --network host \
-e MYSQL_ROOT_PASSWORD=root123 \
-e MYSQL_DATABASE=metrics_db \
mysql:8.0
# ClickHouse (optional)
docker run -d --name clickhouse --network host \
clickhouse/clickhouse-server:23.8
2.4 Flink Consumer (Kafka -> DB)¶
A Flink DataStream API-based Kafka consumption job, using Flink KafkaSource + Checkpoint for offset management.
# Create configuration file flink-consumer.conf
# Refer to conf/flink/flink-consumer-mysql.conf or flink-consumer-clickhouse.conf
# Standalone run (no Flink cluster needed, uses Flink LocalEnvironment)
java -jar metrics-flink-consumer-dist-1.0.0-SNAPSHOT.jar /path/to/flink-consumer.conf
# Submit to Flink cluster (recommended for production)
/opt/flink-1.18.0/bin/flink run -c x.mg.metrics.flink.Main \
-m localhost:8081 \
/path/to/metrics-flink-consumer-dist-1.0.0-SNAPSHOT.jar /path/to/flink-consumer.conf
# Background submission (survives SSH disconnection)
nohup /opt/flink-1.18.0/bin/flink run -c x.mg.metrics.flink.Main \
-m localhost:8081 \
/path/to/metrics-flink-consumer-dist-1.0.0-SNAPSHOT.jar /path/to/flink-consumer.conf \
> /tmp/flink-submit.log 2>&1 &
# Check cluster job status
curl -s http://localhost:8081/jobs | python3 -c \
'import json,sys; [print(j["id"],j["status"]) for j in json.load(sys.stdin)["jobs"]]'
# Cancel a job
/opt/flink-1.18.0/bin/flink cancel <job-id>
The Flink Consumer automatically creates tables on startup (15 category tables + metric_events unified wide table), no manual schema initialization needed. The metric_events wide table consolidates data from all engines for cross-engine analysis. Kafka offsets are managed by Flink checkpoint, with checkpoint.path as the checkpoint storage directory.
2.5 Grafana¶
docker run -d --name grafana --network host \
-e GF_SECURITY_ADMIN_PASSWORD=admin123 \
grafana/grafana:latest
For data source configuration and dashboard import, see section 6 below.
3. Component Deployment¶
All sections below use the Omnipackage single JAR (
spark-telemetry-dist-omni-*.jar), which auto-detects the Spark version (2.x / 3.x / 4.x), no need to select different JARs.
3.1 Spark Plugin¶
Copy the JAR to the same path on all nodes:
scp spark-telemetry-dist-omni-*.jar node:/opt/spark-telemetry-plugin.jar
Spark 3.x / 4.x (SparkPlugin API)¶
spark-submit --master yarn \
--jars /opt/spark-telemetry-plugin.jar \
--conf spark.plugins=x.mg.metrics.sparktelemetry.adapter.SparkTelemetryPlugin \
--conf spark.telemetry.otel.exporter.endpoint=http://otel-collector:4317 \
--conf spark.telemetry.otel.service.name=my-spark-app \
your-app.jar
Spark 2.x (spark.extraListeners)¶
spark-submit --master yarn \
--jars /opt/spark-telemetry-plugin.jar \
--conf spark.extraListeners=x.mg.metrics.sparktelemetry.adapter.SparkTelemetryListener \
--conf spark.telemetry.otel.exporter.endpoint=http://otel-collector:4317 \
--conf spark.telemetry.otel.service.name=my-spark-app \
your-app.jar
Configuration Methods (pick one)¶
| Method | Example |
|---|---|
| Spark conf inline | --conf spark.telemetry.otel.exporter.endpoint=http://... |
| HOCON config file | --conf spark.telemetry.config.path=/etc/telemetry.conf |
| Hybrid (conf overrides file) | Use both simultaneously, Spark conf takes highest priority |
Preset Configurations¶
| Preset | Path | Description |
|---|---|---|
| basic | conf/spark{version}/basic/telemetry.conf |
Core task metrics only, minimal overhead |
| full | conf/spark{version}/full/telemetry.conf |
All metrics (task + stage + job + SQL) |
Preset configuration directories correspond to Spark versions:
| Directory | Applicable Version |
|---|---|
conf/spark24-hadoop27-hive2.3.9/ |
Spark 2.4 + Hadoop 2.7 |
conf/spark30-hadoop3-hive2.3.9/ |
Spark 3.0 + Hadoop 3 |
conf/spark32-hadoop3-hive2.3.9/ |
Spark 3.2 + Hadoop 3 |
conf/spark35-hadoop3-hive2.3.9/ |
Spark 3.5 + Hadoop 3 |
conf/spark40-hadoop3-hive2.3.9/ |
Spark 4.0 + Hadoop 3 |
Key Configuration Items¶
YARN Mode Requirement: When using
--master yarn, theHADOOP_CONF_DIRenvironment variable must point to the Hadoop configuration directory (containingcore-site.xml,yarn-site.xml,mapred-site.xml).mapred-site.xmlmust includemapreduce.framework.name=yarnandmapreduce.application.classpath, otherwise MR/Hive will fall back to local mode.
# Required
spark.telemetry.otel.exporter.endpoint=http://otel-collector:4317
# Recommended configuration
spark.telemetry.otel.service.name=my-spark-app # Service name, used for Grafana filtering
spark.telemetry.otel.export.interval.ms=10000 # Export interval (default 10s)
spark.telemetry.config.path=/etc/telemetry.conf # Config file path
# Metric switches (default values below)
spark.telemetry.metrics.task.execution=true # task CPU/GC/memory/duration
spark.telemetry.metrics.task.shuffle-extended=true # detailed shuffle metrics
spark.telemetry.metrics.task.info=true # task host/locality info
spark.telemetry.metrics.stage.detailed=true # stage-level metrics
spark.telemetry.metrics.job.lifecycle=true # job lifecycle events
spark.telemetry.metrics.sql.query-execution=true # SQL execution metrics (join/shuffle bytes/query text)
spark.telemetry.sql.max-length=4096 # SQL text max truncation length (characters)
Note: conf keys must include the full path including the
.otel.segment. Correct:spark.telemetry.otel.exporter.endpoint, Wrong:spark.telemetry.exporter.endpoint.
3.2 MR Agent (Task-level Real-time Metrics)¶
Injects into Mapper/Reducer JVMs via Java Agent, collecting task-level IO counters.
Prerequisite: Ensure
mapred-site.xmlhasmapreduce.framework.name=yarnconfigured, otherwise MR jobs will run in local mode and the Agent cannot be distributed via YARN.
# 1. Copy JAR to Hadoop node
scp spark-telemetry-dist-omni-*.jar node:/opt/hadoop/lib/mr-telemetry-agent.jar
# 2. Configure mapred-site.xml
<!-- mapred-site.xml -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-javaagent:/opt/hadoop/lib/mr-telemetry-agent.jar -Dmr.telemetry.agent.otel.exporter.endpoint=http://otel-collector:4317</value>
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-javaagent:/opt/hadoop/lib/mr-telemetry-agent.jar -Dmr.telemetry.agent.otel.exporter.endpoint=http://otel-collector:4317</value>
</property>
MR Agent-collected metrics are written to the mr_task_metrics table:
- map_input_records, map_output_records, map_output_bytes
- reduce_input_records, reduce_output_records, reduce_shuffle_bytes
- spilled_records
3.3 MR Collector (Job-level Historical Metrics)¶
A standalone process that polls the Hadoop History Server REST API to collect completed MR job metrics.
# 1. Create configuration file mr-collector.conf
# Refer to conf/examples/mr-collector.conf.example or conf/spark35-hadoop3-hive2.3.9/mr-collector.conf
# mr-collector.conf
mr-telemetry {
history-server {
url = "http://hadoop-historyserver:19888"
poll.interval.secs = 30
}
otel {
exporter.endpoint = "http://otel-collector:4317"
service.name = "mr-telemetry-collector"
export.interval.ms = 10000
}
state {
file = "/tmp/mr-telemetry-state.json" # Resume from checkpoint, no duplicate collection after restart
}
collection {
job.counters = true # job-level: HDFS IO, CPU, GC, maps/reduces count
task.counters = false # task-level (large data volume, enable on demand)
job.details = true # job name, user, status
}
}
# 2. Run (using Omnipackage)
java -jar spark-telemetry-dist-omni-*.jar --mr-collector /path/to/mr-collector.conf
# 3. For production, use systemd or nohup for background execution
nohup java -jar spark-telemetry-dist-omni-*.jar --mr-collector /etc/mr-collector.conf &
MR Collector-collected metrics are written to the mr_job_metrics table:
- elapsed_time_ms, state, launched_maps, launched_reduces
- hdfs_bytes_read, hdfs_bytes_written, file_bytes_read, file_bytes_written
- cpu_time_ms, gc_time_ms
3.4 Hive Telemetry Hook¶
Captures HiveServer2 query metrics (engine-independent, supports MR and Spark engines).
# 1. Place the Omnipackage JAR in HiveServer2 auxlib (auto-loaded, no need for hive.aux.jars.path)
cp spark-telemetry-dist-omni-*.jar $HIVE_HOME/auxlib/
<!-- hive-site.xml -->
<property>
<name>hive.exec.post.hooks</name>
<value>x.mg.metrics.hivetelemetry.HiveTelemetryHook</value>
</property>
<property>
<name>hive.telemetry.otel.exporter.endpoint</name>
<value>http://otel-collector:4317</value>
</property>
<property>
<name>hive.telemetry.sql.max-length</name>
<value>4096</value>
</property>
Hive Hook-collected metrics are written to the hive_query_metrics and hive_table_io_metrics tables:
- query_id, operation, user_name, success, duration_ms
- input_bytes, output_bytes, input_rows, output_rows
- input_tables, output_tables, execution_engine (mr/spark)
4. Data Flow Verification¶
Check if OTel Collector Received Data¶
docker logs otel-collector --tail=50 | grep -E "spark\.|mr\.|hive\."
Check Messages in Kafka¶
docker exec kafka /opt/kafka/bin/kafka-dump-log.sh \
--files /tmp/kafka-logs/telemetry-metrics-0/00000000000000000000.log
Check MySQL Data¶
-- Spark metrics
SELECT COUNT(*) FROM task_metrics;
SELECT COUNT(*) FROM sql_query_metrics;
-- MR metrics
SELECT COUNT(*) FROM mr_job_metrics; -- MR Collector
SELECT COUNT(*) FROM mr_task_metrics; -- MR Agent
-- Hive metrics
SELECT COUNT(*) FROM hive_query_metrics;
SELECT COUNT(*) FROM hive_table_io_metrics;
-- Unified wide table
SELECT engine, event_type, COUNT(*) FROM metric_events GROUP BY engine, event_type;
Using the Diagnostic Tool¶
Build and run the diagnostic tool to automatically verify all backend components and application configuration:
# Build diagnostic tool
mvn clean package -pl diagnostic/diagnostic-core -am -DskipTests
# Run (interactive CLI, JLine terminal)
java -jar diagnostic/diagnostic-core/target/diagnostic-core-1.0.0-SNAPSHOT.jar
# Specify configuration file
java -jar diagnostic/diagnostic-core/target/diagnostic-core-1.0.0-SNAPSHOT.jar \
--config /path/to/diagnostic.conf
The diagnostic tool automatically performs the following checks:
| Check Item | Description |
|---|---|
| Spark Plugin | JAR existence, spark.plugins configuration |
| Hive Hook | hive.exec.post.hooks configuration |
| MR Collector | Configuration file, History Server connectivity |
| OTel Collector | gRPC port connectivity, Health Check |
| Kafka | Broker connectivity, Topic existence |
| MySQL | Database connectivity, table schema validation |
| Grafana Dashboards | Dashboard SQL query validity check |
| Data Flow | End-to-end data integrity verification |
Configuration file reference: diagnostic/diagnostic-core/src/main/resources/diagnostic.conf
5. Grafana Dashboard Configuration¶
5.1 Add MySQL Data Source¶
URL: mysql:3306
Database: metrics_db
User: metrics / Password: metrics
Set data source UID to DS_MYSQL (dashboard SQL queries reference this UID).
5.2 Import Dashboards¶
Import the JSON files from the deploy/grafana/ directory into Grafana:
| File | Dashboard Name | Description |
|---|---|---|
overview.json |
Platform Telemetry Overview | Full platform overview |
spark.json |
Spark Telemetry | Task/Stage/SQL metrics |
mr.json |
MapReduce Telemetry | Job Level + Task Level |
hive-mr.json |
Hive on MR Telemetry | Hive MR engine queries |
hive-spark.json |
Hive on Spark Telemetry | Hive Spark engine queries |
spark-mr-telemetry-dashboard.json |
Spark/MR/Hive Combined Panel | Consolidated view |
hive-analysis.json |
Hive Query & Data Lineage Analysis | Operation distribution, table IO, execution engine comparison |
performance-analysis.json |
Performance Anomaly & Bottleneck Analysis | Stage duration, GC overhead, data skew detection |
efficiency.json |
Comprehensive Efficiency Score | Resource efficiency score, queue efficiency comparison |
reliability.json |
Reliability & Failure Analysis | Task success rate trends, failure events |
capacity.json |
Capacity Planning & Resource Utilization | Task concurrency, memory trends, GC frequency |
cost-attribution.json |
Cost Attribution & Resource Ranking | User/queue/application resource ranking |
io-analysis.json |
Data Throughput & IO Analysis | Cross-engine IO throughput, Shuffle analysis |
5.3 MR Dashboard Description¶
The MR dashboard is divided into two tiers (with different data sources):
| Tier | Data Source | Collection Method | Dashboard Content |
|---|---|---|---|
| Job Level | mr_job_metrics |
MR Collector (History Server) | Job count, duration, success rate, HDFS IO, CPU/GC |
| Task Level | mr_task_metrics |
MR Agent (javaagent) | Map/Reduce task count, output bytes, shuffle bytes, records |
The two tiers run independently and can be deployed separately or together.
6. Frequently Asked Questions¶
| Problem | Cause | Solution |
|---|---|---|
ClassNotFoundException: scala.$less$colon$less |
Old JAR in $SPARK_HOME/jars/, or scala-collection-compat falsely detecting Scala 2.13 |
Delete old JARs from $SPARK_HOME/jars/, use the latest Omnipackage |
No GrpcSenderProvider found |
Shade missing OkHttp3/Kotlin dependencies | Ensure building with build-omni.sh, do not shade independently |
| Short jobs have no metrics | Job completes before OTel first export | Reduce spark.telemetry.otel.export.interval.ms (e.g., 5000) |
module-info.class conflict |
JDK 9+ module system conflict | zip -d <jar> META-INF/versions/9/module-info.class |
| SQL shuffle_bytes NULL | AQE inputPlan returns initial plan |
Already fixed in latest version, uses reflection to access currentPhysicalPlan |
Hive dashboard Unknown column 'mr' |
Old Grafana dashboard version | Re-import deploy/grafana/hive-mr.json |
7. Version Compatibility¶
| Component | Minimum Version | Verified Versions |
|---|---|---|
| Spark | 2.4.x | 2.4.4, 3.0.x, 3.2.0, 3.5.8 |
| Hadoop | 2.7.x | 2.7.0, 3.2.0, 3.4.3 |
| Hive | 2.3.x | 2.3.9, 3.1.3 |
| Java | 8 | OpenJDK 8u482 |
| Kafka | 3.x | 3.7.0, 3.9.2 |
| Flink | 1.18 | 1.18.0 |
| OTel Collector | 0.96+ | 0.96.0 |
| MySQL | 8.0 | 8.0 |
| ClickHouse | 23.x | 23.8 |
| Grafana | 10.x | latest |