Que sont les UUID et pourquoi sont-ils utiles ?

0
118
Stokkete/Shutterstock.com

Un identifiant universel unique (UUID) est une forme spécifique d'identifiant qui peut être considérée comme unique en toute sécurité pour la plupart des objectifs pratiques. Deux UUID correctement générés ont une chance pratiquement négligeable d'être identiques, même s'ils sont créés dans deux environnements différents par des parties distinctes. C'est pourquoi les UUID sont dits universellement uniques.

Dans cet article, nous examinerons les caractéristiques des UUID, le fonctionnement de leur unicité et les scénarios dans lesquels ils peuvent simplifier l'identification des ressources. Bien que nous abordions les UUID du point de vue commun des logiciels qui interagissent avec les enregistrements de base de données, ils sont largement applicables à tout cas d'utilisation où la génération décentralisée d'ID unique est requise.

Qu'est-ce qu'un UUID ?

Un UUID est simplement une valeur que vous pouvez traiter en toute sécurité comme unique. Le risque de collision est si faible que vous pouvez raisonnablement choisir de l'ignorer complètement. Vous pouvez voir des UUID référencés en utilisant des termes différents (GUID, ou Globally Unique Identifier, est la sémantique préférée de Microsoft), mais la signification et l'effet restent les mêmes.

Un véritable UUID est un identifiant unique généré et représenté par un format standardisé. Les UUID valides sont définis par la RFC 4122 ; cette spécification décrit les algorithmes qui peuvent être utilisés pour générer des UUID qui préservent l'unicité entre les implémentations, sans autorité centrale émettrice.

La RFC comprend cinq algorithmes différents qui utilisent chacun un mécanisme différent pour produire une valeur. Voici un bref résumé des “versions” :

  • Version 1 – Basé sur le temps– Combine un horodatage, une séquence d'horloge et une valeur spécifique à l'appareil générateur (généralement son adresse MAC) pour produire une sortie unique pour cet hôte à ce moment précis.
  • Version 2 – Sécurité DCE – Cette version a été développée comme une évolution de la version 1 pour une utilisation avec Distributed Computing Environment (DCE). Il n'est pas largement utilisé.
  • Version 3 – Basé sur le nom (MD5)– MD5 hache un “espace de noms” et un “nom” pour créer une valeur unique pour ce nom dans l'espace de noms. La génération d'un autre UUID avec le même espace de noms et le même nom produira une sortie identique afin que cette méthode fournisse des résultats reproductibles.
  • Version 4 – Aléatoire – La plupart des systèmes modernes ont tendance à opter pour UUID v4 car il utilise la source de nombres aléatoires ou pseudo-aléatoires de l'hôte pour émettre ses valeurs. Les chances que le même UUID soit produit deux fois sont pratiquement négligeables.
  • Version 5 – Basé sur le nom (SHA-1)– Ceci est similaire à la version 3 mais il utilise l'algorithme SHA-1 plus fort pour hacher l'espace de noms et le nom d'entrée.

Publicité

Bien que la RFC se réfère aux algorithmes comme des versions, cela ne ne signifie pas que vous devez toujours utiliser la version 5, car c'est apparemment la plus récente. Celui à choisir dépend de votre cas d'utilisation ; dans de nombreux scénarios, la v4 est choisie en raison de sa nature aléatoire. Cela en fait le candidat idéal pour un simple "donnez-moi un nouvel identifiant" scénarios.

Les algorithmes de génération émettent un entier non signé de 128 bits. Cependant, les UUID sont plus souvent considérés comme des chaînes hexadécimales et peuvent également être stockés sous la forme d'une séquence binaire de 16 caractères. Voici un exemple de chaîne UUID :

16763be4-6022-406e-a950-fcd5018633ca

La valeur est représentée par cinq groupes de caractères alphanumériques séparés par des tirets. Les tirets ne sont pas un composant obligatoire de la chaîne ; leur présence est due aux détails historiques de la spécification UUID. Ils rendent également l'identifiant beaucoup plus facile à percevoir pour les yeux humains.

Cas d'utilisation d'UUID

Le principal cas d'utilisation des UUID est la génération décentralisée d'unique identifiants. Vous pouvez générer l'UUID n'importe où et le considérer en toute sécurité comme unique, qu'il provienne de votre code backend, d'un appareil client ou de votre moteur de base de données.

Les UUID simplifient la détermination et la maintenance de l'identité des objets dans des environnements déconnectés. Historiquement, la plupart des applications utilisaient un champ entier auto-incrémenté comme clé primaire. Lorsque vous créez un nouvel objet, vous ne pouvez connaître son ID qu'après l'avoir inséré dans la base de données. Les UUID vous permettent de déterminer l'identité beaucoup plus tôt dans votre application.

Voici une démonstration PHP de base qui démontre la différence. Regardons d'abord le système basé sur les nombres entiers :

classe BlogPost { fonction publique __construct( public readonly ?int $Id, public readonly string $Headline, public readonly ?AuthorCollection $Authors=null) {} }   #[POST("/posts")] function createBlogPost(HttpRequest $Request) : vide { $titre = $Demande -> getField("Titre"); $blogPost = nouveau BlogPost(null, $headline); } Publicité

Nous devons initialiser la propriété $Id avec null car nous ne pouvons pas savoir qu'il s'agit d'un ID réel tant qu'il n'a pas été conservé dans la base de données. Ce n'est pas idéal – $Id ne devrait pas vraiment être nullable et cela permet aux instances de BlogPost d'exister dans un état incomplet.

Le passage aux UUID résout le problème :

