Cosa sono gli UUID e perché sono utili?

0
810
Stokkete/Shutterstock.com

Un identificatore univoco universale (UUID) è una forma specifica di identificatore che può essere tranquillamente considerato univoco per la maggior parte degli scopi pratici. Due UUID generati correttamente hanno una possibilità praticamente trascurabile di essere identici, anche se vengono creati in due ambienti diversi da parti separate. Questo è il motivo per cui si dice che gli UUID siano universalmente univoci.

In questo articolo, esamineremo le caratteristiche degli UUID, come funziona la loro unicità e gli scenari in cui possono semplificare l'identificazione delle risorse. Sebbene ci avvicineremo agli UUID dalla prospettiva comune del software che interagisce con i record del database, sono ampiamente applicabili a qualsiasi caso d'uso in cui è richiesta la generazione decentralizzata di ID univoci.

Che cos'è effettivamente un UUID?

Un UUID è semplicemente un valore che puoi tranquillamente considerare unico. Il rischio di collisione è così basso che puoi ragionevolmente scegliere di ignorarlo del tutto. Potresti vedere UUID a cui si fa riferimento utilizzando termini diversi (GUID, o Globally Unique Identifier, è la semantica preferita di Microsoft), ma il significato e l'effetto rimangono gli stessi.

Un vero UUID è un identificatore univoco generato e rappresentato da un formato standardizzato. Gli UUID validi sono definiti da RFC 4122; questa specifica descrive gli algoritmi che possono essere utilizzati per generare UUID che preservano l'unicità tra le implementazioni, senza un'autorità di emissione centrale.

L'RFC include cinque diversi algoritmi, ciascuno dei quali utilizza un meccanismo diverso per produrre un valore. Ecco un breve riassunto delle “versioni” disponibili:

  • Versione 1 – Basato sul tempo– Combina un timestamp, una sequenza di clock e un valore specifico del dispositivo di generazione (solitamente il suo indirizzo MAC) per produrre un output unico per quell'host in quel momento.
  • Versione 2 – Sicurezza DCE – Questa versione è stata sviluppata come evoluzione della versione 1 per l'utilizzo con Distributed Computing Environment (DCE). Non è ampiamente utilizzato.
  • Versione 3 – Basato sul nome (MD5)– MD5 esegue l'hashing di un “spazio dei nomi” e un “nome” per creare un valore univoco per quel nome all'interno dello spazio dei nomi. La generazione di un altro UUID con lo stesso spazio dei nomi e nome produrrà un output identico, quindi questo metodo fornisce risultati riproducibili.
  • Versione 4 – Casuale – La maggior parte dei sistemi moderni tende a optare per UUID v4 poiché utilizza la fonte dell'host di numeri casuali o pseudocasuali per emettere i suoi valori. Le possibilità che lo stesso UUID venga prodotto due volte sono praticamente trascurabili.
  • Versione 5 – Basato sul nome (SHA-1)– È simile alla versione 3 ma utilizza l'algoritmo SHA-1 più potente per eseguire l'hashing dello spazio dei nomi e del nome di input.

Pubblicità

Sebbene la RFC si riferisca agli algoritmi come versioni, ciò non non significa che dovresti sempre usare la versione 5 perché sembra essere la più recente. Quello da scegliere dipende dal tuo caso d'uso; in molti scenari, la v4 viene scelta a causa della sua natura casuale. Questo lo rende il candidato ideale per semplici “dammi un nuovo identificatore” scenari.

Gli algoritmi di generazione emettono un intero senza segno a 128 bit. Tuttavia, gli UUID sono più comunemente visti come stringhe esadecimali e possono anche essere archiviati come una sequenza binaria di 16 caratteri. Ecco un esempio di stringa UUID:

16763be4-6022-406e-a950-fcd5018633ca

