Datendrehscheibe statt Durchreiche: Pulsar Functions im Datenstrom

Datendrehscheibe statt Durchreiche: Pulsar Functions im Datenstrom
By Matthias Petermann / on 19.12.2025

Einleitung: Vom Message Bus zur Datendrehscheibe

Event-Streaming-Plattformen gelten in vielen Architekturen noch immer als notwendige, aber weitgehend passive Infrastruktur. Sie transportieren Nachrichten von A nach B, entkoppeln Systeme zeitlich und sorgen im Idealfall für Zuverlässigkeit und Skalierbarkeit. Damit endet ihre Rolle jedoch häufig.

Apache Pulsar erlaubt – unter klaren technischen und organisatorischen Annahmen – einen anderen Zuschnitt. Die Plattform kann nicht nur Nachrichten transportieren, sondern zur zentralen Datendrehscheibe werden, in der Datenzugriff, einfache Entscheidungslogik und Governance zusammenfallen.

Der Gedanke dahinter ist pragmatisch: Wenn Daten ohnehin durch ein zentrales System fließen, können bestimmte Regeln, Selektionen und einfache Transformationen dort stattfinden – sofern sie den Datenfluss betreffen (und nicht fachliche Kernlogik darstellen), und sofern Ownership, Betrieb und Grenzen sauber definiert sind.

Dieser Artikel zeigt, wie Pulsar Functions diesen Ansatz umsetzen, unter welchen Bedingungen er sich bewährt – und wo bewusst Grenzen gezogen werden müssen.

Apache Pulsar: Architektur und Grundbegriffe

Um Pulsar Functions sinnvoll einordnen zu können, lohnt sich ein kurzer Blick auf die zentralen Begriffe.

Broker sind die aktiven Knoten des Systems. Sie nehmen Nachrichten entgegen, verwalten Topics und Subscriptions und führen – optional – Pulsar Functions aus. Wichtig dabei: Broker sind bewusst zustandsarm konzipiert und lassen sich horizontal skalieren. Persistenter Zustand liegt außerhalb des Brokers (z. B. in BookKeeper).

Tenants bilden die oberste organisatorische und sicherheitstechnische Grenze. Sie trennen Mandanten, Organisationseinheiten oder Projekte sauber voneinander.

Namespaces strukturieren Tenants weiter. Sie bündeln Topics, Subscriptions, Retention-Regeln, Quotas und ACLs – und sind damit ein klar abgegrenzter Datenraum. In der Praxis ist der Namespace häufig auch die zentrale Einheit, um Deployments, Limits und Verantwortlichkeiten für Functions zu organisieren.

Topics sind persistente Event-Streams. Nachrichten werden nicht einfach weitergereicht, sondern dauerhaft gespeichert und zeitlich entkoppelt konsumierbar gemacht.

Subscriptions definieren, wie Topics gelesen werden. Sie sind kein Detail, sondern ein zentrales Governance-Instrument für Zugriff, Semantik, Wiederholbarkeit und Lastverteilung.

ℹ️ Infrastruktur, nicht Applikation
Diese Konzepte sind Teil der Infrastruktur. Sie beschreiben den kontrollierten Datenraum, in dem sich Anwendungen bewegen dürfen – unabhängig von deren Implementierung.

Pulsar Functions: Compute im Datenstrom – mit klaren Grenzen

Pulsar Functions erweitern dieses Modell um gezielten Compute. Sie erlauben es, Nachrichten direkt im Datenstrom zu:

  • filtern
  • weiterzuleiten (Routing)
  • zu transformieren
  • technisch anzureichern

Dabei geht es nicht darum, beliebige Fachlogik in den Broker zu verlagern. Pulsar Functions adressieren genau jene Logik, die unmittelbar mit dem Datenfluss verbunden ist – also dort, wo Entscheidungen am Datenrand sonst verteilt und schwer kontrollierbar werden.

