DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»UUID : clés uniques sans coordination – DZone
    Uncategorized

    UUID : clés uniques sans coordination – DZone

    février 10, 2023
    UUID : clés uniques sans coordination - DZone
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Construisons une application IoT avec des capteurs météorologiques déployés dans le monde entier. Les capteurs collecteront des données et nous stockerons les données avec les identifiants des capteurs. Nous exécuterons plusieurs instances de base de données et les capteurs écriront dans la base de données géographiquement la plus proche. Toutes les bases de données échangeront régulièrement des données, de sorte que toutes les bases de données auront éventuellement des données de tous les capteurs.

    Nous avons besoin que chaque capteur ait un identifiant unique au monde. Comment pouvons-nous y parvenir ? Par exemple, nous pourrions exécuter un service attribuant des ID de capteur dans le cadre de la procédure d’installation du capteur. Cela signifierait une complexité architecturale supplémentaire, mais c’est faisable. Les identifiants de capteur sont immuables, de sorte que chaque capteur n’a besoin de parler au service d’identification qu’une seule fois, juste après l’installation. Ce n’est pas si mal.

    Que se passe-t-il si nous devons stocker un identifiant unique pour chaque lecture de données ? Utiliser le service d’identification centralisé chaque fois que nous avons besoin de stocker des données n’est pas une option. Cela solliciterait trop le service d’identification, et lorsque le service d’identification n’est pas disponible, aucun capteur ne pourrait écrire de données.

    Quelles sont les solutions possibles ?

    Dans le cas le plus simple, chaque capteur pourrait parler au service d’identification à distance et réserver un bloc d’identifications qu’il pourrait ensuite attribuer localement sans autre coordination. Lorsqu’il épuise le bloc, il en demande un nouveau au service d’identification. Cette stratégie réduirait la charge sur le service d’identification et les capteurs pourraient fonctionner même lorsque le service d’identification est temporairement indisponible. Nous pourrions également générer des ID de lecture locaux et les préfixer avec notre ID de capteur immuable unique. Nous pourrions également être intelligents et utiliser des algorithmes d’identification fantaisistes comme FlakeIDs.

    Les stratégies mentionnées visent à minimiser le besoin de coordination tout en garantissant que les identifiants sont uniques au monde. L’objectif est de générer des identifiants uniques sans aucune coordination. C’est ce que nous appelons des identifiants uniques sans coordination.

    UUID entre en scène

    Lancez une pièce 128 fois et notez 1 pour chaque face et 0 pour chaque face. Cela vous donne une séquence de 128 1 et 0, ou 128 bits aléatoires. C’est un espace suffisamment grand pour que la probabilité de générer deux fois la même séquence soit si extrêmement faible que vous pouvez l’exclure à des fins pratiques.

    Quel est le lien avec les UUID ? Si vous avez déjà vu un UUID, vous savez qu’il ressemble à ceci : 420cd09a-4d56-4749-acc2-40b2e8aa8c42. Ce format n’est qu’une représentation textuelle de 128 bits. Comment ça marche? La chaîne UUID comporte 36 caractères au total. Si nous supprimons les 4 tirets, qui sont là juste pour le rendre un peu plus lisible par l’homme, il nous reste 32 chiffres hexadécimaux : 0-F. Chaque chiffre représente 4 bits et 32 ​​* 4 bits = 128 bits. Les UUID sont donc des valeurs de 128 bits. Nous les représentons souvent sous forme de chaînes, mais ce n’est qu’une commodité.

    UUID a été explicitement conçu pour être unique et généré sans coordination. Quand on a un bon générateur aléatoire, 128 bits aléatoires suffisent pour pratiquement garantir l’unicité. Dans le même temps, 128 bits ne sont pas trop, donc les UUID n’occupent pas trop d’espace lorsqu’ils sont stockés.

    Versions UUID

    Il existe plusieurs versions d’UUID. Les versions 1 à 5 sont définies dans la RFC 4122 et sont les plus largement utilisées. Les versions 6 à 8 sont actuellement à l’état de projet et pourraient être approuvées à l’avenir. Voyons brièvement les différentes versions.

    Version 1

    La version 1 est générée en utilisant une adresse MAC et une heure comme entrées. L’adresse MAC est utilisée pour garantir l’unicité sur plusieurs machines. Le temps garantit l’unicité entre plusieurs processus sur la même machine. L’utilisation du MAC signifie que les UUID générés peuvent être suivis jusqu’à une machine spécifique. Cela peut être utile occasionnellement, mais cela peut ne pas être souhaitable dans d’autres cas, car une adresse MAC peut être considérée comme une information privée.

    Chose intéressante, la partie temporelle n’est pas basée sur l’époque Unix habituelle, mais elle utilise un décompte d’intervalles de 100 nanosecondes depuis 00:000:00.00 le 15 octobre 1582. Quelle est la particularité d’octobre 1582 ? C’est la réforme du calendrier grégorien. Voir la version 7 pour un UUID avec une époque Unix standard.

    Version 2

    La version 2 est similaire à la version 1 mais ajoute un ID de domaine local à l’UUID. Il n’est pas largement utilisé.

    Versions 3 et 5

    Ces versions utilisent une fonction de hachage pour générer l’UUID. La fonction de hachage est ensemencée avec un UUID d’espace de noms et un nom. L’UUID de l’espace de noms est utilisé pour garantir l’unicité entre plusieurs espaces de noms. Le nom est utilisé pour garantir l’unicité dans un espace de noms.

    La version 3 utilise MD5 comme fonction de hachage, tandis que la version 5 utilise SHA-1. SHA-1 génère 160 bits, donc le résumé est tronqué à 128 bits.

    Variante 4

    La version 4 UUID est probablement la plus populaire. Il s’appuie uniquement sur un générateur aléatoire pour générer des UUID, similaires à l’exemple de pile ou face ci-dessus. Cela signifie que la qualité du générateur aléatoire est critique.

    Variante 6

    La version 6 est similaire à la version 1 mais a un ordre différent des octets. Il encode le temps du plus significatif au moins significatif. Cela permet de trier correctement les UUID par heure lorsque vous triez uniquement les octets représentant les UUID.

    Variante 7

    La version 7 utilise un horodatage de 48 bits et des données aléatoires. Contrairement aux versions 1, 2 ou 6, il utilise une époque Unix standard en millisecondes. Il utilise également un générateur aléatoire au lieu d’une adresse MAC.

    Variante 8

    La version 8 est destinée à être utilisée à des fins expérimentales et privées.

    Considérations de sécurité

    Les UUID sont conçus pour être uniques, mais ils ne sont pas conçus pour être secrets. Quelle est la différence? Si vous générez un UUID, vous pouvez supposer qu’il est différent de tout autre UUID généré avant ou après, mais vous ne devez pas le traiter comme un mot de passe ou un identifiant de session secret. Voici ce que dit la RFC 4122 à ce sujet :

    Ne présumez pas que les UUID sont difficiles à deviner ; ils ne doivent pas être utilisés comme capacités de sécurité (identifiants dont la simple possession autorise l’accès), par exemple. Une source prévisible de nombres aléatoires exacerbera la situation.

    UUID dans QuestDB

    Les UUID sont des identifiants synthétiques populaires car ils peuvent être générés sans aucune coordination et n’utilisent pas trop d’espace. Les utilisateurs de QuestDB stockent souvent des UUID, mais jusqu’à récemment, QuestDB n’avait pas de support de première classe. La plupart des utilisateurs ont stocké les UUID dans une colonne de chaîne. Cela a du sens car, comme nous l’avons vu ci-dessus, les UUID ont une représentation textuelle canonique.

    Stocker les UUID dans une colonne de chaîne est possible, mais c’est inefficace. Faisons quelques calculs : nous savons déjà que chaque UUID a 128 bits, soit 16 octets. La représentation textuelle canonique de l’UUID comporte 36 caractères. QuestDB utilise le codage UTF-16 pour les chaînes, de sorte que chaque caractère ASCII utilise 2 octets. Il y a aussi un coût fixe de 4 octets par chaîne stockée. Il faut donc 36 * 2 + 4 = 76 octets pour stocker un seul UUID qui ne contient que 16 octets d’informations ! Il ne s’agit pas seulement de gaspiller de l’espace disque. QuestDB doit lire ces octets lors de l’évaluation d’un prédicat SQL, de la jointure de tables ou du calcul d’une agrégation. Ainsi, le stockage des UUID sous forme de chaînes ralentit également vos requêtes !

    C’est pourquoi QuestDB 6.7 a implémenté UUID comme type de données de première classe. Cela permet aux applications utilisateur de déclarer une colonne comme UUID, puis chaque UUID stocké n’utilisera que 16 octets. Grâce à cela, les requêtes SQL seront plus rapides.

    Temps de démonstration

    La démo crée des tables occupant un peu moins de 100 Go d’espace disque. Assurez-vous d’avoir suffisamment d’espace disque disponible. Vous devrez peut-être également augmenter le délai d’expiration de la requête via le query.timeout.sec propriété. Voir Configuration pour plus de détails. Alternativement, vous pouvez changer le long_sequence() fonction pour créer un plus petit nombre de lignes.

    Créons une table avec une seule colonne de chaîne et remplissons-la avec 1 milliard d’UUID aléatoires. La colonne est définie en tant que type de chaîne, de sorte que les UUID seront stockés sous forme de chaînes.

    CREATE TABLE tab_s (s string); 
    INSERT INTO tab_s SELECT rnd_uuid4() FROM long_sequence(1000000000);

    Essayons de l’interroger :

    SELECT * FROM tab_s WHERE s="ab632aba-be36-43e5-a4a0-4895e9cd3f0d";

    Cela prend environ 2,2 secondes. Ce n’est pas terrible étant donné qu’il s’agit d’un balayage de table complet sur un milliard de chaînes, mais nous pouvons faire mieux ! Combien mieux? Voyons. Créez une table avec une colonne UUID :

    CREATE TABLE tab_u (u uuid);

    Remplissez-le avec les valeurs UUID de la première table :

    INSERT INTO tab_u SELECT * FROM tab_s;

    La table nouvellement créée a les mêmes valeurs que la première table, mais la colonne est définie comme UUID au lieu de chaîne, ce qui élimine le gaspillage dont nous avons parlé ci-dessus. Voyons comment le prédicat fonctionne maintenant :

    SELECT * FROM tab_u WHERE u = 'ab632aba-be36-43e5-a4a0-4895e9cd3f0d';

    Cette requête prend environ 380 ms sur ma boîte de test. C’est presque 6 fois mieux que les 2,2 secondes d’origine ! La vitesse est la clé de toute analyse en temps réel, c’est donc certainement important.

    Vérifions l’espace disque. Le du La commande affiche l’espace utilisé par chaque table. Tout d’abord, la table avec des chaînes :

    $ du -h
    79G    ./default
    79G    .

    Le tableau avec UUID :

    $ du -h
    15G    ./default
    15G    .

    Déclarer la colonne comme UUID a permis d’économiser 64 Go d’espace disque !

    L’utilisation de l’UUID optimise les performances des requêtes et est rentable. Enfin, les prédicats sur les valeurs UUID deviendront encore plus rapides dans les futures versions de QuestDB car nous examinons comment les vectoriser en utilisant les instructions SIMD !

    Conclusion

    Nous utilisons des UUID pour générer des identifiants uniques au monde sans aucune coordination. Ils ont une longueur de 128 bits et n’occupent donc pas trop d’espace. Cela les rend adaptés aux applications distribuées, à l’IoT, aux crypto-monnaies ou à la finance décentralisée.

    Lorsque votre application stocke des UUID, indiquez à votre base de données qu’il s’agit d’un UUID, ne les stockez pas dans une colonne de chaîne. Vous économiserez de l’espace disque et des cycles CPU.

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.