Zum Inhalt springen
Deutsch

Observability — Überblick

Ein produktives Actor-System braucht drei Dinge, damit es von außen beobachtbar ist:

SäuleWas sie beantwortetModul
Metriken„Wie hoch ist die Rate / Anzahl / Latenz gerade?”MetricsExtension
Tracing„Was hat dieser einzelne Request gemacht?”TracingExtension
Management„Läuft das System und ist es gesund?”HttpManagement

Alle drei sind Extensions — sie laufen nicht, bis du danach greifst. Eine App, die Observability ignoriert, hat keinen Overhead durch ungenutzte Metrik-Puffer oder nicht gestartete Trace-Exporter.

import { ActorSystem, MetricsExtensionId } from 'actor-ts';
const system = ActorSystem.create('my-app');
const metrics = system.extension(MetricsExtensionId);
const requests = metrics.counter('http.requests.total', { route: '/orders' });
requests.inc();
const latency = metrics.histogram('http.requests.duration_ms', { route: '/orders' });
latency.observe(42);
const active = metrics.gauge('sessions.active');
active.set(123);

Vier Metrik-Typen:

  • Counter — monoton steigend. Gesamtanzahl der Requests, Gesamtfehler.
  • Gauge — Wert zu einem Zeitpunkt. Aktive Sessions, aktuelle Speichernutzung.
  • Histogram — gesampelte Verteilung. Request-Latenz, Payload- Größe. Erlaubt es, p50/p95/p99 zur Scrape-Zeit zu berechnen.
  • Timertimer.start() gibt eine Stop-Funktion zurück; baut auf Histogram auf für timing-spezifische Ergonomie.

Jede Metrik hat einen Namen + Labels (Key-Value-Paare). Labels erlauben es dir, dieselbe Metrik nach Dimensionen zu zerlegen — http.requests.total nach route oder status.

Die Metriken selbst sind framework-intern; sie zu einem Metrik-Backend zu bringen, geschieht über einen Exporter:

ExporterBackend
PrometheusExporterStellt einen /metrics-Endpoint bereit, den Prometheus scrapt.
PromClientAdapterSchiebt in die prom-client-Bibliothek, falls du sie schon nutzt.
OtelMetricsAdapterMeldet via OpenTelemetry.

Siehe Prometheus-Exporter für den Deep-Dive zu jedem.

Das Framework zeichnet automatisch eine Basislinie an Metriken auf, sobald die Extension gestartet wird:

  • Actor-Metriken — Message-Counts pro Actor-Typ, Verarbeitungsdauer-Histogramme, Mailbox-Tiefe-Gauges.
  • Mailbox-Metriken — Enqueue-Rate, Dequeue-Rate, Anzahl gedroppter Nachrichten für Bounded Mailboxes.
  • Cluster-Metriken — Anzahl der Mitglieder nach Zustand, Gossip-Lag, Reachability-Flips.

Siehe Stock-Metriken für die vollständige Liste. Damit bekommst du „Verarbeiten meine Actor Nachrichten?” Out-of-the-Box, ohne einen einzigen Metrik-Code zu schreiben.

import { ActorSystem, TracingExtensionId } from 'actor-ts';
import { OtelTracerAdapter } from 'actor-ts';
const system = ActorSystem.create('my-app');
system.extension(TracingExtensionId).configure({
tracer: new OtelTracerAdapter({ /* OTel SDK Setup */ }),
});

Mit aktiviertem Tracing bekommt jede Actor-Nachricht ihren eigenen Span. Der Span trägt:

  • Den Pfad des Actors.
  • Die Klasse / Art der Nachricht.
  • Den Parent-Span-Kontext (aus dem aktiven Span des Senders).
  • Die Dauer von onReceive.

Spans verketten sich über Tells hinweg — ein Actor, der einen Request verarbeitet und einem anderen Actor etwas tellt, gibt den aktuellen Span-Kontext via Envelope weiter; der Span des zweiten Actors verlinkt zurück zum ersten.

HTTP-Request

actor /user/api

empfängt Request

actor /user/db

verarbeitet Query — verlinkt zurück

Postgres-Span

OTel-Auto-Instrumentation

Das Endergebnis: ein Trace pro logischem Request, selbst wenn er durch 4-5 Actor hüpft.

Der Exporter ist OpenTelemetry-konform. Nutze OtelTracerAdapter in Produktion; ein RecordingTracer existiert für Tests.

import { HttpManagement, ActorSystem } from 'actor-ts';
const system = ActorSystem.create('my-app');
const management = await HttpManagement.start(system, {
port: 8558,
cluster, // optional, für /cluster-Endpunkte
});

Das startet einen kleinen HTTP-Server (getrennt vom HTTP-Server deiner App), der Endpunkte für den Betrieb bereitstellt:

EndpunktWas
GET /health/readyLiveness — läuft das System?
GET /health/aliveReadiness — ist das System bereit für Traffic?
GET /cluster/membersListe der Cluster-Mitglieder (wenn Cluster konfiguriert ist).
GET /sharding/regionsSharding-Regionen, gehostete Shards pro Node.
GET /metricsPrometheus-Exposition, wenn PrometheusExporter konfiguriert ist.

Nützlich für K8s-Probes (Liveness + Readiness) und Ad-hoc- Operations-Debugging. Siehe HTTP-Endpunkte für die volle Oberfläche.

management.addHealthCheck('db', async () => {
if (!(await db.ping())) return { ok: false, reason: 'db unreachable' };
return { ok: true };
});

Eigene Checks hängen sich in /health/ready ein — ein fehlschlagender Check lässt den Endpunkt 503 zurückgeben, was K8s als „nicht zu diesem Pod routen” liest.

Siehe Health Checks für die Konfiguration.

Für ein neues Produktivsystem:

  1. Metriken — zumindest die Stock-Metriken, mit einem Prometheus-Exporter. Counter- und Gauge-Dashboards geben dir „was macht das System gerade?”.
  2. Health Checks — Liveness + Readiness für K8s. Selbst wenn dein Workload keine fancy Probes braucht, will K8s diese Endpunkte.
  3. Tracing — zuletzt. Tracing ist aufwendiger (Exporter-Konfiguration, Sampling, Kosten) und bringt abnehmenden Grenznutzen für einfache Apps. Füge es hinzu, wenn du Multi-Actor-Requests hast und Ende-zu-Ende-Latenz sehen musst.

Für ein Dev-/Staging-Umfeld ist nichts davon Pflicht — Console-Logs decken die Basics ab.