English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Résumé des méthodes pour générer un ID unique global pour le serveur de jeu en Java

Lors du développement de systèmes de serveurs système, pour s'adapter aux demandes de grande concurrence de données, nous devons souvent stocker les données de manière asynchrone, en particulier lors de la création de systèmes distribués. À ce moment-là, on ne peut pas attendre que la base de données retourne l'ID automatique après l'insertion, mais il faut générer un ID unique global avant l'insertion dans la base de données. En utilisant un ID unique global, dans les serveurs de jeu, un ID unique global peut être utilisé pour faciliter la fusion des serveurs à l'avenir, ce qui évitera les conflits de clés. De plus, en cas de croissance des affaires, il est possible de réaliser la division de la base de données et des tables, par exemple, les articles d'un utilisateur doivent être placés dans la même partition, et cette partition peut être déterminée par la valeur de la plage de l'ID utilisateur, par exemple, l'ID utilisateur est supérieur1000 est inférieur10Les utilisateurs de 0000 sont dans une partition. Actuellement, les types les plus courants sont les suivants :

1UUID natif de Java

UUID.randomUUID().toString(), peut être généré localement par le programme de service, la génération de l'ID ne dépend pas de l'implémentation de la base de données.

Avantages :

Génération locale de l'ID, sans appel à distance.

Unique et non répété globalement.

Une excellente capacité d'extension horizontale.

Inconvénients :

L'ID a128 bits, prend beaucoup d'espace, doit être stocké sous forme de chaîne, l'efficacité de l'index est extrêmement faible.

Les ID générés ne contiennent pas de Timestamp, ce qui ne garantit pas une augmentation de tendance, ce qui est mauvais pour dépendre lors de la division de la base de données et des tables.

2Basé sur la méthode incr de Redis

Redis est une opération mono-threadée, et l'incr garantit une opération d'incrémentation atomique. De plus, il est possible de définir une étape d'incrémentation.

Avantages :

Déploiement simple, utilisation facile, il suffit d'appeler une API Redis.

Plusieurs serveurs peuvent partager un service Redis, ce qui réduit le temps de développement des données partagées.

Redis peut être déployé en grappe pour résoudre le problème de panne unique.

Inconvénients :

Si le système est trop庞大,de nombreux services demandent simultanément à Redis, ce qui peut entraîner un verrouillage des performances.

3Solution venue de Flicker

Cette méthode de résolution est basée sur l'ID auto-incrementé de la base de données, elle utilise une base de données dédiée pour générer des ID. Les détails peuvent être trouvés sur Internet, personnellement, je trouve que c'est assez compliqué à utiliser, je ne le recommande pas.

4,Twitter Snowflake

Snowflake est un algorithme de génération d'ID distribué open-source de Twitter, dont l'idée principale est : générer un ID de type long, utiliser41bit en tant que millisecondes,10bit en tant que numéro de machine,12bit en tant que séquenceur millisecondaire. Théoriquement, cette algorithmique peut générer jusqu'à1000*(2^12) bits, ce qui représente environ400W de l'ID, ce qui suffit à répondre aux besoins des entreprises.

Selon l'idée de l'algorithme snowflake, nous pouvons générer notre propre ID unique global en fonction de notre scénario d'entreprise. Car la longueur du type long en Java est64bits, donc nous devons contrôler l'ID que nous concevons pour64bits.

Avantage : haute performance, faible délai ; application indépendante ; ordonné par temps.

Inconvénient : nécessite un développement et un déploiement indépendants.

Par exemple, l'ID que nous avons conçu contient les informations suivantes :

| 41 bits: Timestamp | 3 bits: Région | 10 bits: Numéro de machine | 10 bits: Numéro de séquence |

Code Java pour générer un ID unique:

