Kontakt

Nino Grossrieder (-Müller)

Keine Nachricht verlieren: Dead-Lettering und Reconciliation in der Streaming-Ingestion

Die unangenehmste Frage in jedem Datenprojekt lautet nicht «Stimmt die Zahl?», sondern «Sind alle Daten drin?». Die erste Frage können Sie nachrechnen. Die zweite können Sie nur beantworten, wenn Ihre Pipeline von Anfang an dafür gebaut wurde.

In einer Streaming-Ingestion verschwinden Nachrichten leise. Kein Fehler im Log, kein Alarm, keine Lücke im Dashboard – nur eine Kurve, die etwas flacher ist, als sie sein sollte. Dieser Artikel beschreibt drei Bausteine, die das verhindern: ein Verbatim-Archiv, einen Dead-Letter mit Begründung, und eine Reconciliation-Invariante, die jederzeit aufgehen muss. Die Beispiele stammen aus einer MQTT-Pipeline mit HiveMQ als Broker und TigerData als Zeitreihendatenbank – das Prinzip gilt für jede Streaming-Ingestion.

Die zwei Arten, wie Nachrichten verschwinden

Es gibt genau zwei Fehlerklassen, und die meisten Pipelines behandeln nur die erste:

  • Kaputte Eingabe. Ungültiges JSON, ein Topic, das nicht zum erwarteten Muster passt, ein leeres Payload. Das fällt beim Parsen auf und landet im Log.
  • Gültige Eingabe, die niemand routen kann. Die Nachricht ist einwandfrei – nur kennt Ihre Pipeline diesen Nachrichtentyp nicht, oder das Feld, das den Messwert tragen sollte, ist leer, oder eine fachliche Regel greift nicht. Das fällt nicht auf. Frühe Versionen unserer Pipeline haben genau diese Fälle still verworfen – und das war der teuerste Fehler im ganzen Projekt.

Beide müssen sichtbar werden. «Verworfen» ist ein Zustand, den man sehen können muss.

Baustein 1: das Verbatim-Archiv

Bevor der Transformationsjob eine einzige Zeile interpretiert, kopiert er den gesamten übernommenen Batch unverändert in eine Archivtabelle. Topic, Payload, Ankunftszeit – genau so, wie es der Broker geliefert hat.

Das kostet Speicher, den Sie über eine Retention-Policy nach wenigen Tagen oder Wochen wieder freigeben. Und es kauft Ihnen zwei Dinge, die man nicht nachträglich beschaffen kann:

  • Trennung von Empfang und Verarbeitung. «Haben wir es bekommen?» und «Haben wir es richtig verarbeitet?» werden zu zwei unabhängigen Fragen mit unabhängigen Antworten.
  • Reprocessing. Stellt sich eine Transformationsregel nach drei Wochen als falsch heraus, ist das Original noch da. Ohne Archiv ist derselbe Fehler ein Datenverlust.

Baustein 2: der Dead-Letter mit Begründung

Jede Zeile, die der Job nicht in einen Fakt verwandeln kann, wird in eine Dead-Letter-Tabelle geschrieben – zusammen mit dem Grund im Klartext. Nicht ein Fehlercode, sondern ein Satz, den auch jemand versteht, der die Pipeline nicht gebaut hat.

Typische Gründe in der Praxis:

AblehnungsgrundWas dahinterstecktTypische Reaktion
Ungültiges JSONGerät sendet fehlerhaft oder abgeschnittenFirmware prüfen
Topic passt nicht zum MusterNamenskonvention verletztKonfiguration am Gerät korrigieren
Unbekannte Nachrichtenartneuer Anlagentyp angeschlossenRegel ergänzen, Archiv neu verarbeiten
Kein verwertbarer WertFeld leer oder unerwartet benanntPayload-Vertrag klären
Zeitstempel nicht interpretierbarunbekanntes ZeitformatKonvertierung erweitern
Signal nicht in der DimensionTag wurde nie registriertIdentitätsauflösung prüfen

Der Dead-Letter ist damit nicht nur ein Sicherheitsnetz, sondern ein Betriebsinstrument: Er sagt Ihnen, welches Gerät ein Problem hat, noch bevor jemand ein fehlendes Dashboard meldet. Ein Alarm auf «mehr als N Dead-Letter pro Stunde» ist eine der nützlichsten Regeln, die Sie einrichten können.

Baustein 3: die Reconciliation-Invariante

Das eigentliche Herzstück ist eine Gleichung, die immer gelten muss:

empfangen = archiviert
archiviert = transformiert + Dead-Letter

Wenn diese Rechnung aufgeht, wissen Sie mit Sicherheit, dass nichts unbemerkt verschwunden ist. Wenn sie nicht aufgeht, haben Sie einen Bug – und zwar einen, den Sie sonst nie gefunden hätten.

