Résumé

  • Les 48 premiers bits d’un UUIDv7 portent le nombre de millisecondes écoulées depuis l’époque Unix. Les 74 bits disponibles restants sont aléatoires par défaut ou peuvent accueillir précision supplémentaire et compteur.
  • La monotonie dans une même milliseconde, le recul de l’horloge, le débordement du compteur et la persistance d’état sont des choix d’implémentation. Deux générateurs conformes ne partagent pas pour autant un ordre causal.
  • UUIDv7 n’est ni authentification, ni autorisation, ni capacité de sécurité. Un ordre opposable exige des champs distincts : instant métier, générateur, lien causal, séquence de validation et reçu protégé.

Un format fait pour le rangement

Un UUIDv4 répartit ses valeurs de manière aléatoire. Cette propriété facilite la génération décentralisée, mais les insertions successives peuvent toucher des zones éloignées d’un index. RFC 9562 introduit des formes ordonnées dans le temps pour améliorer la localité et permettre le tri des octets sans introspection complexe.

Dans UUIDv7, un entier non signé de 48 bits encode les millisecondes Unix, secondes intercalaires exclues. Après les bits de version et de variante, 74 bits sont disponibles. Ils peuvent rester aléatoires ou combiner une fraction de milliseconde, un compteur puis de l’aléa. Le standard recommande v7 plutôt que v1 ou v6 lorsque c’est possible.

Cette disposition fournit une chronologie approximative très utile. Les valeurs créées au cours de millisecondes ultérieures se classent normalement après les précédentes. Le mot « normalement » rappelle la limite : la donnée provient de l’horloge et de la politique du générateur, pas d’un séquenceur de transactions partagé.

Le format ne sait pas quand l’événement métier s’est produit. L’application peut créer l’identifiant avant une opération finalement annulée, après réception différée d’un message ou lors de l’importation d’une archive.

Une milliseconde, plusieurs solutions conformes

À fort débit, un processus crée plusieurs UUID pendant la même milliseconde. Des suffixes aléatoires correctement produits limitent les collisions, mais ne reproduisent pas nécessairement l’ordre de création.

RFC 9562 décrit trois méthodes facultatives de monotonie : réserver des bits de poids fort à un compteur, employer un compteur monotone amorcé aléatoirement, ou inscrire une précision sous-milliseconde dans au plus 12 bits. Une implémentation peut aussi conserver de l’aléa après ces éléments.

Deux bibliothèques peuvent donc respecter le standard et faire des choix différents. Deux processus d’une même machine peuvent avoir des états séparés. Le tri de leur union donnera toujours un ordre total des octets ; il ne donnera pas automatiquement l’ordre de début, de validation ou de visibilité des opérations.

La résistance aux collisions et l’ordre sont deux propriétés. Un vaste espace aléatoire traite la première. Un compteur local traite une partie de la seconde. Ni l’un ni l’autre ne crée une relation de cause à effet entre des nœuds indépendants.

Quand l’horloge repart en arrière

Une correction manuelle, un protocole de synchronisation, la reprise d’une machine virtuelle ou un défaut peuvent faire reculer l’horloge. La section de bonnes pratiques de RFC 9562 demande à l’implémentation de traiter ce cas selon ses exigences.

Une application soucieuse de monotonie devrait comparer chaque nouvel UUID au précédent. Si la valeur n’est pas supérieure, elle peut conserver l’ancien timestamp et avancer un compteur, attendre que l’horloge rattrape, avancer artificiellement le timestamp inscrit ou signaler une erreur.

Chaque option déplace le compromis. Conserver le timestamp protège l’ordre local, mais détache l’heure inscrite du présent. Attendre protège mieux la proximité temporelle, au prix de disponibilité. Avancer écrit volontairement une heure future. Refuser préserve une règle en renonçant à l’identifiant.

Le RFC autorise en outre la modification, le brouillage ou le lissage du timestamp et ne garantit pas sa proximité avec l’heure réelle. Décoder la valeur ne suffit donc pas à connaître la politique qui l’a produite.

La monotonie a un périmètre d’état

Un générateur peut conserver sur stockage stable son dernier timestamp, ses compteurs et ses données aléatoires. Après redémarrage, cet état aide à rester au-dessus des valeurs antérieures. Cette persistance est facultative ; repartir comme un premier lot reste possible, avec davantage de risque de collision et de pression sur l’entropie.

Il faut alors nommer le périmètre de la promesse : un thread, un processus, un hôte, un cluster, une région ? Un compteur privé ne coordonne pas les autres générateurs. Le RFC remarque qu’une base monolithique peut obtenir la meilleure monotonie en générant elle-même ses UUID.

