Wo Auto-Increment zerbricht
Auto-Increment-IDs sind perfekt, bis man mehr als einen Server hat. Offsets, Ticket-Server, und die Antwort, die wirklich funktioniert.
Ein Thema, das langweilig klingt, bis es zubeißt: Wie erzeugt man eindeutige IDs, wenn mehr als eine Maschine schreibt?
Die zwei üblichen Verdächtigen
UUID. Im Wesentlichen 128 zufällige Bits. Jede Maschine kann eine erzeugen, ohne jemanden zu fragen, Kollisionen sind ein theoretisches Problem. Die Nachteile: groß, nicht nach Entstehungszeit sortierbar, und die Schreibzugriffe verteilen sich wild über den Index, was Datenbanken nicht mögen.
Auto-Increment. Bei 1 anfangen, für jede neue Zeile plus 1. Klein, sortierbar, hervorragende Index-Performance, und die Datenbank macht die ganze Arbeit. Ein Haken: Es funktioniert nur, wenn genau eine Stelle die Nummern vergibt.
Wo es zerbricht
Drei Server, A, B und C, jeder muss selbständig IDs erzeugen. Mit schlichtem Auto-Increment fangen alle bei 1 an. Drei Zeilen, eine ID. Tot bei Ankunft.
Offsets. A startet bei 1, B bei 2, C bei 3, und alle zählen in Dreierschritten. A bekommt 1, 4, 7. B bekommt 2, 5, 8. C bekommt 3, 6, 9. Das funktioniert ganz ordentlich für eine feste Zahl von Servern. Dann kommt Server D dazu. Jetzt müssten alle in Viererschritten zählen, und niemand weiß, wo D anfangen soll, ohne mit bereits vergebenen Nummern zu kollidieren. Das Schema zerbricht genau dann, wenn sich der Cluster verändert, also genau dann, wenn man es am dringendsten braucht.
Ein Ticket-Server. Ein isolierter Server in der Mitte, dessen einzige Aufgabe es ist, die nächste Nummer herauszugeben. A fragt, bekommt 1. B fragt, bekommt 2. Sauber, eindeutig, sortierbar. Und es macht den ganzen Sinn kaputt, weil es jetzt wieder zentral ist. Eine Maschine, auf die alle warten, eine Maschine, die alles mit sich reißt, wenn sie ausfällt.
Die Antwort, die funktioniert
Die ID aus Teilen bauen, die für sich genommen eindeutig sind: ein Zeitstempel, eine Knoten-ID und ein Zähler pro Knoten. Twitters Snowflake hat das mit 64 Bit gemacht (41 Bit Millisekunden, 10 Bit Maschinen-ID, 12 Bit Sequenz). Jeder Knoten erzeugt IDs allein, kein Ticket-Server, keine Offsets, und das Ergebnis sortiert trotzdem grob nach Zeit. Dieselbe Idee lebt in ULID weiter und in UUID Version 7, die einen Zeitstempel in die oberen Bits einer sonst zufälligen UUID legt, damit sie indexfreundlich bleibt.
Der Preis: Jeder Knoten muss seine eigene ID kennen und eine halbwegs richtige Uhr haben. Beides lösbar. Beides nicht umsonst.
Wann es wichtig wird
Mit einem einzigen Schreiber spielt nichts davon eine Rolle. Eine Datenbank, ein Zähler, kein Problem. Auto-Increment ist die richtige Antwort und bleibt es.
Der Wert liegt darin, zu wissen, wo die Klippe ist, bevor man darauf zuläuft. An dem Tag, an dem ein zweiter Schreiber auftaucht, ist die billigste Lösung weder Offsets noch ein Ticket-Server. Es ist, den ID-Typ zu wechseln, bevor die erste Zeile geschrieben ist. Denn ihn hinterher zu ändern, das ist der Teil, der wirklich wehtut.