Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Dividere un archivio dati in un set di partizioni orizzontali. Questo approccio può migliorare la scalabilità quando si archivia e si accede a grandi volumi di dati.
Contesto e problema
Un archivio dati in un singolo server presenta le limitazioni seguenti:
Spazio di archiviazione: Un archivio dati per un'applicazione cloud su larga scala può contenere un volume elevato di dati che aumenta nel tempo. Un server fornisce una quantità limitata di spazio di archiviazione su disco ed è possibile sostituire i dischi esistenti con quelli più grandi o aggiungere più dischi man mano che aumentano i volumi di dati. Il sistema raggiunge infine un limite in cui non è possibile aumentare la capacità di archiviazione in un singolo server.
Risorse di calcolo: Un'applicazione cloud deve supportare un numero elevato di utenti simultanei che eseguono query sull'archivio dati. Un singolo server potrebbe non fornire una potenza di calcolo sufficiente per questo carico, il che comporta tempi di risposta e timeout estesi. È possibile aggiungere memoria o aggiornare processori, ma il sistema raggiunge un limite in cui non è possibile aumentare ulteriormente le risorse di calcolo.
Larghezza di banda di rete: Frequenza con cui un singolo server può ricevere richieste e inviare risposte limita le prestazioni dell'archivio dati. Il volume del traffico di rete può superare la capacità della connessione di rete, con il risultato di richieste non riuscite.
Geografia: I requisiti legali, di conformità o di prestazioni potrebbero richiedere l'archiviazione dei dati utente nella stessa area geografica degli utenti. Se gli utenti si estendono in paesi/aree geografiche, potrebbe non essere possibile archiviare tutti i dati dell'applicazione in un singolo archivio dati.
Per posticipare temporaneamente queste limitazioni, è possibile ridimensionare verticalmente aggiungendo capacità del disco, potenza di elaborazione, memoria e connessioni di rete. Un'applicazione cloud che deve supportare un numero elevato di utenti e volumi di dati elevati deve essere ridimensionata orizzontalmente.
Soluzione
È possibile dividere un archivio dati in partizioni orizzontali. Ogni partizione ha lo stesso schema, ma contiene un proprio subset distinto dei dati. Ogni partizione è un archivio dati completo che può contenere dati per molte entità di tipi diversi. Una partizione viene eseguita in un server che funge da nodo di archiviazione.
Questo modello offre i vantaggi seguenti:
È possibile aumentare il numero di istanze del sistema aggiungendo altre partizioni in nodi di archiviazione aggiuntivi.
Un sistema può usare hardware predefinito anziché computer specializzati e costosi per ogni nodo di archiviazione.
È possibile ridurre la contesa e migliorare le prestazioni bilanciando il carico di lavoro tra le partizioni.
Nel cloud le partizioni possono risiedere fisicamente vicino agli utenti che accedono ai dati.
Quando si divide un archivio dati in partizioni, decidere quali dati inserire in ogni partizione. Ogni partizione contiene in genere elementi raggruppati per uno o più attributi di dati. Questi attributi formano la chiave di shard, talvolta denominata chiave di partizione.
Il partizionamento orizzontale organizza fisicamente i dati. Quando un'applicazione archivia e recupera i dati, la logica di partizionamento orizzontale li indirizza alla partizione appropriata. È possibile implementare questa logica nel codice di accesso ai dati dell'applicazione o nel sistema di archiviazione dei dati se supporta in modo trasparente il partizionamento orizzontale.
L'astrazione della posizione fisica dei dati nella logica di partizionamento orizzontale fornisce il controllo sulle partizioni che contengono i dati. È anche possibile eseguire la migrazione dei dati tra partizioni senza modificare la logica di business dell'applicazione quando è necessario ridistribuire i dati, ad esempio quando le partizioni diventano sbilanciate. Il compromesso è l'overhead per l'accesso ai dati aggiuntivo necessario per determinare la posizione di ciascun elemento di dati durante il recupero.
Selezione della chiave di partizione
La chiave di partizione è la decisione di progettazione più critica in un sistema partizionato. Per modificare una chiave di partizione dopo averlo scelto, in genere è necessario eseguire la migrazione di tutti i dati a un nuovo layout di partizione, ovvero un'operazione costosa e rischiosa in un sistema attivo. Prendere questa decisione con attenzione prima di scrivere codice.
Una chiave di partizione efficace non è modificabile, ha cardinalità elevata, distribuisce i dati e carica in modo uniforme e si allinea ai modelli di query dominanti in modo che la maggior parte delle richieste venga risolta in una singola partizione. Evitare l'aumento monotonico dei valori (numeri interi autocrement e timestamp sequenziali), attributi di cardinalità bassa (valori booleani e set di enumerazioni di piccole dimensioni) e attributi volatili che cambiano frequentemente. Questi attributi portano a hotspot o a spostamento costoso dei dati tra partizioni.
Se nessun singolo attributo soddisfa questi criteri, definire una chiave di partizione composita combinando due o più attributi. Se le query devono recuperare i dati in base agli attributi che non fanno parte della chiave di partizione, usare un modello come il modello Tabella indice per fornire ricerche secondarie.
Per altre informazioni su come scegliere le chiavi di partizione tra i servizi di Azure, vedere Linee guida per il partizionamento dei dati e Strategie di partizionamento dei dati.
Strategie di partizionamento
Usare una delle strategie seguenti quando si seleziona la chiave di partizione e si decide come distribuire i dati tra le partizioni. Non è necessaria una corrispondenza uno-a-uno tra le partizioni e i server che li ospitano. Un singolo server può ospitare più partizioni.
Strategia di partizionamento orizzontale della ricerca
Nella strategia di ricerca, detta anche strategia basata su directory, la logica di partizionamento orizzontale implementa una mappa che instrada una richiesta di dati alla partizione che contiene tali dati usando la chiave di partizione. In un'applicazione multi-tenant è possibile archiviare tutti i dati per un tenant in una partizione usando l'ID tenant come chiave di partizione. Più tenant possono condividere la stessa partizione, ma i dati per un singolo tenant non vengono distribuiti tra più partizioni. Il diagramma seguente mostra il partizionamento orizzontale dei dati del tenant in base agli ID tenant.
Il mapping tra i valori della chiave di partizione e l'archiviazione fisica può essere diretto, in cui ogni valore della chiave di partizione è mappato a una partizione fisica. Una tecnica più flessibile è il partizionamento virtuale, in cui i valori delle chiavi di partizione vengono mappati alle partizioni virtuali e il sistema esegue quindi il mapping di tali partizioni virtuali a un minor numero di partizioni fisiche. Un'applicazione individua i dati usando un valore di chiave di partizione che fa riferimento a una partizione virtuale e il sistema esegue il mapping trasparente delle partizioni virtuali alle partizioni fisiche. Il mapping tra una partizione virtuale e una partizione fisica può cambiare senza richiedere modifiche al codice dell'applicazione.
Strategia di partizionamento orizzontale basata su intervalli
La strategia basata su intervalli raggruppa gli elementi correlati nella stessa partizione e li ordina in base alla chiave di partizione sequenziale. Questa strategia supporta le applicazioni che recuperano spesso set di elementi usando query di intervallo. Le query di intervallo restituiscono un set di elementi di dati per una chiave di partizione che rientra in un determinato intervallo.
Ad esempio, se un'applicazione deve trovare regolarmente tutti gli ordini inseriti in un determinato mese, è possibile recuperare i dati più velocemente se si archiviano tutti gli ordini per un mese nell'ordine di data e ora nella stessa partizione. Se si archivia ogni ordine in una partizione diversa, l'applicazione deve recuperarle singolarmente eseguendo un numero elevato di query di punti. Il diagramma seguente mostra set sequenziali, o intervalli, di dati archiviati in partizioni.
In questo esempio, la chiave di partizione è una chiave composta che contiene il mese dell'ordine come elemento più significativo, seguito dal giorno e dall'ora dell'ordine. I nuovi ordini vengono organizzati automaticamente man mano che vengono creati e aggiunti a uno shard.
Alcuni archivi dati supportano chiavi di shard in due parti. Una chiave di partizione identifica la partizione e una chiave di riga identifica in modo univoco un elemento all'interno della partizione. Lo shard archivia in genere i dati in ordine di chiave di riga. Per gli elementi che richiedono query di intervallo e devono essere raggruppati, è possibile usare una chiave di shard con lo stesso valore per la chiave di partizione, ma un valore univoco per la chiave di riga.
Strategia di partizionamento orizzontale basata su hash
La strategia basata su hash riduce la probabilità di hotspot, ovvero partizioni che ricevono una quantità sproporzionata di carico. Questa strategia distribuisce i dati tra partizioni per bilanciare le dimensioni di ogni partizione e il carico medio rilevato da ogni partizione. La logica di partizionamento calcola la partizione per archiviare un elemento in base a un hash di uno o più attributi dei dati. La funzione di hashing scelta deve distribuire i dati in modo uniforme tra le partizioni. Il diagramma seguente illustra il partizionamento orizzontale dei dati del tenant in base a un hash di ID tenant.
Per comprendere il vantaggio della strategia hash rispetto ad altre strategie di partizionamento orizzontale, considerare come un'applicazione multi-tenant che registra i nuovi tenant in sequenza potrebbe assegnare i tenant alle partizioni nell'archivio dati. Quando si usa la strategia di intervallo, i dati per i tenant da 1 a n vengono archiviati nella partizione A, i dati per i tenant n+1-m vengono archiviati nella partizione B e gli intervalli di tenant successivi vengono mappati alle partizioni successive. Se anche i tenant registrati più di recente sono i più attivi, la maggior parte delle attività sui dati si verifica in pochi shard, il che può causare hotspot. Al contrario, la strategia hash alloca i locatari alle partizioni in base a un hash del loro ID locatario. L'hash distribuisce in genere tenant sequenziali tra diverse partizioni, che bilanciano il carico. Il diagramma precedente illustra questo approccio per i tenant 55 e 56.
Strategia di partizionamento orizzontale geografico
La strategia geografica assegna i dati alle partizioni in base all'origine geografica o all'area di consumo desiderata dei dati. In molti carichi di lavoro, gli utenti e i dati generati vengono concentrati in aree specifiche. I requisiti normativi, ad esempio le leggi sulla residenza dei dati, potrebbero richiedere che i dati specifici rimangano all'interno di una giurisdizione specifica. Anche senza driver normativi, l'inserimento dei dati vicino agli utenti che vi accedono spesso riduce la latenza di rete per letture e scritture.
In questa strategia si deriva la chiave di partizione da un attributo geografico, ad esempio il paese o l'area geografica dell'utente, l'area del data center di origine o un identificatore del tenant a livello di area. Si ospita o si fissa ogni frammento all'infrastruttura all'interno di tale confine geografico.
Ad esempio, un'applicazione che serve i clienti in America del Nord, Europa e Asia-Pacific potrebbe gestire tre gruppi di partizioni, un gruppo in ogni area di Azure corrispondente. Un'applicazione europea che serve solo gli utenti europei instrada una richiesta alla partizione Europa. Questo approccio riduce la latenza e soddisfa i requisiti di residenza dei dati.
Il partizionamento orizzontale geografico introduce il rischio di distribuzione non uniforme dei dati. Se la maggior parte degli utenti si trova in una regione, lo shard di quella regione gestisce una parte sproporzionata del carico e della memoria. È possibile combinare il partizionamento orizzontale geografico con un'altra strategia, ad esempio hash o ricerca, all'interno di ogni area per distribuire il carico in modo uniforme tra più partizioni all'interno dello stesso limite geografico.
Vantaggi e considerazioni per ogni strategia
Le quattro strategie di partizionamento orizzontale presentano i vantaggi e le considerazioni seguenti:
La strategia di ricerca offre un maggiore controllo sulla configurazione delle partizioni. Le partizioni virtuali riducono l'impatto del ribilanciamento perché è possibile aggiungere nuove partizioni fisiche per bilanciare il carico di lavoro. È possibile modificare il mapping tra una partizione virtuale e le relative partizioni fisiche senza influire sul codice dell'applicazione. La ricerca delle posizioni delle partizioni comporta un sovraccarico.
La strategia di intervallo è facile da implementare e funziona bene con le query di intervallo. Le query di intervallo possono recuperare più elementi di dati da una singola partizione in un'unica operazione. La gestione dei dati è più semplice. Ad esempio, è possibile pianificare gli aggiornamenti per fuso orario in base ai modelli di carico locali quando gli utenti nella stessa area condividono una partizione. Tuttavia, questa strategia non bilancia il carico in modo uniforme tra le partizioni. Il ribilanciamento è difficile e potrebbe non risolvere il carico non uniforme quando la maggior parte delle attività si concentra sulle chiavi di shard adiacenti.
La strategia hash offre una probabilità migliore di una distribuzione uniforme dei dati e del carico. È possibile instradare le richieste direttamente usando la funzione hash senza gestire una mappa. Il calcolo dell'hash comporta un sovraccarico. Il ribilanciamento è difficile senza hashing consistente.
La strategia geografica soddisfa i requisiti di residenza e sovranità dei dati che altre strategie non soddisfano intrinsecamente. Riduce la latenza di lettura e scrittura quando gli utenti accedono ai dati nella propria area. Tuttavia, il partizionamento orizzontale geografico può creare uno squilibrio significativo dei dati e del carico quando i popolamenti degli utenti non vengono distribuiti uniformemente tra aree. Le query che si estendono su aree, ad esempio la creazione di report globali, devono recuperare i dati da tutte le partizioni geografiche e comportare una latenza più elevata. Combinare il partizionamento orizzontale geografico con un'altra strategia all'interno di ogni area quando è necessaria sia la conformità che la distribuzione del carico.
La maggior parte dei sistemi di partizionamento orizzontale implementa uno di questi approcci, ma è consigliabile considerare anche i requisiti aziendali dell'applicazione e i relativi modelli di utilizzo dei dati. Ad esempio, in un'applicazione multi-tenant:
È possibile partizionare i dati in base al carico di lavoro. Separare i dati per i tenant altamente volatili in partizioni separate per migliorare la velocità di accesso ai dati per altri tenant.
È possibile partizionare i dati in base alla posizione del tenant. Portare offline i dati del tenant in un'area geografica specifica per il backup e la manutenzione durante le ore di minore attività dell'area, mentre i dati del tenant in altre aree rimangono online durante l'orario di ufficio.
Assegnare ai clienti di alto valore i propri shard dedicati e leggermente caricati. I tenant con un valore inferiore possono condividere partizioni più densamente compresse.
Archiviare i dati per i tenant che necessitano di un forte isolamento dei dati e privacy in server separati.
Operazioni di ridimensionamento e spostamento dei dati per ogni strategia
Ogni strategia di shardizzazione offre funzionalità e diversi livelli di complessità per gestire la scalabilità orizzontale, la scalabilità verticale, lo spostamento dei dati e la manutenzione dello stato.
La strategia di ricerca consente operazioni di ridimensionamento e spostamento dei dati a livello di utente, online o offline. Per spostare i dati:
Sospendere alcune o tutte le attività dell'utente, in genere durante periodi di minore attività.
Spostare i dati nella nuova partizione virtuale o nella partizione fisica.
Aggiorna le mappature.
Invalidare o aggiornare eventuali cache che contengono questi dati.
Riprendere l'attività dell'utente.
È spesso possibile gestire questa operazione centralmente. La strategia di ricerca richiede che lo stato sia altamente memorizzabile nella cache e ottimizzato per le repliche.
La strategia di intervallo limita le operazioni di ridimensionamento e spostamento dei dati perché è necessario suddividere e unire i dati tra partizioni, in genere mentre parte o tutto l'archivio dati è offline. Quando si spostano i dati per ribilanciare le partizioni, è possibile che non si elimini il carico non uniforme se la maggior parte delle attività si concentra sulle chiavi di partizione adiacenti o sugli identificatori di dati all'interno dello stesso intervallo. La strategia di intervallo potrebbe anche richiedere che lo stato mappi gli intervalli alle partizioni fisiche.
La strategia hash complica le operazioni di ridimensionamento e spostamento dei dati. Le chiavi di partizione sono hash delle chiavi di shard o degli identificatori di dati. Con una funzione hash standard, ad esempio
hash(key) mod N, l'aggiunta o la rimozione di una partizione riassegna la maggior parte delle chiavi e attiva la migrazione dei dati su larga scala. L'hashing coerente riduce questo impatto disponendo lo spazio hash in modo che venga spostata solo una piccola frazione di chiavi quando cambia il numero di partizioni. La strategia hash non richiede la manutenzione di uno stato di mapping separato.La strategia geografica collega direttamente le operazioni di scalabilità al provisioning dell'infrastruttura regionale. L'aggiunta di capacità in un'area non riduce il carico in un'altra area. I requisiti normativi che impongono il partizionamento orizzontale geografico possono anche limitare lo spostamento dei dati attraverso i limiti geografici. All'interno di ogni area, il ridimensionamento usa la strategia secondaria che distribuisce i dati tra le partizioni di tale area.
Problemi e considerazioni
Quando si decide come implementare questo modello, tenere presente quanto segue:
Utilizzare lo sharding in modo complementare ad altre forme di partizionamento, come il partizionamento verticale e il partizionamento funzionale. Ad esempio, una singola partizione può contenere entità partizionate verticalmente ed è possibile implementare una partizione funzionale come più partizioni. Per altre informazioni, vedere Partizionamento orizzontale, verticale e funzionale dei dati.
Mantenere bilanciate le partizioni in modo che possano gestire tutti un volume di input/output (I/O) simile. L'asimmetria dei dati si accumula nel tempo quando i record vengono inseriti ed eliminati, che causano hotspot. Pianificare periodicamente il ribilanciamento.
Il ribilanciamento sposta i dati tra le partizioni e spesso causa tempi di inattività o velocità effettiva ridotta. Per ribilanciare meno frequentemente, usare le partizioni virtuali. Mappare molte partizioni logiche a un numero minore di shard fisiche. Quando un frammento è sovraccarico, ridistribuire le sue partizioni virtuali su nuovi frammenti fisici senza ricalcolare l'hash dell'intero set di dati. Azure Cosmos DB usa questo approccio per separare lo schema di partizione dall'infrastruttura fisica.
È preferibile utilizzare molti piccoli frammenti piuttosto che pochi grandi. I frammenti più piccoli migrano più velocemente, bilanciano il carico in modo più equilibrato e offrono maggiore flessibilità per la ridistribuzione dei dati.
Usare dati stabili per la chiave di partizione. Se la chiave di partizione cambia, potrebbe essere necessario spostare l'elemento di dati corrispondente tra le partizioni, aumentando così il sovraccarico dell'operazione di aggiornamento. Evitare di basare la chiave di partizione su informazioni potenzialmente volatili. Scegliere gli attributi che sono invarianti o che formano naturalmente una chiave.
Assicurarsi che le shard key siano univoche. Evitare, ad esempio, di usare campi a incremento automatico come shard key. In alcuni sistemi, i campi auto-incrementati non possono coordinarsi tra frammenti, il che può causare elementi in frammenti diversi con la stessa chiave di frammento.
Annotazioni
I valori auto-incrementati in altri campi che non sono chiavi shard possono causare problemi. Ad esempio, se si usano campi autoincremented per generare ID univoci, è possibile assegnare allo stesso ID due elementi diversi in partizioni diverse.
Partizionare i dati per supportare le query eseguite più di frequente. Potrebbe non essere possibile progettare uno shard key che soddisfi i requisiti di ogni query sui dati. Se necessario, creare tabelle di indice secondarie per supportare query che recuperano i dati in base agli attributi che non fanno parte della chiave di partizione. Per altre informazioni, vedere Modello di tabella dell'indice.
Progettare la chiave shard e il modello di dati per fare in modo che la maggior parte delle operazioni siano limitate a un singolo shard. Le query che accedono a una singola partizione sono più efficienti rispetto alle query che recuperano dati da più partizioni. Denormalizzare i dati per mantenere le entità correlate comunemente sottoposte a query, ad esempio i clienti e i relativi ordini, nella stessa partizione per ridurre il numero di letture separate.
Le query tra partizioni aggiungono latenza, consumo di risorse e complessità. Quando un'applicazione deve recuperare dati da più partizioni, usare query di fan-out parallele eseguite su ogni partizione contemporaneamente e aggregare i risultati. Anche con il parallelismo, la partizione più lenta determina la latenza complessiva.
Suggerimento
Se un'entità in una partizione fa riferimento a un'entità in un'altra partizione, includere la chiave di partizione per la seconda entità come parte dello schema per la prima entità. Questo approccio può migliorare le prestazioni delle query che fanno riferimento ai dati correlati tra partizioni.
Riconsiderare la chiave di partizione o se il partizionamento orizzontale soddisfa le proprie esigenze se il carico di lavoro richiede un'integrità transazionale avanzata attraverso i limiti delle partizioni. Le transazioni cross-shard presentano sfide. Protocolli di coordinamento distribuiti, ad esempio commit in due fasi, aggiunta di latenza, introduzione delle modalità di errore e riduzione della velocità effettiva. La maggior parte dei sistemi partizionati evita le transazioni distribuite e adotta invece la coerenza finale. In questo modello ogni partizione viene aggiornata in modo indipendente e l'applicazione gestisce incoerenze temporanee.
Assicurarsi che le risorse disponibili per ogni nodo di archiviazione di frammenti possano gestire i requisiti di scalabilità in termini di dimensioni e capacità di trasmissione dei dati. Per altre informazioni, vedere Strategie di partizionamento dei dati.
Prendere in considerazione di replicare i dati di riferimento in tutti i frammenti. Se una query su una partizione fa riferimento anche a dati statici o a spostamento lento, aggiungere questi dati alla partizione. L'applicazione può quindi recuperare tutti i dati per la query senza eseguire un round trip in un archivio dati separato.
Annotazioni
Se i dati di riferimento contenuti in più partizioni cambiano, il sistema deve sincronizzare queste modifiche in tutte le partizioni. Durante l'esecuzione di questa sincronizzazione può verificarsi un certo grado di incoerenza. Progettare le applicazioni per tollerare questa incoerenza.
I sistemi partizionati moltiplicano il carico operativo. Pianifica per queste considerazioni:
Monitoraggio: È necessario aggregare metriche e log in tutte le partizioni per ottenere una visualizzazione completa dell'integrità del sistema.
Backup e ripristino: È necessario eseguire il backup di ogni partizione in modo indipendente e progettare procedure di ripristino per mantenere la coerenza tra partizioni. Un ripristino temporizzato di una partizione può creare incoerenze con altre partizioni.
Modifiche dello schema: È necessario coordinare le modifiche DDL (Data Definition Language) in ogni partizione.
È possibile implementare queste attività usando script o altre soluzioni di automazione.
È possibile geolocare le partizioni per posizionare i dati nelle istanze dell'applicazione che lo usano. Questo approccio può migliorare le prestazioni, ma richiede una pianificazione aggiuntiva per le operazioni che devono accedere a più partizioni in posizioni diverse.
Quando usare questo modello
Suggerimento
Prima di progettare un livello di partizionamento orizzontale personalizzato, determinare quali responsabilità di partizionamento orizzontale sono già gestite dalla piattaforma dati. Alcuni servizi gestiscono completamente il partizionamento orizzontale. Ad esempio, Azure Cosmos DB distribuisce i dati tra partizioni fisiche, gestisce le divisioni e instrada le query senza coinvolgimento dell'applicazione. Altri servizi gestiscono parzialmente il partizionamento orizzontale. Ad esempio, il database SQL di Azure fornisce strumenti di database elastici per la gestione delle mappe shard e il routing dipendente dai dati, ma tu progetti la chiave shard e gestisci le operazioni di divisione. Usare il modello di partizionamento orizzontale quando si compila e si gestisce manualmente la logica di partizionamento orizzontale.
Usare questo modello quando:
Il volume di dati totale supera la capacità di archiviazione di una singola istanza del database e nessuna opzione di ridimensionamento verticale risolve il calo.
La velocità effettiva delle transazioni o la concorrenza delle query supera ciò che una singola istanza può sostenere e le repliche di lettura da sole non risolvono il collo di bottiglia perché anche il carico di scrittura è elevato.
Annotazioni
Il partizionamento orizzontale migliora le prestazioni e la scalabilità di un sistema e può anche migliorare la disponibilità. Un errore in una partizione non impedisce necessariamente a un'applicazione di accedere ai dati in altre partizioni. E un operatore può eseguire la manutenzione o il ripristino di una partizione senza rendere tutti i dati non disponibili. Per altre informazioni, vedere Indicazioni sul partizionamento dei dati.
I requisiti normativi o di conformità impongono che specifici subset di dati si trovino in giurisdizioni geografiche specifiche e che nessuna distribuzione a singola area possa soddisfare tutti i requisiti.
I tenant distinti o i segmenti dei clienti richiedono l'isolamento dei dati fisici per motivi di sicurezza, prestazioni o contrattuali.
In scenari come questi, il modello di partizionamento orizzontale viene talvolta applicato oltre gli archivi dati tradizionali. Ad esempio, un sistema di gestione della zona DNS può essere partizionato da team, ambiente o area per ridurre il raggio di esplosione delle modifiche DNS e stabilire limiti di proprietà chiari. In questo contesto, la motivazione principale è la segmentazione operativa anziché la scalabilità. Per altre informazioni, vedere Partizionamento orizzontale delle zone DNS private.
Il partizionamento orizzontale introduce una complessità sostanziale e permanente nell'architettura dei dati. Questa complessità influisce sullo sviluppo, le operazioni, i test, la progettazione delle query e il ripristino degli errori per la durata del sistema.
Questo modello potrebbe non essere adatto quando:
Il volume di dati e la velocità effettiva rientrano in una singola istanza del database, anche con una crescita prevista. La scalabilità verticale mantiene la semplicità delle query e l'integrità transazionale.
Il collo di bottiglia è il volume di lettura, non il volume di scrittura o la capacità di archiviazione. Le repliche di lettura e i livelli di memorizzazione nella cache possono scaricare il traffico di lettura senza la complessità delle query tra partizioni introdotta dal sharding.
Il motore di database supporta il partizionamento a livello di tabella che soddisfa le esigenze di prestazioni. Il partizionamento all'interno di una singola istanza non richiede più server o logica di routing.
I modelli di query principali richiedono join tra più entità, transazioni multientità o aggregazioni di dataset completo. Il partizionamento orizzontale rende queste operazioni costose e il sovraccarico delle query di fan-out e del coordinamento distribuito può superare i vantaggi di ridimensionamento.
Progettazione del carico di lavoro
Valutare come usare il modello di partizionamento orizzontale nella progettazione di un carico di lavoro per soddisfare gli obiettivi e i principi trattati nei pilastri di Azure Well-Architected Framework. La tabella seguente fornisce indicazioni su come questo modello supporta gli obiettivi di ogni pilastro.
| Pilastro | Come questo modello supporta gli obiettivi di pilastro |
|---|---|
| decisioni di progettazione dell'affidabilità consentono al carico di lavoro di diventare resiliente a un malfunzionamento e assicurano che ripristini a uno stato completamente funzionante dopo che si verifica un guasto. | I dati e l'elaborazione sono isolati nella partizione, quindi un malfunzionamento in una partizione rimane isolato in tale partizione. - Partizionamento dei dati - RE:07 Autoconservazione |
| L'ottimizzazione dei costi è incentrata sul mantenimento e sul miglioramento del ritorno del carico di lavoro sugli investimenti. | Un sistema che implementa le partizioni spesso trae vantaggio dall'uso di più istanze di risorse di calcolo o archiviazione meno costose anziché da una singola risorsa più costosa. In molti casi, questa configurazione può risparmiare denaro. - Costi dei componenti CO:07 |
| l'efficienza delle prestazioni consente al carico di lavoro soddisfare in modo efficiente le richieste tramite ottimizzazioni di ridimensionamento, dati e codice. | Quando si usa il partizionamento orizzontale nella strategia di ridimensionamento, i dati e l'elaborazione sono isolati per ogni partizione, quindi le richieste competono solo per le risorse all'interno della partizione assegnata. È anche possibile usare il partizionamento orizzontale per ottimizzare in base all'area geografica. - PE:05 Ridimensionamento e partizionamento - Prestazioni dei dati PE:08 |
Se questo modello introduce compromessi all'interno di un pilastro, considerarli contro gli obiettivi degli altri pilastri.
Esempio
Si consideri un sito Web che espone una vasta raccolta di informazioni sui libri pubblicati in tutto il mondo. Il numero di libri possibili catalogati in questo carico di lavoro e i modelli di utilizzo e query tipici superano ciò che un singolo database relazionale può gestire. L'architetto del carico di lavoro decide di partizionare i dati in più istanze di database usando il codice ISBN statico dei libri come chiave di partizione. In particolare, l'architetto usa la cifra di spunta (0 - 10) del codice ISBN, che fornisce 11 possibili partizioni logiche con distribuzione dei dati abbastanza bilanciata.
Per iniziare, l'architetto coloca le 11 partizioni logiche in tre database di partizioni fisiche. In questo approccio di partizione virtuale, molte partizioni logiche eseguono il mapping a un minor numero di nodi fisici. L'architetto utilizza l'approccio di sharding per la ricerca e memorizza il mapping chiave-server in un database della mappa shard.
Il servizio app di Azure è etichettato come sito web del catalogo di libri. Si connette a più istanze del database SQL e a un'istanza di Ricerca di intelligenza artificiale di Azure. Uno dei database viene etichettato come database ShardMap. Include una tabella di esempio che rispecchia una parte della tabella di mapping, elencata più avanti in questo articolo. La tabella include tre istanze di database shard: bookdbshard0, bookdbshard1 e bookdbshard2. Gli altri database includono elenchi di esempi identici delle tabelle sottostanti. Le tabelle includono Books, LibraryOfCongressCatalog e un indicatore di più tabelle. Ricerca AI è utilizzata per la navigazione a faccette e la ricerca nei siti. L'identità gestita è associata al servizio app.
Mappa partizioni di ricerca
Il database della mappa dei frammenti contiene la seguente tabella di mapping e dati.
SELECT ShardKey, DatabaseServer
FROM BookDataShardMap
| ShardKey | DatabaseServer |
|----------|----------------|
| 0 | bookdbshard0 |
| 1 | bookdbshard0 |
| 2 | bookdbshard0 |
| 3 | bookdbshard1 |
| 4 | bookdbshard1 |
| 5 | bookdbshard1 |
| 6 | bookdbshard2 |
| 7 | bookdbshard2 |
| 8 | bookdbshard2 |
| 9 | bookdbshard0 |
| 10 | bookdbshard1 |
Codice del sito Web di esempio: accesso a partizione singola
Il sito Web non è a conoscenza del numero di database di partizioni fisici esistenti (tre in questo caso) o della logica che esegue il mapping di una chiave di partizione a un'istanza del database. Sa solo che la cifra di controllo del codice ISBN di un libro è la chiave di partizione. Il sito Web ha accesso in sola lettura al database della mappa partizioni e all'accesso in lettura/scrittura a tutti i database partizioni. In questo esempio il sito Web usa l'identità gestita dal sistema dell'host del servizio app di Azure per l'autorizzazione, che mantiene i segreti fuori dalle stringhe di connessione.
Il sito web è configurato con le seguenti stringhe di connessione, presenti in un file appsettings.json, come illustrato in questo esempio, oppure attraverso le impostazioni dell'app di App Service.
{
...
"ConnectionStrings": {
"ShardMapDb": "Data Source=tcp:<database-server-name>.database.windows.net,1433;Initial Catalog=ShardMap;Authentication=Active Directory Default;App=Book Site v1.5a",
"BookDbFragment": "Data Source=tcp:SHARD.database.windows.net,1433;Initial Catalog=Books;Authentication=Active Directory Default;App=Book Site v1.5a"
},
...
}
Il codice seguente illustra come il sito Web esegue una query di aggiornamento sul pool di partizioni del database del carico di lavoro.
...
// All data for this book is stored in a shard based on the book's ISBN check digit,
// which is converted to an integer 0 - 10 (special value 'X' becomes 10).
int isbnCheckDigit = book.Isbn.CheckDigitAsInt;
// Establish a pooled connection to the database shard for this specific book.
using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: isbnCheckDigit, cancellationToken))
{
// Update the book's Library of Congress catalog information.
SqlCommand cmd = sqlConn.CreateCommand();
cmd.CommandText = @"UPDATE LibraryOfCongressCatalog
SET ControlNumber = @lccn,
...
Classification = @lcc
WHERE BookID = @bookId";
cmd.Parameters.AddWithValue("@lccn", book.LibraryOfCongress.Lccn);
...
cmd.Parameters.AddWithValue("@lcc", book.LibraryOfCongress.Lcc);
cmd.Parameters.AddWithValue("@bookId", book.Id);
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
...
Nel codice di esempio precedente, se book.Isbn era 978-8-1130-1024-6, isbnCheckDigit allora dovrebbe essere 6. La OpenShardConnectionForKeyAsync(6) chiamata viene in genere implementata usando un approccio cache-aside. Se le informazioni sulla partizione memorizzate nella cache per la chiave partizione 6 non sono disponibili, il metodo esegue una query sul database della mappa partizioni identificato dalla ShardMapDb stringa di connessione. Il metodo recupera il valore bookdbshard2 dalla cache dell'applicazione o dal database di shard e lo sostituisce a SHARD nella stringa di connessione BookDbFragment. Il metodo stabilisce o riestablisa una connessione in pool a bookdbshard2.database.windows.net, la apre e la restituisce al codice chiamante. Il codice aggiorna quindi il record esistente nell'istanza del database.
Codice del sito Web di esempio: accesso a più partizioni
Nel raro caso in cui il sito web richiede una query diretta tra frammenti, l'applicazione esegue una query di fan-out parallela in tutti i frammenti.
...
// Retrieve all shard keys.
var shardKeys = shardedDatabaseConnections.GetAllShardKeys();
// Run the query in a fan-out style against each shard in the shard list.
Parallel.ForEachAsync(shardKeys, async (shardKey, cancellationToken) =>
{
using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: shardKey, cancellationToken))
{
SqlCommand cmd = sqlConn.CreateCommand();
cmd.CommandText = @"SELECT ...
FROM ...
WHERE ...";
SqlDataReader reader = await cmd.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
// Collect the results into a thread-safe data structure.
}
reader.Close();
}
});
...
In alternativa alle query tra partizioni, questo carico di lavoro può usare un indice gestito esternamente in Azure Ricerca AI per la ricerca di siti o la navigazione con faccette.
Aggiungere istanze di partizione
Il team del carico di lavoro sa che se il catalogo dati o il relativo utilizzo simultaneo aumenta in modo significativo, potrebbero richiedere più di tre istanze di database. Il team del carico di lavoro non si aspetta di aggiungere server di database in modo dinamico e accetta tempi di inattività del carico di lavoro quando viene online una nuova partizione. Per portare online una nuova istanza di partizione, è necessario spostare i dati dalle partizioni esistenti alla nuova partizione e aggiornare la tabella della mappa partizioni. Con questo approccio abbastanza statico, il workload può memorizzare nella cache il mapping del database delle chiavi di shard nel codice del sito.
La logica della chiave di partizione in questo esempio ha un limite massimo di 11 partizioni fisiche. Se il team del carico di lavoro determina attraverso la stima del carico che alla fine richiede più di 11 istanze di database, deve apportare una modifica invasiva alla logica della chiave di partizione. Questa modifica comporta un'attenta pianificazione delle modifiche del codice e della migrazione dei dati alla nuova logica chiave.
Funzionalità dell'SDK
Anziché scrivere codice personalizzato per la gestione delle partizioni e il routing delle query alle istanze di SQL Database, valutare la libreria client del database elastico. Questa libreria supporta la gestione delle mappe di partizioni, il routing delle query dipendenti dai dati e le query tra partizioni in C# e Java.
Passo successivo
- Livelli di coerenza in Azure Cosmos DB: la distribuzione dei dati tra partizioni introduce compromessi di coerenza. Questo articolo descrive lo spettro dei modelli di coerenza, da forte a finale e i relativi effetti sulla disponibilità e la latenza.
Risorse correlate
- Partizionamento orizzontale, verticale e funzionale dei dati: questo articolo descrive altre strategie per il partizionamento dei dati nel cloud per migliorare la scalabilità, ridurre i conflitti e ottimizzare le prestazioni.
- Modello di tabella dell'indice: a volte non è possibile supportare tutte le query solo tramite la progettazione della chiave di partizione. Un'applicazione può usare il modello Index Table per recuperare dati da un archivio dati di grandi dimensioni specificando una chiave diversa dalla chiave di partizione.
- Modello vista materializzata: per mantenere le prestazioni di alcune operazioni di query, è possibile creare viste materializzate che aggregano e riepilogino i dati, soprattutto se si distribuiscono tali dati tra partizioni.