Table des matières
Solutions d'identification distribuées couramment utilisées
UUID
Snowflake
Le code Java de l'algorithme Snowflake :
Leaf
Le code Java de l'algorithme Leaf :
Générer en fonction de l'ID d'incrémentation automatique de la base de données
Générer en fonction de l'UUID
Générer en fonction de Redis
Générer en fonction de ZooKeeper
Maison base de données Redis Quelles sont les solutions pour l'ID distribué Redis ?

Quelles sont les solutions pour l'ID distribué Redis ?

Jun 03, 2023 am 10:14 AM
redis id

    Solutions d'identification distribuées couramment utilisées

    Dans un système distribué, il est très important de générer un identifiant globalement unique, car dans un système distribué, plusieurs nœuds générant des identifiants en même temps peuvent provoquer des conflits d'identification.

    Ce qui suit présente plusieurs solutions d'identification distribuées couramment utilisées.

    UUID

    UUID (Universally Unique Identifier) ​​​​​​est un identifiant composé de 128 chiffres, qui peut garantir une unicité globale car son algorithme de génération est basé sur des facteurs tels que l'horodatage et l'ID du nœud. L'UUID peut être généré à l'aide de la classe UUID fournie avec Java, comme indiqué ci-dessous :

    javaCopy code
    import java.util.UUID;
    public class UuidGenerator {
        public static void main(String[] args) {
            UUID uuid = UUID.randomUUID();
            System.out.println(uuid.toString());
        }
    }
    Copier après la connexion

    La classe UUID fournie avec Java est très simple et facile à utiliser, et ne nécessite aucune configuration ni gestion supplémentaire. C'est son avantage. En raison de sa longueur (128 bits), l'UUID ne convient pas comme clé primaire pour les tables de bases de données et est difficile à trier et à indexer.

    Snowflake

    Snowflake est un algorithme de génération d'identifiant distribué open source par Twitter. Il peut générer un identifiant unique de 64 bits, qui contient des informations telles que l'horodatage, l'identifiant du centre de données et l'identifiant de la machine. Le code Java de l'algorithme Snowflake est le suivant :

    Le code Java de l'algorithme Snowflake :
    javaCopy code
    public class SnowflakeGenerator {
        private final static long START_STMP = 1480166465631L;
        private final static long SEQUENCE_BIT = 12;
        private final static long MACHINE_BIT = 5;
        private final static long DATACENTER_BIT = 5;
        private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
        private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
        private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
        private final static long MACHINE_LEFT = SEQUENCE_BIT;
        private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
        private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
        private long datacenterId;
        private long machineId;
        private long sequence = 0L;
        private long lastStmp = -1L;
        public SnowflakeGenerator(long datacenterId, long machineId) {
            if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
                throw new IllegalArgumentException("datacenterId can&#39;t be greater than MAX_DATACENTER_NUM or less than 0");
            }
            if (machineId > MAX_MACHINE_NUM || machineId < 0) {
                throw new IllegalArgumentException("machineId can&#39;t be greater than MAX_MACHINE_NUM or less than 0");
            }
            this.datacenterId = datacenterId;
            this.machineId = machineId;
        }
        public synchronized long nextId() {
            long currStmp = getNewstmp();
            if (currStmp < lastStmp) {
                throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
            }
            if (currStmp == lastStmp) {
                sequence = (sequence + 1) & MAX_SEQUENCE;
                if (sequence == 0L) {
                    currStmp = getNextMill();
                }
            } else {
                sequence = 0L;
            }
            lastStmp = currStmp;
            return (currStmp - START_STMP) << TIMESTMP_LEFT
                    | datacenterId << DATACENTER_LEFT
                    | machineId << MACHINE_LEFT
                    | sequence;
        }
        private long getNextMill() {
            long mill = getNewstmp();
            while (mill <= lastStmp) {
                mill = getNewstmp();
            }
            return mill;
        }
        private long getNewstmp() {
            return System.currentTimeMillis();
        }
    }
    Copier après la connexion

    L'avantage de l'algorithme Snowflake est qu'il a de hautes performances dans la génération d'identifiants et que la longueur de l'identifiant est courte (64 bits) .Il peut être utilisé comme clé primaire de la table de base de données et est pratique pour le tri et l'indexation. Cependant, il convient de noter que si le nombre de nœuds dans le cluster dépasse le nombre de chiffres occupés par l'ID de la machine, ou si le cluster est très grand et que le nombre de chiffres d'horodatage n'est pas suffisant, alors d'autres algorithmes de génération d'ID distribués doivent être considéré.

    Leaf

    Leaf est un algorithme de génération d'identifiant distribué open source par Meituan Dianping. Il peut générer un identifiant 64 bits unique au monde. Le code Java de l'algorithme Leaf est le suivant :

    Le code Java de l'algorithme Leaf :
    javaCopy code
    public class LeafGenerator {
        private static final Logger logger = LoggerFactory.getLogger(LeafGenerator.class);
        private static final String WORKER_ID_KEY = "leaf.worker.id";
        private static final String PORT_KEY = "leaf.port";
        private static final int DEFAULT_PORT = 8080;
        private static final int DEFAULT_WORKER_ID = 0;
        private static final int WORKER_ID_BITS = 10;
        private static final int SEQUENCE_BITS = 12;
        private static final int MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;
        private static final int MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1;
        private static final long EPOCH = 1514736000000L;
        private final SnowflakeIdWorker idWorker;
        public LeafGenerator() {
            int workerId = SystemPropertyUtil.getInt(WORKER_ID_KEY, DEFAULT_WORKER_ID);
            int port = SystemPropertyUtil.getInt(PORT_KEY, DEFAULT_PORT);
            this.idWorker = new SnowflakeIdWorker(workerId, port);
            logger.info("Initialized LeafGenerator with workerId={}, port={}", workerId, port);
        }
        public long nextId() {
            return idWorker.nextId();
        }
        private static class SnowflakeIdWorker {
            private final long workerId;
            private final long port;
            private long sequence = 0L;
            private long lastTimestamp = -1L;
            SnowflakeIdWorker(long workerId, long port) {
                if (workerId < 0 || workerId > MAX_WORKER_ID) {
                    throw new IllegalArgumentException(String.format("workerId must be between %d and %d", 0, MAX_WORKER_ID));
                }
                this.workerId = workerId;
                this.port = port;
            }
            synchronized long nextId() {
                long timestamp = System.currentTimeMillis();
                if (timestamp < lastTimestamp) {
                    throw new RuntimeException("Clock moved backwards. Refusing to generate id");
                }
                if (timestamp == lastTimestamp) {
                    sequence = (sequence + 1) & MAX_SEQUENCE;
                    if (sequence == 0L) {
                        timestamp = tilNextMillis(lastTimestamp);
                    }
                } else {
                    sequence = 0L;
                }
                lastTimestamp = timestamp;
                return ((timestamp - EPOCH) << (WORKER_ID_BITS + SEQUENCE_BITS))
                        | (workerId << SEQUENCE_BITS)
                        | sequence;
            }
            private long tilNextMillis(long lastTimestamp) {
                long timestamp = System.currentTimeMillis();
                while (timestamp <= lastTimestamp) {
                    timestamp = System.currentTimeMillis();
                }
                return timestamp;
            }
        }
    }
    Copier après la connexion

    Bien que l'algorithme Leaf génère des identifiants légèrement plus lents que l'algorithme Snowflake, il peut prendre en charge plus de nœuds de travail. L'ID généré par l'algorithme Leaf se compose de trois parties, à savoir l'horodatage, l'ID du travailleur et le numéro de série. L'horodatage occupe 42 bits, l'ID du travailleur occupe 10 bits et le numéro de série occupe 12 bits, pour un total de 64 bits.

    Les algorithmes ci-dessus sont des algorithmes de génération d'identifiants distribués courants. Bien sûr, il existe d'autres solutions, telles que : MongoDB ID, UUID, Twitter Snowflake, etc. Différentes solutions conviennent à différents scénarios commerciaux, et les détails de mise en œuvre et les performances spécifiques sont également différents. Vous devez choisir la solution appropriée en fonction de la situation réelle.

    En plus de l'algorithme de génération d'ID distribué présenté ci-dessus, de nouvelles solutions de génération d'ID distribuées émergent également, telles que l'algorithme de génération d'ID distribué de Flicker, qui utilise une idée similaire à Snowflake, mais utilise un nombre de bits différent pour la méthode d'allocation. est plus flexible que Snowflake et le nombre de bits occupés par chaque partie peut être ajusté dynamiquement selon les besoins. En outre, Facebook a également lancé la solution ID Generation Service (IGS), qui sépare la génération d'identifiants et le stockage, offrant une solution plus flexible et évolutive, mais nécessite une conception et une mise en œuvre d'architecture plus complexes.

    Plusieurs solutions de génération d'ID distribuées peuvent être conçues pour différents besoins commerciaux. Voici quelques-unes de mes suggestions personnelles :

    • Génération basée sur l'ID d'auto-incrémentation de la base de données : l'utilisation de l'ID d'auto-incrémentation de la base de données comme identifiant globalement unique peut garantir l'unicité de l'ID et est simple à mettre en œuvre, mais cela peut être possible lorsque le degré de concurrence est élevé. Peut entraîner des goulots d'étranglement en matière de performances. Par conséquent, il n’est pas recommandé de l’utiliser dans des scénarios à forte concurrence.

    • Génération basée sur l'UUID : l'utilisation de l'UUID comme identifiant unique au monde peut bien garantir l'unicité de l'identifiant, mais la longueur de l'identifiant est longue (128 bits), ce qui n'est pas pratique pour le stockage et la transmission, et la probabilité de duplication Les identifiants sont très petits. Pas 0. Il est recommandé que lors de l'utilisation d'un système distribué, la longueur de l'ID ainsi que le coût du stockage et de la transmission soient pris en compte.

    • Généré sur la base de Redis : grâce au fonctionnement atomique de Redis, l'unicité de l'ID peut être garantie et la vitesse de génération de l'ID est très rapide, ce qui peut être appliqué à des scénarios de concurrence élevée. Il convient de noter que si Redis plante ou fonctionne mal, cela peut affecter l'efficacité et la disponibilité de la génération d'ID.

    • Généré sur la base de ZooKeeper : l'utilisation du générateur de numéro de série de ZooKeeper peut garantir l'unicité de l'ID, et la mise en œuvre est relativement simple, mais elle nécessite l'introduction de dépendances et de ressources supplémentaires, et il peut y avoir des goulots d'étranglement en termes de performances.

    Pour choisir une solution de génération d'ID distribuée adaptée à votre scénario commercial, vous devez prendre en compte de manière globale plusieurs facteurs tels que l'unicité de l'ID, la vitesse de génération, la longueur, le coût de stockage, l'évolutivité et la disponibilité. La mise en œuvre de différentes solutions nécessite de considérer des compromis et des choix dans des situations réelles, car les détails de leur mise en œuvre et leurs performances sont également différents.

    La démo détaillée du code de chaque solution est donnée ci-dessous :

    Générer en fonction de l'ID d'incrémentation automatique de la base de données

    javaCopy code
    public class IdGenerator {
        private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test";
        private static final String JDBC_USER = "root";
        private static final String JDBC_PASSWORD = "password";
        public long generateId() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
                pstmt = conn.prepareStatement("INSERT INTO id_generator (stub) VALUES (null)", Statement.RETURN_GENERATED_KEYS);
                pstmt.executeUpdate();
                rs = pstmt.getGeneratedKeys();
                if (rs.next()) {
                    return rs.getLong(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (pstmt != null) {
                        pstmt.close();
                    }
                    if (conn != null) {
                        conn.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return 0L;
        }
    }
    Copier après la connexion

    Générer en fonction de l'UUID

    javaCopy code
    import java.util.UUID;
    public class IdGenerator {
        public String generateId() {
            return UUID.randomUUID().toString().replace("-", "");
        }
    }
    Copier après la connexion

    Générer en fonction de Redis

    javaCopy code
    import redis.clients.jedis.Jedis;
    public class IdGenerator {
        private static final String REDIS_HOST = "localhost";
        private static final int REDIS_PORT = 6379;
        private static final String REDIS_PASSWORD = "password";
        private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;
        private static final String ID_GENERATOR_KEY = "id_generator";
        public long generateId() {
            Jedis jedis = null;
            try {
                jedis = new Jedis(REDIS_HOST, REDIS_PORT);
                jedis.auth(REDIS_PASSWORD);
                long id = jedis.incr(ID_GENERATOR_KEY);
                jedis.expire(ID_GENERATOR_KEY, ID_GENERATOR_EXPIRE_SECONDS);
                return id;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
            return 0L;
        }
    }
    Copier après la connexion

    Générer en fonction de ZooKeeper

    javaCopy code
    import java.util.concurrent.CountDownLatch;
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooDefs.Ids;
    import org.apache.zookeeper.ZooKeeper;
    public class IdGenerator implements Watcher {
        private static final String ZK_HOST = "localhost";
        private static final int ZK_PORT = 2181;
        private static final int SESSION_TIMEOUT = 5000;
        private static final String ID_GENERATOR_NODE = "/id_generator";
        private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;
        private long workerId = 0;
        public IdGenerator() {
            try {
                ZooKeeper zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, this);
                CountDownLatch latch = new CountDownLatch(1);
                latch.await();
                if (zk.exists(ID_GENERATOR_NODE, false) == null) {
                    zk.create(ID_GENERATOR_NODE, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                }
                workerId = zk.getChildren(ID_GENERATOR_NODE, false).size();
                zk.create(ID_GENERATOR_NODE + "/worker_" + workerId, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public long generateId() {
            ZooKeeper zk = null;
            try {
                zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, null);
                CountDownLatch latch = new CountDownLatch(1);
                latch.await();
                zk.create(ID_GENERATOR_NODE + "/id_", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, (rc, path, ctx, name) -> {}, null);
                byte[] data = zk.getData(ID_GENERATOR_NODE + "/worker_" + workerId, false, null);
                long id = Long.parseLong(new String(data)) * 10000 + zk.getChildren(ID_GENERATOR_NODE, false).size();
                return id;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (zk != null) {
                    try {
                        zk.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return 0L;
        }
        @Override
        public void process(WatchedEvent event) {
            if (event.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("Connected to ZooKeeper");
                CountDownLatch latch = new CountDownLatch(1);
                latch.countDown();
            }
        }
    }
    Copier après la connexion

    Notez que ZooKeeper's temporaire est utilisé ici pour coordonner chaque nœud de travail. Si un nœud de travail meurt, son nœud temporaire sera également supprimé. Cela garantit que l'ID obtenu par chaque nœud de travail est unique.

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

    Outils d'IA chauds

    Undresser.AI Undress

    Undresser.AI Undress

    Application basée sur l'IA pour créer des photos de nu réalistes

    AI Clothes Remover

    AI Clothes Remover

    Outil d'IA en ligne pour supprimer les vêtements des photos.

    Undress AI Tool

    Undress AI Tool

    Images de déshabillage gratuites

    Clothoff.io

    Clothoff.io

    Dissolvant de vêtements AI

    AI Hentai Generator

    AI Hentai Generator

    Générez AI Hentai gratuitement.

    Article chaud

    R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
    4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Meilleurs paramètres graphiques
    4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Comment réparer l'audio si vous n'entendez personne
    4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25: Comment déverrouiller tout dans Myrise
    1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

    Outils chauds

    Bloc-notes++7.3.1

    Bloc-notes++7.3.1

    Éditeur de code facile à utiliser et gratuit

    SublimeText3 version chinoise

    SublimeText3 version chinoise

    Version chinoise, très simple à utiliser

    Envoyer Studio 13.0.1

    Envoyer Studio 13.0.1

    Puissant environnement de développement intégré PHP

    Dreamweaver CS6

    Dreamweaver CS6

    Outils de développement Web visuel

    SublimeText3 version Mac

    SublimeText3 version Mac

    Logiciel d'édition de code au niveau de Dieu (SublimeText3)

    Comment construire le mode Cluster Redis Comment construire le mode Cluster Redis Apr 10, 2025 pm 10:15 PM

    Le mode Redis Cluster déploie les instances Redis sur plusieurs serveurs grâce à la rupture, à l'amélioration de l'évolutivité et de la disponibilité. Les étapes de construction sont les suivantes: Créez des instances de redis étranges avec différents ports; Créer 3 instances Sentinel, Moniteur Redis Instances et basculement; Configurer les fichiers de configuration Sentinel, ajouter des informations d'instance Redis de surveillance et des paramètres de basculement; Configurer les fichiers de configuration d'instance Redis, activer le mode de cluster et spécifier le chemin du fichier d'informations de cluster; Créer un fichier nœuds.conf, contenant des informations de chaque instance redis; Démarrez le cluster, exécutez la commande CREATE pour créer un cluster et spécifiez le nombre de répliques; Connectez-vous au cluster pour exécuter la commande d'informations de cluster pour vérifier l'état du cluster; faire

    Comment utiliser la commande redis Comment utiliser la commande redis Apr 10, 2025 pm 08:45 PM

    L'utilisation de la directive Redis nécessite les étapes suivantes: Ouvrez le client Redis. Entrez la commande (Verbe Key Value). Fournit les paramètres requis (varie de l'instruction à l'instruction). Appuyez sur Entrée pour exécuter la commande. Redis renvoie une réponse indiquant le résultat de l'opération (généralement OK ou -err).

    Comment afficher toutes les clés dans Redis Comment afficher toutes les clés dans Redis Apr 10, 2025 pm 07:15 PM

    Pour afficher toutes les touches dans Redis, il existe trois façons: utilisez la commande Keys pour retourner toutes les clés qui correspondent au modèle spécifié; Utilisez la commande SCAN pour itérer les touches et renvoyez un ensemble de clés; Utilisez la commande info pour obtenir le nombre total de clés.

    Comment utiliser un seul fileté redis Comment utiliser un seul fileté redis Apr 10, 2025 pm 07:12 PM

    Redis utilise une architecture filetée unique pour fournir des performances élevées, une simplicité et une cohérence. Il utilise le multiplexage d'E / S, les boucles d'événements, les E / S non bloquantes et la mémoire partagée pour améliorer la concurrence, mais avec des limites de limitations de concurrence, un point d'échec unique et inadapté aux charges de travail à forte intensité d'écriture.

    Comment démarrer le serveur avec redis Comment démarrer le serveur avec redis Apr 10, 2025 pm 08:12 PM

    Les étapes pour démarrer un serveur Redis incluent: Installez Redis en fonction du système d'exploitation. Démarrez le service Redis via Redis-Server (Linux / MacOS) ou Redis-Server.exe (Windows). Utilisez la commande redis-Cli Ping (Linux / MacOS) ou redis-Cli.exe Ping (Windows) pour vérifier l'état du service. Utilisez un client redis, tel que redis-cli, python ou node.js pour accéder au serveur.

    Comment utiliser Redis Lock Comment utiliser Redis Lock Apr 10, 2025 pm 08:39 PM

    L'utilisation des opérations Redis pour verrouiller nécessite l'obtention du verrouillage via la commande setnx, puis en utilisant la commande Expire pour définir le temps d'expiration. Les étapes spécifiques sont les suivantes: (1) Utilisez la commande setnx pour essayer de définir une paire de valeurs de clé; (2) Utilisez la commande Expire pour définir le temps d'expiration du verrou; (3) Utilisez la commande del pour supprimer le verrouillage lorsque le verrouillage n'est plus nécessaire.

    Comment effacer les données redis Comment effacer les données redis Apr 10, 2025 pm 10:06 PM

    Comment effacer les données Redis: utilisez la commande flushall pour effacer toutes les valeurs de clé. Utilisez la commande flushdb pour effacer la valeur clé de la base de données actuellement sélectionnée. Utilisez SELECT pour commuter les bases de données, puis utilisez FlushDB pour effacer plusieurs bases de données. Utilisez la commande del pour supprimer une clé spécifique. Utilisez l'outil Redis-CLI pour effacer les données.

    Que faire si redis-server ne peut être trouvé Que faire si redis-server ne peut être trouvé Apr 10, 2025 pm 06:54 PM

    Étapes pour résoudre le problème que Redis-Server ne peut pas trouver: Vérifiez l'installation pour vous assurer que Redis est installé correctement; Définissez les variables d'environnement redis_host et redis_port; Démarrer le serveur Redis Redis-Server; Vérifiez si le serveur exécute Redis-Cli Ping.

    See all articles