minipulsar – aktueller Stand des Pulsar-kompatiblen Broker-Prototyps für Edge-Szenarien

minipulsar – aktueller Stand des Pulsar-kompatiblen Broker-Prototyps für Edge-Szenarien
By Matthias Petermann / on 31.01.2026

Ausgangspunkt: das Protokoll-Experiment

In der Vorweihnachtszeit hatte ich ein Experiment beschrieben, das aus einer eher banalen, aber wiederkehrenden Situation entstand: In Gesprächen und beim Troubleshooting tauchte immer wieder die Frage auf, was bei Pulsar eigentlich wirklich auf der Leitung passiert.

Im Alltag verlässt man sich auf Client-Libraries, APIs und Konfigurationen. Das funktioniert gut – blendet aber genau den Teil aus, in dem sich viele Annahmen, Zustände und implizite Regeln verbergen. Auch bei mir war ein Teil dieses Wissens eher gefühlt als verstanden.

Der naheliegendste Weg, das zu ändern, war ein radikaler: einen minimalen Broker zu bauen, der gerade so viel vom Pulsar-Binary-Protokoll implementiert, dass echte Clients damit sprechen können. Nicht als Produkt, nicht als Ersatz für Apache Pulsar, sondern als Analysewerkzeug.

Dieses Ziel wurde erreicht. Der Broker nahm Verbindungen an, verstand die relevanten Kommandos und verhielt sich aus Sicht realer Pulsar-Clients korrekt. Vor allem aber machte er das Protokoll greifbar: Zustände, Reihenfolgen und Erwartungen waren nicht mehr theoretisch, sondern konkret implementiert und beobachtbar.

Eigentlich war damit alles erledigt.


Vom Experiment zum gezielten Prototyp

Der Broker blieb in meinem Werkzeugkasten bestehen, weil er eine Eigenschaft hat, die das Original nicht besitzt: Er ist klein, stabil und vollständig überschaubar. Damit stellte sich eine neue, praktische Frage:

Lässt sich aus einem reinen Protokoll-Experiment gezielt ein Broker entwickeln, der dort sinnvoll einsetzbar ist, wo ein vollständiger Apache-Pulsar-Stack technisch oder betrieblich nicht passt?

Aus meiner täglichen Arbeit mit Apache Pulsar habe ich ein recht klares Gefühl dafür entwickelt, welche Eigenschaften in Unternehmensszenarien tatsächlich kritisch sind – und welche vor allem Komplexität erzeugen, ohne für bestimmte Einsatzbereiche einen proportionalen Mehrwert zu liefern.

Diese Erfahrung ermöglichte eine bewusste Entscheidung: minipulsar sollte kein reduzierter Apache Pulsar sein, sondern ein eigenständiger Broker-Prototyp, der sich konsequent auf einen kleinen, klar definierten Funktionskern konzentriert – und dafür auf einen Großteil der verteilten Infrastruktur verzichtet.

Ein zentrales Motiv für diese Weiterentwicklung war die Plattformunabhängigkeit. Durch die konsequente Nutzung von nativem Go entsteht ein einzelnes statisches Binary ohne Laufzeitabhängigkeiten.

Der Broker läuft bereits heute unverändert auf:

  • Linux
  • NetBSD
  • FreeBSD
  • macOS
  • Windows

Gerade auf langlebigen Systemen, in isolierten Netzen oder auf Edge-Knoten sind diese Eigenschaften oft entscheidender als horizontale Skalierung oder Feature-Vollständigkeit.

ℹ️ Einordnung

minipulsar ist kein Spielzeug und kein vollständiger Ersatz für Apache Pulsar, sondern ein gezielt entwickelter Broker-Prototyp mit klaren Einsatzgrenzen.

Der Fokus liegt auf:

  • Protokolltreue
  • Portabilität
  • expliziten Zustandsmodellen
  • minimaler operativer Komplexität

Vergleich: Apache Pulsar vs. minipulsar