Il valore è rappresentato da cinque gruppi di caratteri alfanumerici separati da trattini. I trattini non sono un componente obbligatorio della stringa; la loro presenza dipende dai dettagli storici della specifica UUID. Inoltre rendono l'identificatore molto più facile da percepire per gli occhi umani.

Casi d'uso UUID

Il caso d'uso principale per gli UUID è la generazione decentralizzata di identificatori. Puoi generare l'UUID ovunque e considerarlo univoco in tutta sicurezza, indipendentemente dal fatto che provenga dal tuo codice back-end, da un dispositivo client o dal tuo motore di database.

Gli UUID semplificano la determinazione e il mantenimento dell'identità dell'oggetto in ambienti disconnessi. Storicamente la maggior parte delle applicazioni utilizzava un campo intero a incremento automatico come chiave primaria. Quando stai creando un nuovo oggetto, non puoi conoscerne l'ID fino a quando non è stato inserito nel database. Gli UUID ti consentono di determinare l'identità molto prima nella tua applicazione.

Ecco una demo PHP di base che dimostra la differenza. Diamo prima un'occhiata al sistema basato su numeri interi:

classe BlogPost { funzione pubblica __construct( public readonly ?int $Id, public readonly string $Headline, public readonly ?AuthorCollection $Autori=null) {} }   #[POST("/posts")] funzione createBlogPost(HttpRequest $Request) : vuoto { $titolo = $Richiesta -> getField("Titolo"); $blogPost = nuovo BlogPost(null, $titolo); } Pubblicità

Dobbiamo inizializzare la proprietà $Id con null perché non possiamo sapere che è l'ID effettivo fino a quando non è stato mantenuto nel database. Questo non è l'ideale – $Id non dovrebbe essere realmente nullable e consente alle istanze BlogPost di esistere in uno stato incompleto.

La modifica degli UUID risolve il problema:

classe BlogPost { funzione pubblica __construct( public readonly stringa $Uuid, public readonly stringa $Headline, public readonly ?AuthorCollection $Authors=null) {} }   #[POST("/posts")] funzione createBlogPost(HttpRequest $Request) : vuoto { $titolo = $Richiesta -> getField("Titolo"); $blogPost = nuovo BlogPost("16763be4-…", $titolo); }

Ora è possibile generare identificatori di post all'interno dell'applicazione senza rischiare valori duplicati. Ciò garantisce che le istanze dell'oggetto rappresentino sempre uno stato valido e non necessitino di proprietà ID nullable ingombranti. Il modello semplifica anche la gestione della logica transazionale; i record figlio che necessitano di un riferimento al genitore (come le associazioni degli autori del nostro post) possono essere inseriti immediatamente, senza un viaggio di andata e ritorno del database per recuperare l'ID assegnato al genitore.

In futuro, l'applicazione del tuo blog potrebbe spostare più logica nel client. Forse il frontend ottiene il supporto per la creazione di bozze offline complete, creando in modo efficace istanze BlogPost che vengono temporaneamente mantenute sul dispositivo dell'utente. Ora il client può generare l'UUID del post e trasmetterlo al server quando viene ripristinata la connettività di rete. Se il client ha successivamente recuperato la copia della bozza dal server, potrebbe abbinarla a qualsiasi stato locale rimanente poiché l'UUID sarebbe già noto.

Gli UUID ti aiutano anche a combinare i dati da varie origini . L'unione di tabelle di database e cache che utilizzano chiavi intere può essere noiosa e soggetta a errori. Gli UUID offrono unicità non solo all'interno delle tabelle ma a livello dell'intero universo. Questo li rende candidati molto migliori per strutture e dati replicati che vengono spesso spostati tra diversi sistemi di archiviazione.

Avvertenze quando gli UUID incontrano i database

h2>

I vantaggi degli UUID sono piuttosto interessanti. Tuttavia, ci sono diversi trucchi da tenere d'occhio quando li usi nei sistemi reali. Un grande fattore a favore degli ID interi è che sono facili da ridimensionare e ottimizzare. I motori di database possono indicizzare, ordinare e filtrare facilmente un elenco di numeri che va solo in una direzione.

