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.
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.
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.
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)
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, dass die Message verworfen wird.
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 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.
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).
Das vollständige Maven-Projekt inklusive aller hier gezeigten Beispiele ist verfügbar unter:
- Apache Pulsar (Projektseite): https://pulsar.apache.org/
- Apache Pulsar Shell: https://pulsar.apache.org/docs/next/administration-pulsar-shell/
- Pulsar CLI: https://forge.ext.d2ux.net/OpenLab/pulsar-cli
- Pulsar Function Tutorials: https://pulsar.apache.org/docs/4.0.x/functions-develop-tutorial/
Bildnachweis: Das Pulsar-Logo ist eine eingetragene Marke der Apache Software Foundation. Verwendung im Rahmen redaktioneller Berichterstattung gemäß den offiziellen Richtlinien.