Eigenschaft Apache Pulsar Kommentar minipulsar Kommentar
🎯 Zielsetzung +++ Cloud, zentrale Systeme +++ Edge, Spezial­szenarien
⚙️ Laufzeitmodell JVM, mehrere Prozesse +++ einzelnes Go-Binary
📦 Binary / Image ~ 1 GB Container Image +++ ~ 20 MB Standalone Binary
🧠 RAM-Verbrauch mehrere GB +++ wenige MB
🔗 Abhängigkeiten ZooKeeper, BookKeeper +++ keine externen
🛠 Konfiguration ++- mächtig, komplex +++ deklarativ, überschaubar
💻 Plattformen +– Linux +++ Linux, NetBSD, FreeBSD, MacOS, Windows
🚀 Installation komplex, mehrere Schritte +++ einfach, ein Binary
⏱ Startup-Zeit ~ 30 s +++ instant (< 1 s)
💾 Persistenz +++ verteilt (Ledger) +– lokal (SQLite)
📈 Skalierung +++ horizontal +– lokal (Node)
🌍 Edge-Eignung Overkill +++ explizit dafür

Architektur und Laufzeitmodell

minipulsar besteht aus einem einzelnen statischen Go-Binary. Die zentralen Bausteine sind:

  • TCP-Listener für Pulsar (:6650) und optional TLS (:6651)
  • Protokoll-Layer für Framing, Checksummen und Protobuf-Parsing
  • Broker-Core für Zustandsverwaltung und Delivery
  • Storage-Layer auf Basis von SQLite
  • eine kleine Control Plane über deklarative HCL-Konfiguration
ℹ️ Portabilität
Der Verzicht auf JVM, ZooKeeper, BookKeeper und native Laufzeitabhängigkeiten ermöglicht den Betrieb auf klassischen Unix-Systemen sowie auf ressourcenarmen Edge-Geräten.

Netzwerk und TLS

Der Broker kann gleichzeitig Plain TCP und TLS bedienen. TLS ist als separater Listener umgesetzt und verändert weder das Protokollverhalten noch die internen Zustandsmodelle.

LOOKUP-Antworten lassen sich explizit konfigurieren, sodass Clients konsistente Broker-Adressen erhalten – unabhängig vom verwendeten Transport.

ℹ️ LOOKUP-Verhalten
Pulsar-Clients erwarten, dass LOOKUP-Antworten zum verwendeten Transport passen. minipulsar kann beworbene URLs für Plain und TLS getrennt setzen, um Fehlkonfigurationen auf Client-Seite zu vermeiden.

Unterstützter Pulsar-Protokollumfang

minipulsar implementiert die für klassische Publish/Subscribe-Szenarien notwendigen Protokollpfade:

  • CONNECT / CONNECTED
  • LOOKUP / LOOKUP_RESPONSE
  • PARTITIONED_METADATA (0 Partitionen)
  • PRODUCER / PRODUCER_SUCCESS
  • SEND / SEND_RECEIPT
  • SUBSCRIBE / SUCCESS
  • FLOW / MESSAGE
  • ACK (individual)
  • PING / PONG

Standard-Pulsar-Clients funktionieren damit ohne Anpassung.


Schnellstart

Der Schnellstart zeigt zwei bewusst einfache Varianten: einen Minimalbetrieb ohne Konfigurationsdatei und einen Start mit expliziter HCL-Konfiguration.

Minimaler Start (ohne Konfiguration)

./minipulsar -addr :6650 -db ./minipulsar.db

Der Broker akzeptiert anschließend Pulsar-Clients unter:

pulsar://localhost:6650

Start mit HCL-Konfiguration

./minipulsar -addr :6650 -db ./minipulsar.db -messaging-config ./minipulsar.hcl

Die Struktur und Semantik der HCL-Konfiguration wird in den folgenden Abschnitten erläutert (Namespaces, Policies, Functions und Bindings).

ℹ️ Hinweis
TLS, Authentifizierung, Metriken und Control Plane sind optional und können schrittweise ergänzt werden.

Topics und Persistenzmodell

minipulsar unterscheidet zwischen persistenten und nicht-persistenten Topics.

Persistente Topics verwenden:

  • ein append-only SQLite-Log
  • einen Cursor pro Subscription
  • eine Pending-Tabelle für ausgelieferte, noch nicht bestätigte Nachrichten