Praktisch bedeutet das: eine kleine Abfrage, die diese drei Zähler für ein Zeitfenster vergleicht, als Panel im Betriebsdashboard und als Alarm. Das ist eine halbe Stunde Arbeit und der beste Vertrauensbeweis, den eine Datenplattform liefern kann – gegenüber der IT ebenso wie gegenüber dem Fachbereich, der auf den Zahlen Entscheidungen trifft. Wer Datenqualität ernst meint, fängt hier an, nicht bei Plausibilitätsregeln.

Defensiv parsen: eine schlechte Zeile darf keinen Batch kippen

Die Invariante hält nur, wenn ein einzelner Ausreisser nicht den ganzen Lauf abbricht. Zwei Stellen sind dafür in der Praxis verantwortlich.

Zeitstempel sind nie einheitlich

Geräte senden Zeit, wie es ihnen passt: Sekunden, Millisekunden, Mikrosekunden, Nanosekunden seit 1970 – oder ISO-8601 als Text. Ein fest verdrahteter Cast funktioniert bis zu dem Tag, an dem ein neuer Gerätetyp dazukommt.

Robust ist eine kleine Konvertierungsfunktion: Besteht der Wert nur aus Ziffern, leitet sie die Einheit aus der Stellenzahl ab. Sonst versucht sie ISO-8601. Und bei allem, was sie nicht versteht, gibt sie NULL zurück, statt eine Exception zu werfen. Fehlt der Zeitstempel im Payload ganz, greift die Ankunftszeit als Fallback – markiert, damit später niemand darauf hereinfällt.

JSON verschweigt Typen

Eine JSON-Zahl sagt Ihnen, dass sie eine Zahl ist – nicht, ob die Quelle einen Integer, einen vorzeichenlosen Wert oder eine Fliesskommazahl gemeint hat. Ein Boolean muss unter Umständen als 1 oder 0 in einer numerischen Spalte landen.

Zwei Massnahmen haben sich bewährt: eine Konvertierungsfunktion, die JSON-Skalare sinnvoll auf eine numerische Spalte abbildet, und ein selbstfüllender Typ-Hinweis in der Dimensionstabelle – beim ersten Auftreten eines Signals wird der wahrscheinlichste Typ vermerkt. Ehrlich bleiben gehört dazu: Manche Unterscheidungen sind aus JSON schlicht nicht rekonstruierbar und müssen über Konvention oder Konfiguration kommen.

Und noch eine Falle: der Upsert, der IDs verbrennt

Beim Auflösen von Identitäten liegt eine Falle, die nichts mit Verlust zu tun hat, aber im selben Codeabschnitt wohnt: INSERT … ON CONFLICT DO NOTHING wertet nextval() aus, bevor der Konflikt erkannt wird – jede Dublette erhöht die Sequenz still. Details und die Lösung stehen im Artikel zum Time-Series-Schema auf TigerData.

Der blinde Fleck: die Lizenz der Ingest-Extension

Ein Ausfallmodus, den keine Reconciliation innerhalb der Datenbank sieht: Läuft die Lizenz der Ingest-Extension ab, stoppt der Datenfluss in die Datenbank – der Broker läuft unbeeindruckt weiter. Es gibt keinen Fehler, keine abgelehnte Nachricht, nur Stille. Behandeln Sie die Lizenz deshalb als Teil Ihrer Verfügbarkeit und überwachen Sie sie wie jede andere Komponente. Eine einfache Regel genügt: Wenn seit X Minuten nichts mehr in der Landing-Tabelle angekommen ist, alarmieren.

Was es kostet – und wann es zu viel ist

Archiv, Dead-Letter und Reconciliation kosten etwa einen zusätzlichen Entwicklungstag und einen überschaubaren Anteil Speicher. Das ist verglichen mit dem Nutzen ein Schnäppchen, sobald Ihre Daten in Entscheidungen einfliessen.

Wo es Überbau ist: bei einem Prototyp mit einer Handvoll Signalen, der in vier Wochen wieder abgeschaltet wird. Dort reicht ein Log. Sobald aber jemand im Betrieb auf die Zahlen schaut – oder eine Behörde sie sehen könnte – gehört die Invariante dazu.

Wie wir Sie unterstützen

Operative Zuverlässigkeit ist der Unterschied zwischen einem Prototyp und einem System, auf das sich jemand verlässt. Wir bauen und betreiben operative Datensysteme und Datenplattformen, bei denen genau diese Fragen vorab beantwortet sind – für Schweizer Industrie- und Logistikbetriebe, Verkehrsbetriebe und öffentliche Verwaltungen.

Sie sind nicht sicher, ob Ihre Pipeline Daten verliert? → Kontakt aufnehmen – die Reconciliation-Abfrage ist meist in einem halben Tag gebaut, und die Antwort haben Sie am selben Nachmittag.

Weiterführende Glossar-Artikel

kontakt

Wir freuen uns, von Ihnen zu hören!
Nino Grossrieder (-Müller)