💡 Zentrale Eigenschaft
Pulsar Functions werden im Pulsar-Ökosystem betrieben und sind kein separater Dienst, der „daneben“ existiert. Das verschiebt Datenfluss-Logik in einen beobachtbaren, messbaren und kontrollierbaren Kontext.
⚠️ Was nicht in Functions gehört
Komplexe Fachlogik, lange oder blockierende I/O (z. B. synchrone API-Calls pro Message), umfangreicher Zustand, rechenintensive Jobs oder „Workflows“ gehören in der Regel nicht in Pulsar Functions. Wenn eine Function zum Mini-Microservice wird, ist sie zu groß.

Betrieblich gilt: Eine Function ist Code im Datenpfad. Sie kann den Datenfluss verbessern – oder ihn, bei schlechter Disziplin, destabilisieren. Das ist kein Argument gegen Functions, aber ein Argument für klare Regeln, Ownership und Guardrails.

Fallbeispiel: Digitale Produkte im ERP-Datenstrom

Betrachten wir ein typisches Szenario aus der Praxis.

Ein proprietäres ERP-System vermittelt sämtliche Business-Transaktionen über einen Message Bus. Um eine Bestellung auszuführen, erwartet es eine Nachricht mit einem Warenkorb vom Shopsystem. Pro Sekunde gehen tausende solcher Bestellungen ein. Zusätzlich existiert ein Auslieferungssystem für digitale Produkte wie eBooks oder MP3-Downloads. Dieses System interessiert sich ausschließlich für Bestellungen, die mindestens ein digitales Produkt enthalten, um dem Kunden anschließend einen Download-Link bereitzustellen.

Auf einem „dummen“ Message Bus müsste das Auslieferungssystem alle Bestellungen konsumieren, jede Nachricht parsen und selbst entscheiden, ob sie relevant ist.

Das führt typischerweise zu:

  • unnötigem Netzwerk-Traffic (alle Daten überall hin)
  • verschwendeter Rechenleistung am Edge (jeder Consumer macht dieselbe Selektion)
  • proprietären Formaten, die tief in konsumierende Systeme hineinwandern (Kopplung)
  • Debugging- und Governance-Problemen („Wer filtert wo – und warum?“)

Eine Anpassung des ERP-Systems ist – was keine Seltenheit ist – oft teuer, zeitaufwändig oder schlicht nicht möglich.

Die Pulsar-Lösung: Selektion im Flug – unter Governance

Apache Pulsar erlaubt, diese Logik dorthin zu verlagern, wo sie am meisten Wirkung hat: in den Datenstrom selbst – sofern sie eng am Datenfluss bleibt und sauber betrieben wird.

Eine Pulsar Function analysiert eingehende Bestellungen, erkennt digitale Produkte und leitet nur relevante Nachrichten auf ein dediziertes Topic weiter. Optional kann an dieser Stelle bereits eine Transformation in ein neutrales, herstellerunabhängiges Fachformat erfolgen.

⚠️ Der übliche Einwand
„Dann gibt es zusätzliche Logik, die gewartet und geownt werden muss.“

Das ist korrekt. Die Alternative ist jedoch nicht „keine Logik“, sondern eine (meist schlechter kontrollierbare) Verteilung:

  • Selektion in jedem Konsumenten (diffus, schwer zu auditieren)
  • zusätzliche Bridge-Services (mehr Infrastruktur, eigener Lifecycle)
  • oder Druck auf den ERP-Hersteller (oft unrealistisch)
ℹ️ Ownership: Wer besitzt die Function?
Eine Stream-Function sollte organisatorisch zur Plattform / Integration gehören (z. B. Data Platform Team), nicht zu einzelnen Fachanwendungen. Damit ist klar, wer Änderungen reviewt, deployed und im Incident-Fall reagiert.

Alternativen im Vergleich – fair eingeordnet