classe BlogPost { fonction publique __construct( public readonly string $Uuid, public readonly string $Headline, public readonly ?AuthorCollection $Authors=null) {} }   #[POST("/posts")] function createBlogPost(HttpRequest $Request) : vide { $titre = $Demande -> getField("Titre"); $blogPost = nouveau BlogPost("16763be4-…", $titre); }

Les identifiants de publication peuvent désormais être générés dans l'application sans risquer de doubler les valeurs. Cela garantit que les instances d'objet représentent toujours un état valide et n'ont pas besoin de propriétés d'ID nullables maladroites. Le modèle facilite également la gestion de la logique transactionnelle ; les enregistrements enfants qui ont besoin d'une référence à leur parent (comme les associations d'auteurs de nos articles) peuvent être insérés immédiatement, sans aller-retour dans la base de données pour récupérer l'ID attribué au parent.

À l'avenir, votre application de blog pourrait déplacer plus de logique dans le client. Peut-être que l'interface prend en charge la création complète de brouillons hors ligne, créant ainsi des instances BlogPost qui sont temporairement conservées sur l'appareil de l'utilisateur. Désormais, le client peut générer l'UUID du poste et le transmettre au serveur lorsque la connectivité réseau est rétablie. Si le client récupérait par la suite la copie du brouillon du serveur, il pourrait la faire correspondre à n'importe quel état local restant car l'UUID serait déjà connu.

Les UUID vous aident également à combiner des données provenant de diverses sources . La fusion de tables de base de données et de caches utilisant des clés entières peut être fastidieuse et source d'erreurs. Les UUID offrent un caractère unique non seulement au sein des tables, mais au niveau de l'univers entier. Cela en fait de bien meilleurs candidats pour les structures répliquées et les données fréquemment déplacées entre différents systèmes de stockage.

Caveats When UUIDs Meet Databases

h2>

Les avantages des UUID sont assez convaincants. Cependant, il y a plusieurs pièges à surveiller lors de leur utilisation dans des systèmes réels. Un facteur important en faveur des ID entiers est qu'ils sont faciles à mettre à l'échelle et à optimiser. Les moteurs de base de données peuvent facilement indexer, trier et filtrer une liste de nombres qui ne va que dans une seule direction.

On ne peut pas en dire autant des UUID. Pour commencer, les UUID sont quatre fois plus gros que les entiers (36 octets contre 4 octets) ; pour les grands ensembles de données, cela pourrait être une considération importante en soi. Les valeurs sont également beaucoup plus délicates à trier et à indexer, en particulier dans le cas des UUID aléatoires les plus courants. Leur nature aléatoire signifie qu'ils n'ont pas d'ordre naturel. Cela nuira aux performances d'indexation si vous utilisez un UUID comme clé primaire.

Publicité

Ces problèmes peuvent s'aggraver dans une base de données bien normalisée qui fait un usage intensif de clés étrangères. Maintenant, vous pouvez avoir de nombreuses tables relationnelles, chacune contenant des références à vos UUID de 36 octets. Finalement, la mémoire supplémentaire nécessaire pour effectuer des jointures et des tris pourrait avoir un impact significatif sur les performances de votre système.

Vous pouvez partiellement atténuer les problèmes en stockant vos UUID sous forme de données binaires. Cela signifie une colonne BINARY(16) au lieu de VARCHAR(36). Certaines bases de données telles que PostgreSQL incluent un type de données UUID intégré ; d'autres comme MySQL ont des fonctions qui peuvent convertir une chaîne UUID en sa représentation binaire, et vice versa. Cette approche est plus efficace, mais n'oubliez pas que vous utiliserez toujours des ressources supplémentaires pour stocker et sélectionner vos données.

Une stratégie efficace peut consister à conserver des nombres entiers comme clés primaires, mais à ajouter un champ UUID supplémentaire pour référence de votre application. Les tables de liens relationnels peuvent utiliser des ID pour améliorer les performances pendant que votre code récupère et insère des objets de niveau supérieur avec des UUID. Tout dépend de votre système, de son échelle et de vos priorités : lorsque vous avez besoin d'une génération d'ID décentralisée et de fusions de données simples, les UUID sont la meilleure option, mais vous devez reconnaître les compromis.

Résumé

Les UUID sont des valeurs uniques que vous pouvez utiliser en toute sécurité pour la génération d'identité décentralisée. Les collisions sont possibles mais devraient être si rares qu'elles peuvent être écartées. Si vous génériez un milliard d'UUID par seconde pendant un siècle entier, la probabilité de rencontrer un doublon serait d'environ 50 % en supposant qu'une entropie suffisante était disponible.

Vous pouvez utiliser des UUID pour établir une identité indépendamment de votre base de données, avant qu'une insertion ne se produise. Cela simplifie le code au niveau de l'application et empêche les objets mal identifiés d'exister dans votre système. Les UUID facilitent également la réplication des données en garantissant l'unicité quel que soit le magasin de données, l'appareil ou l'environnement, contrairement aux clés entières traditionnelles qui fonctionnent au niveau de la table.

Bien que les UUID soient désormais omniprésents dans le développement de logiciels, ils ne sont pas parfaits Solution. Les nouveaux arrivants ont tendance à se fixer sur la possibilité de collisions, mais cela ne devrait pas être votre principale préoccupation, à moins que votre système ne soit si sensible que l'unicité doit être garantie.

Publicité

Le défi le plus apparent pour la plupart des développeurs concerne le stockage et récupération des UUID générés. L'utilisation naïve d'un VARCHAR(36) (ou la suppression des traits d'union et l'utilisation de VARCHAR(32)) pourrait paralyser votre application au fil du temps car la plupart des optimisations d'indexation de base de données seront inefficaces. Recherchez les capacités de gestion UUID intégrées de votre système de base de données pour vous assurer d'obtenir les meilleures performances possibles de votre solution.