Nicht-persistente Topics speichern keine Nachrichten und liefern nur bei aktiven Consumern aus.

ℹ️ Speicherziel
SQLite dient der Nachvollziehbarkeit von Zustand und der Vereinfachung des Systems, nicht der Maximierung von Durchsatz.

Delivery und Backpressure

Die Auslieferung ist vollständig clientgetrieben:

  • Consumer steuern Permits über FLOW
  • der Broker liefert nur bei verfügbaren Permits
  • es existiert keine brokerseitige Priorisierung

Shared Subscriptions werden per Round-Robin bedient. ACKs entfernen Pending-Einträge, ohne den Cursor zu verändern.

ℹ️ Zustandsmodell
Cursor bestimmt beanspruchte Nachrichten; Pending markiert Auslieferung; ACK bestätigt Verarbeitung und entfernt Pending.

Retention und Cleanup

Retention und Subscription-Lebenszyklen werden über die Control Plane definiert:

namespace "persistent://public/default" {
  retention_seconds = 10
  subscription_timeout_seconds = 30
}

Dieses Verhalten begrenzt Speicherbedarf und Zustandsmenge, insbesondere auf ressourcenarmen Systemen.


Security und Zugriffskontrolle

Security besteht aus zwei Ebenen:

  • Verbindungsannahme (security.mode)
  • Namespace-basierte Produce-/Consume-Regeln

Fehlende Regeln führen deterministisch zu Zugriff verweigert.

⚠️ Eigenschaft
Keine impliziten Rollen, keine stillen Fallbacks.

Betriebliche Aspekte und Beobachtbarkeit

Neben dem Protokoll- und Laufzeitmodell adressiert minipulsar auch grundlegende betriebliche Anforderungen, ohne zusätzliche Infrastruktur vorauszusetzen.

Metriken

Der Broker stellt unter http://127.0.0.1:8080/metrics Prometheus-kompatible Metriken bereit.
Diese werden topicfein erfasst und erlauben Einblicke in Verbindungen, Nachrichtenfluss und Auslieferung – ohne externen Agent oder Sidecar.

ℹ️ Beobachtbarkeit
Metriken sind Bestandteil des Brokers, nicht nachträglich angebaut.

Logging

Logging erfolgt konsequent 12-Factor-konform über stdout.
Es gibt keine impliziten Log-Dateien, keine versteckten Pfade und keine Logger-Hierarchien mit Seiteneffekten.

Damit lässt sich minipulsar direkt in bestehende Log-Pipelines integrieren oder einfach per Shell beobachten.

Optionale TUI (Text User Interface)

Optional kann minipulsar mit einer interaktiven TUI gestartet werden.
Diese dient explizit nicht dem produktiven Betrieb, sondern als Werkzeug für Entwicklungs- und Testszenarien.

Die TUI zeigt auf einen Blick:

  • aktive Client-Verbindungen
  • Producer- und Consumer-Aktivität
  • Topic-Zugriffe
  • aktuelle Broker-Ereignisse

Gerade in lokalen Entwickler-Setups oder bei Protokolltests ist dies hilfreich, um unmittelbar zu sehen, wie sich Clients verbinden und wie sich der Broker verhält.

Minipulsar TUI Dashboard

Lokale Functions und Bindings

Ein wiederkehrendes Problem in Messaging-Systemen ist, dass selbst sehr einfache Transformationen oder Weiterleitungen einen vollständigen Consumer- und Producer-Prozess erfordern. Für triviale Datenpfade entsteht dadurch unnötige Komplexität: zusätzlicher Code, zusätzliche Deployments und zusätzliche Betriebszustände.

minipulsar adressiert dieses Problem mit lokalen Funktionen und Bindings, die es erlauben, einfache Verarbeitungsschritte direkt im Broker zu definieren und explizit an Topics zu binden.

ℹ️ Einordnung: Functions in Apache Pulsar

Das Konzept lokaler Nachrichtenverarbeitung existiert in dieser Form bereits in Apache Pulsar. Pulsar Functions erlauben es, eingehende Nachrichten direkt im Kontext des Brokers oder in einer eng angebundenen Laufzeit zu verarbeiten, zu transformieren oder weiterzuleiten – ohne dass dafür ein externer Consumer-Prozess notwendig ist.