Ansatz Vorteile Nachteile Systemische Auswirkungen
🔴 Proprietäres Format bis zum Konsumenten Keine zusätzliche Stream-Logik, einfache Producer Jeder Consumer muss alle Messages lesen und parsen, hohe Kopplung Hoher Netzwerk-Traffic, CPU-Last in allen Consumern, skaliert schlecht mit Anzahl der Subscriptions
🔴 Zusätzliche Bridge-Services Zentrale Selektion möglich, fachliche Consumer entlastet Zusätzliche Services, eigener Betrieb und Lifecycle Doppelte Datenbewegung, zusätzliche Latenz, neue Failure-Domäne
🔴 Anpassung durch ERP-Hersteller Selektion am Ursprung, saubere API Oft unrealistisch, lange Vorläufe, externe Abhängigkeit Hohe Projektkosten und Time-to-Market-Risiko
🟢 Pulsar Function Selektion vor dem Fan-out, geringe Latenz, auditierbar Code im Datenpfad, diszipliniertes Debugging erforderlich Einmalige Selektion im Stream, minimale Netzwerk- und Consumer-Last bei klaren Guardrails

Function Development

Die eigentliche Function ist hier bewusst in Java umgesetzt: Es ist in vielen Unternehmen etabliert und fügt sich gut in bestehende Build- und Betriebsprozesse ein.

Wichtiger als die Sprache ist das Modell: Eine Pulsar Function ist eine kleine, klar abgegrenzte Einheit, die genau eine Entscheidung im Datenstrom trifft. Sie implementiert das Interface Function<I, O> und besitzt keine eigene Infrastruktur, keinen eigenen Server und keinen eigenen „Service-Lifecycle“.

Die folgende Function prüft eingehende Bestellungen lediglich darauf, ob sie digitale Produkte enthalten. Das Beispiel ist bewusst einfach gehalten, um den Fokus auf das Prinzip zu legen – nicht auf Parsing- oder Schema-Details.

package net.d2ux.stream.order.filter;

import org.apache.pulsar.functions.api.Context;
import org.apache.pulsar.functions.api.Function;

public final class DigitalOrderFilter implements Function<String, String> {

    private static final String KEYWORD = "digital";

    @Override
    public String process(String input, Context context) {

        if (input == null || input.isBlank()) {
            context.getLogger().debug("Skipping empty message");
            return null;
        }

        // echte Systeme nutzen Schema (JSON/Avro) + robuste Validierung.
        if (input.toLowerCase().contains(KEYWORD)) {
            context.getLogger().info("Digital order detected");
            return input;
        }

        return null;
    }
}
ℹ️ Return null heißt: filtern
In Pulsar Functions bedeutet return null, dass die Message verworfen wird.
⚠️ Produktionshinweis
In der Praxis gehören hier typischerweise mindestens dazu: Schema (z. B. JSON/Avro), Keys, Validierung, DLQ/Dead-Letter-Strategie und Tests. Das Beispiel zeigt bewusst nur das Entscheidungsmodell.

Build und Deployment der Function

Der Build der Function erfolgt mit Maven. Zu einem vollständigen Projekt gehören daher eine pom.xml, eine saubere Paketstruktur sowie (idealerweise) Tests und CI-Definitionen.

Für das Beispiel genügt ein einfacher Build-Schritt, der ein ausführbares JAR erzeugt:

mvn clean install

Das Ergebnis ist ein einzelnes JAR. Deployment erfolgt über die Pulsar Shell:

$ pulsar-shell
default(localhost)> admin functions create \
  --tenant public \
  --namespace default \
  --name order.filter.digital \
  --jar /abs/path/filter-order-digital-1.0.0.jar \
  --classname net.d2ux.stream.order.filter.DigitalOrderFilter \
  --inputs persistent://public/default/orders.raw \
  --output persistent://public/default/orders.filtered.digital
ℹ️ Governance by Design
Die Function unterliegt denselben organisatorischen Grenzen wie Topics und Subscriptions: Tenant/Namespace, ACLs, Quotas, Observability und (je nach Setup) Deployment-Policies.

Governance konkret: Guardrails statt Wildwuchs