Lo stesso non si può dire per gli UUID. Per cominciare, gli UUID sono quattro volte più grandi degli interi (36 byte contro 4 byte); per set di dati di grandi dimensioni, questa potrebbe essere di per sé una considerazione significativa. I valori sono anche molto più complicati da ordinare e indicizzare, in particolare nel caso degli UUID casuali più comuni. La loro natura casuale significa che non hanno un ordine naturale. Ciò danneggerà le prestazioni dell'indicizzazione se utilizzi un UUID come chiave primaria.

Pubblicità

Questi problemi possono aggravarsi in un database ben normalizzato che fa un uso massiccio di chiavi esterne. Ora potresti avere molte tabelle relazionali, ognuna contenente riferimenti ai tuoi UUID a 36 byte. Alla fine, la memoria aggiuntiva necessaria per eseguire join e ordinamenti potrebbe avere un impatto significativo sulle prestazioni del tuo sistema.

Puoi mitigare parzialmente i problemi archiviando i tuoi UUID come dati binari. Ciò significa una colonna BINARY(16) invece di VARCHAR(36). Alcuni database come PostgreSQL includono un tipo di dati UUID integrato; altri come MySQL hanno funzioni che possono convertire una stringa UUID nella sua rappresentazione binaria e viceversa. Questo approccio è più efficiente, ma ricorda che continuerai a utilizzare risorse extra per archiviare e selezionare i tuoi dati.

Una strategia efficace può essere quella di conservare numeri interi come chiavi primarie ma aggiungere un campo UUID aggiuntivo per il riferimento della tua applicazione. Le tabelle di collegamento relazionali potrebbero utilizzare gli ID per migliorare le prestazioni mentre il codice recupera e inserisce oggetti di primo livello con UUID. Tutto dipende dal tuo sistema, dalla sua scala e dalle tue priorità: quando hai bisogno di una generazione decentralizzata di ID e di unioni di dati semplici, gli UUID sono l'opzione migliore, ma devi riconoscere i compromessi.

Riepilogo

Gli UUID sono valori univoci che puoi utilizzare in sicurezza per la generazione decentralizzata di identità. Le collisioni sono possibili ma dovrebbero essere così rare da poter essere scartate dalla considerazione. Se generassi un miliardo di UUID al secondo per un intero secolo, la probabilità di incontrare un duplicato sarebbe di circa il 50% supponendo che fosse disponibile sufficiente entropia.

È possibile utilizzare gli UUID per stabilire l'identità indipendentemente dal database, prima che si verifichi un inserimento. Ciò semplifica il codice a livello di applicazione e impedisce l'esistenza di oggetti identificati in modo errato nel sistema. Gli UUID aiutano anche la replica dei dati garantendo l'unicità indipendentemente dall'archivio dati, dal dispositivo o dall'ambiente, a differenza delle tradizionali chiavi intere che operano a livello di tabella.

Sebbene gli UUID siano ormai onnipresenti nello sviluppo del software, non sono perfetti soluzione. I nuovi arrivati ​​tendono a fissarsi sulla possibilità di collisioni, ma questa non dovrebbe essere la tua prima considerazione, a meno che il tuo sistema non sia così sensibile da dover garantire l'unicità.

Pubblicità

La sfida più evidente per la maggior parte degli sviluppatori riguarda il archiviazione e recupero degli UUID generati. L'uso ingenuo di un VARCHAR(36) (o l'eliminazione dei trattini e l'utilizzo di VARCHAR(32)) potrebbe paralizzare l'applicazione nel tempo poiché la maggior parte delle ottimizzazioni dell'indicizzazione del database saranno inefficaci. Ricerca le funzionalità di gestione UUID integrate nel tuo sistema di database per assicurarti di ottenere le migliori prestazioni possibili dalla tua soluzione.