Überwachung von Kotlin-Anwendungen: Metriken und Alarme auf fortgeschrittenem Niveau
In der modernen Softwareentwicklung ist die Überwachung keine Option mehr – sie ist ein obligatorischer Bestandteil der Produktionsinfrastruktur. Für Kotlin-Anwendungen, die unter hoher Last laufen, reicht einfaches Logging nicht aus. Erforderlich ist eine vollständige Observability: Metrikenerfassung, Alarmkonfiguration und Datenvisualisierung in Echtzeit. In diesem Artikel werden wir fortgeschrittene Techniken zur Überwachung von Kotlin-Anwendungen mit dem Stack Prometheus, Grafana und Micrometer behandeln.
1. Werkzeuge: Micrometer und Prometheus
Der beste Weg, die Überwachung in eine Kotlin-Anwendung zu integrieren, ist die Verwendung der Bibliothek Micrometer. Sie bietet eine Fassade für verschiedene Überwachungssysteme, einschließlich Prometheus. Micrometer unterstützt sowohl JVM-Metriken als auch benutzerdefinierte Geschäftskennzahlen.
Fügen wir die Abhängigkeiten in build.gradle.kts hinzu:
dependencies { implementation("io.micrometer:micrometer-core:1.12.0") implementation("io.micrometer:micrometer-registry-prometheus:1.12.0") implementation("io.ktor:ktor-server-metrics-micrometer:2.3.7")}Für eine Ktor-Anwendung sieht die Konfiguration wie folgt aus:
import io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.application.*import io.ktor.server.metrics.micrometer.*import io.micrometer.prometheus.PrometheusMeterRegistryimport io.micrometer.prometheus.PrometheusConfig
fun main() { val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
embeddedServer(Netty, port = 8080) { install(MicrometerMetrics) { registry = meterRegistry // Standard-JVM-Metriken hinzufügen meterRegistry.config().commonTags("application", "my-kotlin-app") } routing { get("/metrics") { call.respond(meterRegistry.scrape()) } } }.start(wait = true)}Dieser Code sammelt automatisch Metriken zu HTTP-Anfragen, Thread-Pool und JVM. Der Endpunkt /metrics gibt die Daten im Prometheus-Format aus.
2. Benutzerdefinierte Metriken: Geschäftskennzahlen
Standardmetriken reichen oft nicht aus. Für eine fortgeschrittene Überwachung müssen Geschäftskennzahlen erfasst werden: Anzahl der Bestellungen, Bearbeitungszeit von Zahlungen, Häufigkeit von Validierungsfehlern.
Beispiel für die Erstellung eines benutzerdefinierten Zählers und Timers:
import io.micrometer.core.instrument.Counterimport io.micrometer.core.instrument.MeterRegistryimport io.micrometer.core.instrument.Timerimport java.util.concurrent.TimeUnit
class OrderMetrics(private val registry: MeterRegistry) { private val orderCounter: Counter = Counter.builder("orders.created") .description("Total number of created orders") .register(registry)
private val processTimer: Timer = Timer.builder("orders.processing.time") .description("Time to process an order") .publishPercentiles(0.5, 0.95, 0.99) .register(registry)
fun recordOrderCreation() { orderCounter.increment() }
fun measureProcessingTime(block: () -> Unit) { processTimer.record(block) }}Verwendung im Service:
class OrderService(private val metrics: OrderMetrics) { fun createOrder(order: Order): Order { metrics.recordOrderCreation() return metrics.measureProcessingTime { // Geschäftslogik Thread.sleep(100) // Simulation order } }}Beachten Sie die Perzentile: Sie ermöglichen es, nicht nur die Durchschnittszeit, sondern auch die "Ausreißer" (p99) zu verfolgen, was für SLAs entscheidend ist.
3. Konfiguration von Alarmen in Prometheus
Die Erfassung von Metriken ist ohne ein Benachrichtigungssystem nutzlos. Alarme werden in der Prometheus-Konfiguration (Datei alert.rules.yml) konfiguriert.
Beispiel für Regeln für Kotl