Dans un ensemble distribué, les nœuds peuvent produire indépendamment. L’aléa vise la singularité, pas la sérialisation. Fusionner les flux puis trier est pratique pour la pagination et la localisation temporelle. Ce tri ne crée pas après coup un ordre que les producteurs n’avaient jamais partagé.

Synchroniser l’heure ne crée pas la causalité

NTP et les pratiques de RFC 8633 peuvent améliorer les horloges. Ils ne promettent pas l’identité parfaite de deux horloges applicatives à chaque instant et ne décrivent pas le lien causal entre deux actions.

Si le service A écrit puis envoie un message au service B, un décalage peut placer l’UUID de B avant celui de A. Une nouvelle tentative peut recevoir son identifiant à un autre moment du cycle. Deux nœuds peuvent aussi utiliser des règles différentes à l’intérieur de la même milliseconde.

L’application connaît souvent une preuve plus forte : le message B référence A, une base attribue une position de commit, ou un journal délivre un reçu après acceptation. Ces données peuvent accompagner UUIDv7. L’identifiant sert de clé portable et d’indice temporel ; le lien ou la séquence porte l’affirmation causale.

Dire que UUIDv7 ne résout pas la causalité n’est pas relever un défaut. RFC 9562 normalise des identifiants et des pratiques de génération. Il ne se présente ni comme consensus distribué ni comme protocole d’horloge partagée.

Le risque du témoignage fabriqué

Une plateforme trie par UUID puis intitule la vue « ordre des événements ». Ce titre suppose que toutes les horloges sont comparables, que leur recul est traité de la même façon, que les méthodes intra-milliseconde sont compatibles, que l’identifiant est créé au moment métier pertinent et qu’aucun import ne remonte des données anciennes.

L’UUID peut être parfaitement valide alors que l’une de ces hypothèses échoue. Un identifiant peut précéder une transaction annulée, être créé par un producteur avant livraison, ou être attribué aujourd’hui à une opération historique. Un brouillage de temps autorisé peut également modifier sa proximité avec le réel.

Un schéma d’audit sérieux distingue l’identifiant, l’instant de l’événement et sa source, l’instant d’ingestion, le générateur et sa version de politique, le prédécesseur causal, ainsi que la séquence de commit ou de reçu. Tout système n’a pas besoin de tous ces champs, mais aucun ne devrait leur substituer UUIDv7 sans le dire.

Si seul l’identifiant subsiste, l’analyse peut parler d’ordre approximatif à l’horloge du générateur. Elle doit conserver l’incertitude et ne pas trancher un litige sur cette base unique.

L’identifiant ne confère aucun droit

RFC 9562 avertit qu’un UUID ne doit pas être présumé difficile à deviner et ne doit pas servir de capacité de sécurité où la possession ouvre l’accès. La prudence demeure même si les bits aléatoires de v7 proviennent d’un bon générateur.

Singularité, imprévisibilité et autorité ne sont pas synonymes. L’entropie réduit la collision et peut décourager la devinette. Elle n’authentifie pas la personne qui présente la valeur et ne l’autorise pas à lire ou modifier l’objet.

Le timestamp révèle par ailleurs un ordre de création limité pour l’UUID et ses données associées. Un compteur peut exposer un rythme. RFC 4086 et RFC 8937 rappellent qu’une suite d’apparence aléatoire n’est pas automatiquement sûre.

Les contrôles d’accès doivent authentifier l’acteur et autoriser l’action. L’intégrité exige une preuve adaptée. Une API ne devrait pas divulguer une ressource simplement parce qu’un UUID bien formé est fourni.

Un registre de promesses

Avant migration, écrire l’objectif. Pour la localité d’index, mesurer l’index réel. Pour la pagination monotone locale, documenter le périmètre du générateur, la méthode intra-milliseconde, la persistance et la réaction au recul.

Pour un audit distribué, conserver l’endroit où l’UUID a été créé, la source d’heure, la version de politique et l’étape du cycle de vie. Ajouter explicitement les liens causaux ou positions de commit. Si un tiers doit s’y fier, produire un reçu dont l’émetteur et l’intégrité sont vérifiables.

Les tests doivent inclure les rafales dans une milliseconde, le débordement, le redémarrage, la perte d’état, le saut d’horloge dans les deux sens, la partition régionale et la fusion des flux. Ils vérifient la promesse locale, non une vertu abstraite du numéro de version.

Sources