Architecture Design¶
Overall Architecture¶
graph LR
subgraph Data Sources
SP[Spark Plugin]
MR[MR Collector]
HV[Hive Hook]
end
subgraph Collection Layer
OTel[OTel Collector]
end
subgraph Transport Layer
KF[Kafka]
end
subgraph Consumption Layer
FK[Flink Consumer]
end
subgraph Storage Layer
MY[MySQL/ClickHouse]
GF[Grafana]
end
SP -->|gRPC OTLP| OTel
MR -->|gRPC OTLP| OTel
HV -->|gRPC OTLP| OTel
OTel -->|Kafka Producer| KF
KF -->|Kafka Consumer| FK
FK -->|JDBC Batch| MY
MY -->|SQL| GF
Module Structure¶
spark/
├── spark-telemetry-common/ # Java-only core: config, models, OTel SDK setup, lifecycle
├── spark-telemetry-adapter-spark2/ # Scala 2.11 adapter for Spark 2.4
├── spark-telemetry-adapter-spark30/ # Scala 2.12 adapter for Spark 3.0
├── spark-telemetry-adapter-spark32/ # Scala 2.12 adapter for Spark 3.2
├── spark-telemetry-adapter-spark3/ # Scala 2.12 adapter for Spark 3.5
├── spark-telemetry-adapter-spark4/ # Scala 2.13 adapter for Spark 4.0
├── spark-telemetry-dist-spark{2,3,4}/ # Shaded fat JARs for each Spark version
├── spark-telemetry-omni-facade/ # Pure Java facade for omnipackage
├── spark-telemetry-adapters-relocated/ # Relocates adapters to v2/v3/v4 packages
└── spark-telemetry-dist-omni/ # Unified distribution: Spark 2/3/4 + MR in one JAR
mapreduce-collector/
├── mr-telemetry-collector/ # Standalone MR job metric collector
└── mr-telemetry-dist/
mapreduce-agent/
├── mr-telemetry-agent/ # MR task-level agent via ByteBuddy
└── mr-telemetry-agent-dist/
hive/
├── hive-telemetry-hook/ # Hive query telemetry hook
└── hive-telemetry-hook-dist/
flink/
├── metrics-flink-consumer/ # Kafka -> MySQL/ClickHouse
└── metrics-flink-consumer-dist/
diagnostic/
└── diagnostic-core/ # Diagnostic tool
Data Flow¶
Spark Plugin¶
- SparkTelemetryPlugin loaded via
spark.pluginsconfig - TelemetryDriverPlugin initializes
TelemetryLifecyclesingleton and registersSparkTelemetryListener - TelemetryExecutorPlugin initializes
TelemetryLifecycle+SparkTelemetryMetricsSinkfor JVM metrics - SparkTelemetryListener captures
onTaskEnd/onStageCompletedevents - TelemetryLifecycle.accept() routes events to MetricRecorder
- MetricRecorder records OTel counters/histograms
- OtelRegistry manages: PeriodicMetricReader -> OTLP gRPC exporter (DELTA temporality) -> OTel Collector
Omnipackage Architecture¶
The omnipackage supports Spark 2/3/4 in a single JAR, auto-detecting the version at runtime:
- Each adapter is relocated via shade to
x.mg.metrics.sparktelemetry.adapter.internal.v{2,3,4} - Pure Java facade delegates to the version-specific adapter via reflection
- Version detection uses
Class.forNameto probe for Spark/Scala classes
Key Design Decisions¶
| Decision | Reason |
|---|---|
| DELTA Temporality | Prevent duplicate data on re-export |
| Async Flush | Avoid DAGScheduler thread blocking |
| appId Fallback | Handle local mode and short-lived applications |
| MR Gauge -> Counter | Avoid buildWithCallback memory leak |
| SQL Text LRU Cache | Prevent memory leak, max 1000 entries |