/**
* Générateur d'ID personnalisé
* Règle de génération d'ID: L'ID atteint 64 bits
*
* | 41 bits: Timestamp (millisecondes) | 3 bits: Région (data center) | 10 bits: Numéro de machine | 10 bits: Numéro de séquence |
*/
public class GameUUID{
// Temps de référence
private long twepoch = 1288834974657L; //Thu, 04 Nov 2010 01:42:54 GMT
// Nombre de bits de l'identifiant de marqueur de région
private final static long regionIdBits = 3L;
// Nombre de bits de l'identifiant machine
private final static long workerIdBits = 10L;
// Nombre de bits de l'identifiant de séquence
private final static long sequenceBits = 10L;
// Valeur maximale de l'ID de marqueur de région
private final static long maxRegionId = -1L ^ (-1L << regionIdBits);
// Valeur maximale de l'ID machine
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// Valeur maximale de l'ID de séquence
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
// ID machine décalé à gauche10bit
private final static long workerIdShift = sequenceBits;
// décalage à gauche de l'ID commercial20 bit
private final static long regionIdShift = sequenceBits + workerIdBits;
// décalage à gauche du millième de seconde23bit
private final static long timestampLeftShift = sequenceBits + workerIdBits + regionIdBits;
private static long lastTimestamp = -1L;
private long sequence = 0L;
private final long workerId;
private final long regionId;
public GameUUID(long workerId, long regionId) {
// si il dépasse la plage, une exception est lancée
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("l'ID du worker ne peut pas être supérieur à %d ou inférieur à 0");
}
if (regionId > maxRegionId || regionId < 0) {
throw new IllegalArgumentException("l'ID du datacenter ne peut pas être supérieur à %d ou inférieur à 0");
}
this.workerId = workerId;
this.regionId = regionId;
}
public GameUUID(long workerId) {
// si il dépasse la plage, une exception est lancée
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("l'ID du worker ne peut pas être supérieur à %d ou inférieur à 0");
}
this.workerId = workerId;
this.regionId = 0;
}
public long generate() {
return this.nextId(false, 0);
}
/**
* le code généré réellement
*
* @param isPadding
* @param busId
* @return
*/
private synchronized long nextId(boolean isPadding, long busId) {
long timestamp = timeGen();
long paddingnum = regionId;
if (isPadding) {}}
paddingnum = busId;
}
if (timestamp < lastTimestamp) {
try {
lancer une nouvelle Exception("L'horloge a reculé. Refus de générer un id pour " + (lastTimestamp - timestamp) + " milliseconds");
} catch (Exception e) {
e.printStackTrace();
}
}
//Si le temps généré précédemment est le même que celui actuel, dans le même millième
if (lastTimestamp == timestamp) {
//L'incrémenter sequence, car sequence ne peut être que10bit, donc avec le masque sequenceMask, supprimer les bits de haut niveau
sequence = (sequence + 1) & sequenceMask;
//Vérifier si il y a un dépassement, c'est-à-dire que dans chaque millième, il y a plus de1024si1024lorsque, avec le masque sequenceMask, sequence vaut 0
if (sequence == 0) {
//Attendre en boucle jusqu'au prochain millième
timestamp = tailNextMillis(lastTimestamp);
}
} else {
// Si le temps généré précédemment n'est pas le même, réinitialiser sequence, c'est-à-dire à partir du prochain millième, le comptage de sequence commence à nouveau à zéro,
// Pour assurer une plus grande aléatoire pour la partie finale, configurer un nombre aléatoire en dernier.
sequence = new SecureRandom().nextInt(10;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (paddingnum << regionIdShift) | (workerId << workerIdShift) | sequence;
}
// Prévenir la génération de temps inférieur à celui précédent (à cause de problèmes de rebond NTP, etc.), maintenir la tendance de l'augmentation progressive.
private long tailNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
// Obtenir le timestamp actuel
protected long timeGen() {
return System.currentTimeMillis();
}
}

Points à noter lors de l'utilisation de cette méthode personnalisée :

Pour maintenir la tendance à la croissance, il faut éviter que certains serveurs aient une heure précoce et que d'autres aient une heure tardive, il faut contrôler le temps de tous les serveurs et éviter que le serveur de temps NTP ne rebondisse sur le serveur ; lors du passage à une milliseconde, le numéro de séquence est toujours réinitialisé à 0, ce qui entraîne un grand nombre de numéros de séquence de 0, ce qui rend le modulo des ID générés non uniforme, donc le numéro de séquence n'est pas réinitialisé à 0 à chaque fois, mais à un 0 à9aléatoire.

Les méthodes mentionnées précédemment peuvent être choisies selon nos besoins. Dans le développement de serveurs de jeu, choisissez selon le type de jeu, par exemple, pour les jeux mobiles, vous pouvez utiliser une méthode redis simple, simple et peu susceptible d'erreur, car la quantité de nouveaux ID générés par serveur pour ce type de jeu n'est pas grande, ce qui peut pleinement répondre aux besoins. Pour les serveurs de jeu mondiaux à grande échelle, ils sont principalement basés sur la distribution, donc vous pouvez utiliser la méthode snowflake, le code snowflake mentionné ci-dessus n'est qu'un exemple, vous devez le personnaliser en fonction de vos besoins, donc il y a une quantité supplémentaire de développement, et il faut noter les points mentionnés précédemment.

Les méthodes mentionnées ci-dessus sont un résumé des méthodes de génération d'ID uniques globaux pour les serveurs de jeu basées sur le code Java que l'éditeur présente aux utilisateurs. J'espère que cela vous sera utile. Si vous avez des questions, n'hésitez pas à laisser un message, l'éditeur répondra à temps. Merci également de votre soutien au site de tutoriels呐喊 !

Déclaration : Le contenu de cet article est hébergé sur Internet, propriété de ses auteurs respectifs, contribué et téléversé par les utilisateurs d'Internet, ce site ne détient pas de droits de propriété, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique connexe. Si vous trouvez du contenu suspect de violation de droits d'auteur, n'hésitez pas à envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.)

Vous pourriez aussi aimer