J'ai généralement mis en œuvre la génération de numéros de séquence à l'aide de séquences de base de données dans le passé.
Par exemple, en utilisant le type SERIAL Postgres http://www.neilconway.org/docs/sequences/
Je suis cependant curieux de savoir comment générer des numéros de séquence pour les grands systèmes distribués où il n'y a pas de base de données. Quelqu'un a-t-il une expérience ou des suggestions d'une meilleure pratique pour obtenir la génération de numéros de séquence d'une manière thread-safe pour plusieurs clients?
Réponses:
OK, c'est une question très ancienne, que je vois pour la première fois maintenant.
Vous devrez faire la différence entre les numéros de séquence et les ID uniques qui sont (éventuellement) librement triables selon un critère spécifique (généralement l'heure de génération). Les vrais numéros de séquence impliquent la connaissance de ce que tous les autres travailleurs ont fait et, en tant que tels, nécessitent un état partagé. Il n'y a pas de moyen facile de le faire de manière distribuée et à grande échelle. Vous pouvez examiner des éléments tels que les diffusions réseau, les plages fenêtrées pour chaque travailleur et les tables de hachage distribuées pour les ID de travailleur uniques , mais c'est beaucoup de travail.
Les identifiants uniques sont une autre question, il existe plusieurs bonnes façons de générer des identifiants uniques de manière décentralisée:
a) Vous pouvez utiliser le service réseau Snowflake ID de Twitter . Snowflake est un:
b) Vous pouvez générer les ID uniques sur les clients eux-mêmes, en utilisant une approche dérivée de la manière dont les UUID et les ID de Snowflake sont créés. Il existe plusieurs options, mais quelque chose du genre:
Les 40 bits les plus significatifs: un horodatage; l'heure de génération de l'ID. (Nous utilisons les bits les plus significatifs pour l'horodatage afin de rendre les identifiants triables par heure de génération.)
Les 14 bits suivants: Un compteur par générateur, que chaque générateur incrémente de un pour chaque nouvel ID généré. Cela garantit que les ID générés au même moment (mêmes horodatages) ne se chevauchent pas.
Les 10 derniers bits: une valeur unique pour chaque générateur. En utilisant cela, nous n'avons pas besoin de faire de synchronisation entre les générateurs (ce qui est extrêmement difficile), car tous les générateurs produisent des ID qui ne se chevauchent pas à cause de cette valeur.
c) Vous pouvez générer les ID sur les clients, en utilisant simplement un horodatage et une valeur aléatoire. Cela évite d'avoir à connaître tous les générateurs et d'attribuer à chaque générateur une valeur unique. D'un autre côté, ces identifiants ne sont pas garantis d'être uniques au monde, ils sont très probablement uniques. (Pour entrer en collision, un ou plusieurs générateurs devraient créer la même valeur aléatoire exactement au même moment.) Quelque chose du genre:
d) La solution la plus simple consiste à utiliser des UUID / GUID .
la source
twitter/snowflake
n'est plus maintenuMaintenant, il y a plus d'options.
Bien que cette question soit "ancienne", je suis arrivée ici, donc je pense qu'il pourrait être utile de laisser les options que je connais (jusqu'à présent):
À votre santé
la source
Vous pouvez faire en sorte que chaque nœud ait un ID unique (que vous pouvez avoir de toute façon), puis l'ajouter au numéro de séquence.
Par exemple, le nœud 1 génère la séquence 001-00001 001-00002 001-00003 etc. et le nœud 5 génère 005-00001 005-00002
Unique :-)
Alternativement, si vous voulez une sorte de système centralisé, vous pouvez envisager de faire distribuer votre serveur de séquence par blocs. Cela réduit considérablement les frais généraux. Par exemple, au lieu de demander un nouvel identifiant au serveur central pour chaque identifiant qui doit être attribué, vous demandez des identifiants par blocs de 10 000 au serveur central, puis vous n'avez à faire une autre demande réseau que lorsque vous êtes à court.
la source
Cela peut être fait avec Redisson . Il implémente une version distribuée et évolutive de
AtomicLong
. Voici un exemple:la source
Si cela doit vraiment être globalement séquentiel, et pas simplement unique, alors j'envisagerais de créer un service unique et simple pour distribuer ces numéros.
Les systèmes distribués reposent sur de nombreux petits services en interaction, et pour ce type de tâche simple, avez-vous vraiment besoin ou bénéficieriez-vous vraiment d'une autre solution complexe et distribuée?
la source
Il existe quelques stratégies; mais aucun de ceux que je connais ne peut être vraiment distribué et donner une vraie séquence.
memcached
dispose d'un compteur atomique rapide, dans la grande majorité des cas, il est assez rapide pour l'ensemble de votre cluster.personnellement, je me pencherais sur les UUID, ou sur memcached si je veux avoir un espace principalement contigu.
la source
Pourquoi ne pas utiliser un générateur UUID (thread-safe)?
Je devrais probablement m'étendre là-dessus.
Les UUID sont garantis uniques au monde (si vous évitez ceux basés sur des nombres aléatoires, où l'unicité est tout simplement hautement probable).
Votre exigence "distribuée" est satisfaite, quel que soit le nombre de générateurs d'UUID que vous utilisez, par l'unicité globale de chaque UUID.
Votre exigence "thread-safe" peut être satisfaite en choisissant des générateurs UUID "thread-safe".
Votre exigence de "numéro de séquence" est supposée satisfaite par l'unicité globale garantie de chaque UUID.
Notez que de nombreuses implémentations de numéros de séquence de base de données (par exemple, Oracle) ne garantissent ni l'augmentation monotone, ni (même) l'augmentation des numéros de séquence (sur une base par «connexion»). Cela est dû au fait qu'un lot consécutif de numéros de séquence est alloué dans des blocs «mis en cache» par connexion. Cela garantit l'unicité globale et maintient une vitesse adéquate. Mais les numéros de séquence réellement alloués (au fil du temps) peuvent être mélangés lorsqu'ils sont alloués par plusieurs connexions!
la source
La génération d'ID distribuée peut être archivée avec Redis et Lua. L'implémentation disponible dans Github . Il produit des identifiants uniques distribués et triables en k.
la source
Je sais que c'est une vieille question, mais nous étions également confrontés au même besoin et n'avons pas été en mesure de trouver la solution qui répond à notre besoin. Notre exigence était d'obtenir une séquence unique (0,1,2,3 ... n) d'id et donc flocon de neige n'a pas aidé. Nous avons créé notre propre système pour générer les identifiants à l'aide de Redis. Redis est monothread, donc son mécanisme de liste / file d'attente nous donnerait toujours 1 pop à la fois.
Ce que nous faisons, c'est que nous créons un tampon d'identifiants. Au départ, la file d'attente aura de 0 à 20 identifiants prêts à être envoyés sur demande. Plusieurs clients peuvent demander un identifiant et redis affichera 1 identifiant à la fois, après chaque pop de gauche, nous insérons BUFFER + currentId à droite, ce qui maintient la liste de tampons en cours. Implémentation ici
la source
J'ai écrit un service simple qui peut générer des nombres longs de 64 bits semi-uniques non séquentiels. Il peut être déployé sur plusieurs machines à des fins de redondance et d'évolutivité. Il utilise ZeroMQ pour la messagerie. Pour plus d'informations sur son fonctionnement, consultez la page github: zUID
la source
En utilisant une base de données, vous pouvez atteindre plus de 1000 incréments par seconde avec un seul cœur. C'est assez simple. Vous pouvez utiliser sa propre base de données comme backend pour générer ce nombre (comme il devrait s'agir de son propre agrégat, en termes DDD).
J'ai eu ce qui semble être un problème similaire. J'avais plusieurs partitions et je voulais obtenir un compteur de décalage pour chacune. J'ai implémenté quelque chose comme ceci:
Ensuite, exécutez l'instruction suivante:
Si votre application vous le permet, vous pouvez allouer un bloc à la fois (c'était mon cas).
Si vous avez besoin d'un débit supplémentaire et que vous ne pouvez pas allouer de compensations à l'avance, vous pouvez implémenter votre propre service en utilisant Flink pour un traitement en temps réel. J'ai pu obtenir des incréments d'environ 100K par partition.
J'espère que ça aide!
la source
Le problème est similaire à: Dans le monde iscsi, où chaque lun / volume doit être identifiable de manière unique par les initiateurs exécutés côté client. La norme iscsi dit que les premiers bits doivent représenter les informations du fournisseur / fabricant de stockage et que le reste augmente de manière monotone.
De même, on peut utiliser les bits initiaux dans le système distribué de nœuds pour représenter le nodeID et le reste peut être monotone croissant.
la source
Une solution décente consiste à utiliser une génération basée sur le temps. Cela peut être fait avec le support d'une base de données distribuée.
la source