Dieses Modell ist konzeptionell stark, weil es Datenpfade explizit beschreibt: Eingang, Verarbeitung und Ziel sind klar definiert und bleiben eng am Messaging-System gekoppelt. Für einfache Transformationen, Filter oder Weiterleitungen reduziert das sowohl Latenz als auch operative Komplexität.

Die Functions in minipulsar sind bewusst daran angelehnt. Ziel war es, eine ähnliche Möglichkeit zu schaffen, jedoch in einer deutlich leichtergewichtigen Form. Statt einer separaten Runtime oder eines komplexen Deployment-Modells werden kleine, deterministische Funktionen lokal im Broker ausgeführt.

Die Wahl von Lua ist dabei bewusst pragmatisch: Die Sprache ist leichtgewichtig, schnell einbettbar und gut geeignet für kurze, klar begrenzte Verarbeitungsschritte – ohne den Broker-Prozess unnötig zu belasten.

Vollständiges Beispiel: Messaging-Konfiguration

security {
  mode = "strict"
}

namespace "persistent://public/default" {
  produce = ["tester"]
  consume = ["tester"]
  subscription_timeout_seconds = 30
  retention_seconds = 10
}

function "transform" {
  path = "transform.lua"
  max_runtime = "250ms"
}

binding {
  source   = "persistent://public/default/temperature.f"
  function = "transform"
  target   = "persistent://public/default/temperature.c"
}
ℹ️ Was diese Konfiguration beschreibt
Producer dürfen nach temperature.f publizieren. Jede eingehende Nachricht wird lokal durch die Funktion transform verarbeitet und das Ergebnis nach temperature.c weitergeleitet.

Die Lua-Funktion: Temperaturumrechnung

function handle(payload, ctx)
  local value = tonumber(payload)
  if value == nil then
    return payload
  end
  local celsius = (value - 32) * 5 / 9
  return string.format("%.2f", celsius)
end

Die Funktion arbeitet ausschließlich auf dem Payload und bleibt vollständig vom Pulsar-Wire-Format entkoppelt.


Bindings als lokale Datenpfade

Ablauf:

  1. Nachricht trifft auf temperature.f ein
  2. Broker ruft die Funktion transform auf
  3. Rückgabewert wird neu publiziert
  4. Consumer lesen aus temperature.c
⚠️ Grenzen
Funktionen sind für kurze, deterministische Verarbeitungsschritte gedacht. Lang laufende oder blockierende Logik gehört nicht in den Broker-Prozess.

Implementierungsansatz

Wie bereits beim ursprünglichen Protokoll-Experiment wurde auch dieser Prototyp iterativ entwickelt. Wesentliche Teile der Codes wurden durch ein LLM unterstützt implementiert; Architekturentscheidungen, Protokollvalidierung und Tests erfolgten bewusst manuell.

ℹ️ Quellcode
Der vollständige Quellcode von minipulsar ist öffentlich zugänglich: https://forge.ext.d2ux.net/OpenLab/minipulsar

Fazit

minipulsar verbindet Pulsar-Protokolltreue mit einem bewusst kleinen, nachvollziehbaren Laufzeitmodell. Als Prototyp zeigt er, dass sich zentrale Eigenschaften von Pulsar – Zustandsmodelle, Flow-Control und Client-Interaktion – auch ohne verteilte Infrastruktur sauber abbilden lassen.

Damit positioniert sich minipulsar nicht als Konkurrenz, sondern als Ergänzung: als Werkzeug für Edge-Szenarien, für isolierte Umgebungen und für alle Fälle, in denen Verständnis, Portabilität und Klarheit wichtiger sind als maximale Skalierung.

Für mich ist minipulsar damit kein abgeschlossenes Projekt, sondern ein laufendes Denk- und Arbeitsobjekt. Solange sich daran neue Fragen zum Protokoll, zu Zuständen oder zu sinnvollen Vereinfachungen ergeben, werde ich weiter daran arbeiten, Dinge ausprobieren und schrittweise schärfen – nicht mit dem Ziel, „mehr“ zu bauen, sondern um besser zu verstehen, was wirklich nötig ist.