Ich habe allgemein die Generierung von Sequenznummern implementiert in der Vergangenheit von Sequenznummern mithilfe von Datenbanksequenzen .
Beispiel: Verwenden Sie Postgres SERIAL und geben Sie http://www.neilconway.org/docs/sequences/ ein.
Ich bin jedoch gespannt, wie Sequenznummern für große verteilte Systeme generiert werden können, für die es keine Datenbank gibt. Hat jemand Erfahrung oder Vorschläge für eine bewährte Methode, um eine Sequenznummerngenerierung auf threadsichere Weise für mehrere Clients zu erreichen?
Antworten:
OK, das ist eine sehr alte Frage, die ich jetzt zum ersten Mal sehe.
Sie müssen zwischen Sequenznummern und eindeutigen IDs unterscheiden , die (optional) nach bestimmten Kriterien (normalerweise Generierungszeit) lose sortierbar sind. Wahre Sequenznummern implizieren das Wissen darüber, was alle anderen Arbeiter getan haben, und erfordern als solche einen gemeinsamen Zustand. Es gibt keine einfache Möglichkeit, dies auf verteilte, hochskalierte Weise zu tun. Sie können sich beispielsweise mit Netzwerksendungen, Fensterbereichen für jeden Mitarbeiter und verteilten Hash-Tabellen für eindeutige Mitarbeiter-IDs befassen , aber es ist viel Arbeit.
Eindeutige IDs sind eine andere Sache. Es gibt verschiedene Möglichkeiten, eindeutige IDs dezentral zu generieren:
a) Sie können den Snowflake ID-Netzwerkdienst von Twitter verwenden . Schneeflocke ist ein:
b) Sie können die eindeutigen IDs auf den Clients selbst mithilfe eines Ansatzes generieren, der sich aus der Erstellung der UUIDs und der IDs von Snowflake ergibt . Es gibt mehrere Optionen, aber etwas in der Art von:
Die höchstwertigen 40 Bits: Ein Zeitstempel; die Generierungszeit der ID. (Wir verwenden die höchstwertigen Bits für den Zeitstempel, um IDs nach Generierungszeit sortierbar zu machen.)
Die nächsten 14 Bits: Ein Zähler pro Generator, den jeder Generator für jede neu generierte ID um eins erhöht. Dadurch wird sichergestellt, dass sich zum gleichen Zeitpunkt generierte IDs (gleiche Zeitstempel) nicht überlappen.
Die letzten 10 Bits: Ein eindeutiger Wert für jeden Generator. Auf diese Weise müssen wir keine Synchronisation zwischen Generatoren durchführen (was extrem schwierig ist), da alle Generatoren aufgrund dieses Werts nicht überlappende IDs erzeugen.
c) Sie können die IDs auf den Clients mit nur einem Zeitstempel und einem zufälligen Wert generieren . Dies vermeidet die Notwendigkeit, alle Generatoren zu kennen und jedem Generator einen eindeutigen Wert zuzuweisen. Auf der anderen Seite ist nicht garantiert , dass solche IDs global eindeutig sind, sondern nur sehr wahrscheinlich eindeutig. (Um zu kollidieren, müssten ein oder mehrere Generatoren genau zur gleichen Zeit denselben Zufallswert erstellen.) Etwas in der Art von:
d) Verwenden Sie für den einfachen Ausweg UUIDs / GUIDs .
quelle
twitter/snowflake
wird nicht mehr gewartetJetzt gibt es mehr Möglichkeiten.
Obwohl diese Frage "alt" ist, bin ich hierher gekommen, daher denke ich, dass es nützlich sein könnte, die mir bekannten Optionen (bis jetzt) zu belassen:
Prost
quelle
Sie können jedem Knoten eine eindeutige ID geben (die Sie möglicherweise ohnehin haben) und diese dann der Sequenznummer voranstellen.
Beispielsweise erzeugt Knoten 1 die Sequenz 001-00001 001-00002 001-00003 usw. und Knoten 5 erzeugt 005-00001 005-00002
Einzigartig :-)
Wenn Sie alternativ ein zentrales System wünschen, können Sie Ihren Sequenzserver auch in Blöcken ausgeben lassen. Dies reduziert den Overhead erheblich. Anstatt beispielsweise für jede zuzuweisende ID eine neue ID vom zentralen Server anzufordern, fordern Sie IDs in Blöcken von 10.000 vom zentralen Server an und müssen dann nur dann eine weitere Netzwerkanforderung ausführen, wenn Sie keine mehr haben.
quelle
Es kann mit Redisson gemacht werden . Es implementiert eine verteilte und skalierbare Version von
AtomicLong
. Hier ist ein Beispiel:quelle
Wenn es wirklich global sequentiell und nicht einfach eindeutig sein muss, würde ich in Betracht ziehen, einen einzigen, einfachen Dienst für die Ausgabe dieser Nummern zu erstellen.
Verteilte Systeme sind auf die Interaktion vieler kleiner Dienste angewiesen. Benötigen Sie für diese einfache Aufgabe wirklich eine andere komplexe verteilte Lösung oder würden Sie wirklich davon profitieren?
quelle
Es gibt einige Strategien; aber keiner, den ich kenne, kann wirklich verteilt werden und eine echte Sequenz geben.
memcached
hat einen schnellen Atomzähler, in den allermeisten Fällen ist er schnell genug für Ihren gesamten Cluster.persönlich würde ich mich an UUIDs lehnen oder mich merken, wenn ich einen größtenteils zusammenhängenden Raum haben möchte.
quelle
Warum nicht einen (thread-sicheren) UUID-Generator verwenden?
Ich sollte das wahrscheinlich erweitern.
UUIDs sind garantiert global eindeutig (wenn Sie solche vermeiden, die auf Zufallszahlen basieren, bei denen die Eindeutigkeit nur sehr wahrscheinlich ist).
Ihre "verteilte" Anforderung wird unabhängig von der Anzahl der von Ihnen verwendeten UUID-Generatoren durch die globale Eindeutigkeit jeder UUID erfüllt.
Ihre "Thread-sichere" Anforderung kann durch Auswahl von "Thread-sicheren" UUID-Generatoren erfüllt werden.
Es wird davon ausgegangen, dass Ihre Anforderung "Sequenznummer" durch die garantierte globale Eindeutigkeit jeder UUID erfüllt wird.
Beachten Sie, dass viele Implementierungen von Datenbanksequenznummern (z. B. Oracle) weder eine monoton ansteigende noch eine (sogar) ansteigende Sequenznummer (pro "Verbindung") garantieren. Dies liegt daran, dass ein fortlaufender Stapel von Sequenznummern pro Verbindung in "zwischengespeicherten" Blöcken zugewiesen wird. Dies garantiert globale Einzigartigkeit und sorgt für eine angemessene Geschwindigkeit. Die tatsächlich zugewiesenen Sequenznummern (im Laufe der Zeit) können jedoch durcheinander gebracht werden, wenn sie von mehreren Verbindungen zugewiesen werden!
quelle
Die verteilte ID-Generierung kann mit Redis und Lua archiviert werden. Die Implementierung in Github verfügbar . Es erzeugt verteilte und k-sortierbare eindeutige IDs.
quelle
Ich weiß, dass dies eine alte Frage ist, aber wir hatten auch das gleiche Bedürfnis und konnten keine Lösung finden, die unser Bedürfnis erfüllt. Unsere Anforderung war es, eine eindeutige Sequenz (0,1,2,3 ... n) von IDs zu erhalten, und daher half Schneeflocke nicht. Wir haben unser eigenes System erstellt, um die IDs mit Redis zu generieren. Redis ist Single-Threaded, daher würde sein Listen- / Warteschlangenmechanismus immer 1 Pop auf einmal geben.
Wir erstellen einen Puffer mit IDs. Zu Beginn hat die Warteschlange 0 bis 20 IDs, die auf Anfrage zum Versand bereit sind. Mehrere Clients können eine ID anfordern und redis wird jeweils 1 ID anzeigen. Nach jedem Pop von links fügen wir rechts BUFFER + currentId ein, wodurch die Pufferliste am Laufen bleibt. Implementierung hier
quelle
Ich habe einen einfachen Dienst geschrieben, der halb eindeutige, nicht sequentielle 64-Bit-lange Zahlen erzeugen kann. Es kann aus Redundanz- und Skalierbarkeitsgründen auf mehreren Computern bereitgestellt werden. Es verwendet ZeroMQ für Messaging. Weitere Informationen zur Funktionsweise finden Sie auf der Github-Seite: zUID
quelle
Mit einer Datenbank können Sie mit einem einzigen Kern mehr als 1.000 Inkremente pro Sekunde erreichen. Es ist ziemlich einfach. Sie können eine eigene Datenbank als Backend verwenden, um diese Nummer zu generieren (da es sich in DDD-Begriffen um ein eigenes Aggregat handeln sollte).
Ich hatte ein ähnliches Problem. Ich hatte mehrere Partitionen und wollte für jede einen Versatzzähler bekommen. Ich habe so etwas implementiert:
Führen Sie dann die folgende Anweisung aus:
Wenn Ihre Anwendung es Ihnen erlaubt, können Sie einen Block sofort zuweisen (das war mein Fall).
Wenn Sie weiteren Durchsatz benötigen und keine Offsets im Voraus zuweisen können, können Sie Ihren eigenen Service mithilfe von Flink für die Echtzeitverarbeitung implementieren. Ich konnte ungefähr 100.000 Inkremente pro Partition erzielen.
Ich hoffe es hilft!
quelle
Das Problem ist ähnlich wie in der iscsi-Welt, in der jedes Luns / Volume von den auf der Clientseite ausgeführten Initiatoren eindeutig identifiziert werden muss. Der iscsi-Standard besagt, dass die ersten Bits die Informationen des Speicheranbieters / Herstellers darstellen müssen und der Rest monoton ansteigt.
In ähnlicher Weise kann man die Anfangsbits in dem verteilten Knotensystem verwenden, um die Knoten-ID darzustellen, und der Rest kann monoton ansteigen.
quelle
Eine vernünftige Lösung besteht darin, eine zeitbasierte Generation zu verwenden. Dies kann mit der Unterstützung einer verteilten Datenbank erfolgen.
quelle