„Compute im Stream“ wird nur dann zu einem Vorteil, wenn er kontrolliert bleibt. Typische Guardrails, die sich in der Praxis bewähren:

  • Deployment-Rechte: Nur definierte Rollen/Teams dürfen Functions erstellen/ändern.
  • Topic-Whitelist: Functions dürfen nur auf freigegebene Topics zugreifen (Input/Output).
  • Namens- und Versionierungsregeln: Klar erkennbar, was „prod“ ist und was „experiment“.
  • Change-Management: Review, CI, Rollback-Plan.
  • Limits: Quotas und Ressourcenbegrenzung pro Namespace, um den Broker zu schützen.

Das ist der Punkt, an dem „Governance“ konkret wird: nicht als Buzzword, sondern als Satz von Regeln, die Betrieb möglich machen.

Tests im Datenstrom mit der Pulsar CLI

Streaming-Systeme testet man am sinnvollsten dort, wo sie wirken: im laufenden Datenfluss. Statt komplexer Test-Harnesses genügt hier oft ein bewusst einfacher Ansatz, der dennoch ein realistisches Verhalten prüft.

Die Pulsar CLI erlaubt es, gezielt Producer und Consumer zu starten und damit das Verhalten der Function im Zusammenspiel mit Broker, Topics und Subscriptions zu beobachten.

Im ersten Schritt wird ein Consumer auf dem Ziel-Topic gestartet, auf das die Function relevante Nachrichten weiterleitet:

$ export PULSAR_URL=pulsar://127.0.0.1:6650
$ pulsar-cli consumer -t 'persistent://public/default/orders.filtered.digital' -s debug

Producer auf dem Quell-Topic:

$ echo "Bestellung analog"  | pulsar-cli producer -t 'persistent://public/default/orders.raw'
$ echo "Bestellung digital" | pulsar-cli producer -t 'persistent://public/default/orders.raw'

Erwartetes Verhalten: Nur die digitale Bestellung erscheint im Ziel-Topic.

ℹ️ Warum das ein echter Test ist
Dieser Test validiert nicht nur Code, sondern den kompletten Datenfluss inklusive Broker, Topics/Subs und den zugehörigen Policies.

Monitoring und Transparenz

Pulsar exportiert umfassende Metriken für Functions. Latenzen, Durchsatz und Fehler sind sichtbar – keine Blackbox.

Wichtig: Debugging im Stream ist anders als Debugging in Services. Man braucht klare Metriken, saubere Logs und definierte SLOs. Dann wird es beherrschbar.

Metrik Bedeutung
pulsar_function_received_total Empfangene Messages
pulsar_function_processed_successfully_total Erfolgreiche Verarbeitungen
pulsar_function_user_exceptions_total Fehler im Function-Code
pulsar_function_process_latency_ms Verarbeitungs-Latenz

Fazit

Pulsar Functions sind kein Ersatz für Microservices und kein beliebiges Serverless-Feature. Sie sind ein präzises Werkzeug für klar abgegrenzte Entscheidungen im Datenstrom.

Wer ihre Grenzen respektiert, Ownership klärt und Governance ernst nimmt, kann Compute dort platzieren, wo Daten ohnehin fließen – mit hoher Transparenz, auditierbaren Regeln und häufig deutlich weniger Streuverlust als bei Edge-Selektion in jedem Konsumenten.

Apache Pulsar zeigt damit: Ein Message Bus kann mehr sein als Transport – eine beherrschbare Datendrehscheibe, wenn man sie als Infrastrukturprodukt betreibt (und nicht als Zufalls-Skript-Sammelplatz).

🚀 Vollständiges Beispielprojekt

Das vollständige Maven-Projekt inklusive aller hier gezeigten Beispiele ist verfügbar unter:

https://forge.ext.d2ux.net/OpenLab/pulsar-stream-functions


Bildnachweis: Das Pulsar-Logo ist eine eingetragene Marke der Apache Software Foundation. Verwendung im Rahmen redaktioneller Berichterstattung gemäß den offiziellen Richtlinien.