Was ist Ticketing?
Ticketing ist ein dedizierter Lock-Server, entworfen für genau eine Aufgabe — verteiltes Sperren. Es ist eine einzelne Rust-Server-Binary, gepaart mit offiziellen Clients für jede Sprache, die alle byte-genau dasselbe binäre Protokoll implementieren. Nur zwei Operationen — Acquire und Release —, eine FIFO-Warteschlange pro Schlüssel, Fencing-Tokens und ein optionaler Raft-Cluster, den du bei Bedarf einschaltest. Alles, was eine verteilte Sperre braucht, und sonst nichts.
Wie unterscheidet sich das von Sperren, die auf einem Store aufbauen?
Die meisten verteilten Sperren in der Praxis stützen sich auf einen Key-Value-Store — ein Lua-Skript oder Redlock auf Redis, oder eine Sperre, die auf den Sessions und Leases von ZooKeeper oder etcd aufbaut. Redis ist ein hervorragender Store, aber er ist ein für verteiltes Sperren zweckentfremdeter Key-Value-Store, kein von Grund auf für Sperren gebautes System — und das zeigt sich als struktureller Overhead: Die Parsing-Kosten eines universellen Protokolls und der Overhead universeller Datenstrukturen sind immer mit dabei.
Ticketing wurde von Tag eins an ausschließlich für verteiltes Sperren entworfen, sodass jede Schicht um Sperren herum gebaut ist.
- Protokoll — binäre Felder fester Breite, weder Text noch ein universelles Serialisierungsformat. Werte werden direkt per Byte-Offset ohne Parsing gelesen, und Pipelining erlaubt es, die nächste Anfrage zu senden, ohne auf die vorherige Antwort zu warten.
- Server-Interna — der gesamte Zustand ist eine FIFO-Warteschlange pro Schlüssel plus ein Lease-Timer. Der Anfragepfad alloziert nicht einmal auf dem Heap.
- Betrieb — starte eine Server-Binary (oder einen Container), konfiguriere sie mit einer Handvoll Umgebungsvariablen, und du bist fertig. Kein Schema-Design, kein separater Store, kein sperr-fremdes Betriebswissen erforderlich.
Performance
- Verarbeitet über 1 Million Operationen pro Sekunde bei unter 10 MB Speicherverbrauch
Warum Ticketing
🚦 Reihenfolge-Integrität — FIFO-Warteschlange mit direkter Übergabe
Wer zuerst wartet, wird zuerst bedient. Wenn der Inhaber freigibt, wird die Sperre direkt und ohne erneuten Wettbewerb an die Spitze der Warteschlange übergeben. Kein Verhungern durch Polling-und-Retry-Wettbewerb um die Sperre, und keine Retry-Stürme.
🛟 Ein toter Client lässt die Sperre nicht hängen — lease
Stirbt der Prozess, der die Sperre hält, oder bricht seine Verbindung ab, holt sich der Server die Sperre automatisch zurück, sobald die bei Acquire festgelegte lease-Dauer abgelaufen ist, und übergibt sie an den nächsten Wartenden. Ein vergessenes Release legt nicht das ganze System lahm.
🔑 Verhindert Arbeit in falscher Reihenfolge — Fencing-Tokens
Es gibt einen Fehlerfall, den eine Sperre allein nicht verhindern kann: ein Inhaber, der verspätet aufwacht — ohne zu wissen, dass seine lease bereits abgelaufen ist — und trotzdem verlangt, seine Arbeit abzuschließen. Ticketing vergibt bei jedem Acquire ein monoton steigendes Fencing-Token. Solange die geschützte Ressource eine einzige Regel durchsetzt — "jedes Token ablehnen, das niedriger ist als das zuletzt gesehene" —, wird selbst diese letzte Lücke geschlossen. Die vollständige Erklärung findest du unter Funktionsweise.
🗳️ Ein unterbrechungsfreier Cluster auf Basis von Raft
Ein einzelner Server reicht für sich genommen aus, aber wenn du Nullausfallzeit brauchst, bildest du einen Cluster aus 3 (oder 5) Knoten. Jede Zustandsänderung einer Sperre wird erst finalisiert, nachdem eine Mehrheit der Knoten per Raft-Konsens zugestimmt hat, sodass dieselbe Sperre niemals zweimal gleichzeitig vergeben wird — selbst wenn der Leader stirbt oder das Netzwerk partitioniert wird. Fällt der Leader aus, wird in etwa einer Sekunde ein neuer gewählt, und Clients wechseln automatisch um. Der Dienst läuft weiter, selbst wenn Knoten nacheinander ausfallen — etwa bei Cloud-Instanz-Neustarts oder einer rollierenden Wartung.
🔒 Eingebaute Authentifizierung und TLS
Jede Verbindung durchläuft unmittelbar nach dem Verbindungsaufbau eine Challenge-Response-Token-Authentifizierung, und das Token wird niemals im Klartext über die Leitung gesendet. Verschlüssele die gesamte Verbindung bei Bedarf mit TLS.
🌐 Dasselbe Protokoll, byte-genau, über jede wichtige Sprache hinweg
Rust, Java/Kotlin, JavaScript/TypeScript, Python, C#, Go, Ruby, C/C++ — jeder offizielle Client implementiert dasselbe binäre Protokoll, mit einer API, die sich im Ökosystem jeder Sprache natürlich anfühlt (async oder blockierend). Eine in einer beliebigen Sprache erworbene Sperre reiht sich fair in dieselbe Warteschlange ein wie Clients, die in jeder anderen Sprache geschrieben sind. Installationsanleitungen und Beispiele findest du unter Bibliotheken.
Nur zwei Operationen
Getreu einem reinen Lock-Server ist auch die Angriffsfläche minimal.
- Hänge einen Schlüssel an die Ressource, die du schützen willst — z. B.
order-1234,account-77,daily-batch. - Erwirb (acquire) diesen Schlüssel, bevor du die Arbeit erledigst — hält ihn jemand anders, wartest du in der FIFO-Warteschlange, bis du an der Reihe bist.
- Gib ihn frei (release), wenn die Arbeit erledigt ist — der nächste Wartende übernimmt sofort, ohne erneuten Wettbewerb.
Die einzigen Optionen zu diesen beiden Operationen sind lease (automatisches Zurückholen) und waitTimeout (Warten aufgeben) — das ist die gesamte API.
Was als Nächstes zu lesen ist
- Wie Sperren tatsächlich vergeben werden und wie der Cluster stabil bleibt — Funktionsweise
- Die exakte Byte-genaue Spezifikation dessen, was über die Leitung geht — Protokoll (API)
- Den Server-Startbefehl generieren — Ticketing-Serverbereitstellung