Progettare una strategia di partizionamento scalabile per l'archiviazione tabelle di Azure

Questo articolo illustra il partizionamento di una tabella nell'archiviazione tabelle di Azure e le strategie che è possibile usare per garantire una scalabilità efficiente.

Azure offre archiviazione cloud a disponibilità elevata e altamente scalabile. Il sistema di archiviazione sottostante per Azure viene fornito tramite un set di servizi, tra cui Archiviazione BLOB di Azure, Archiviazione tabelle di Azure, Archiviazione code di Azure e File di Azure.

Archiviazione tabelle di Azure è progettata per archiviare i dati strutturati. Il servizio archiviazione di Azure supporta un numero illimitato di tabelle. Ogni tabella può essere ridimensionata a livelli di grandi dimensioni e fornire terabyte di archiviazione fisica. Per sfruttare al meglio le tabelle, è necessario partizionare i dati in modo ottimale. Questo articolo illustra le strategie che è possibile usare per partizionare in modo efficiente i dati per l'archiviazione tabelle di Azure.

Entità di tabella

Le entità di tabella rappresentano le unità di dati archiviate in una tabella. Le entità di tabella sono simili alle righe in una tipica tabella di database relazionale. Ogni entità definisce una raccolta di proprietà. Ogni proprietà viene definita come coppia chiave/valore in base al nome, al valore e al tipo di dati del valore. Le entità devono definire le tre proprietà di sistema seguenti come parte della raccolta di proprietà:

  • PartitionKey: la proprietà PartitionKey archivia i valori stringa che identificano la partizione a cui appartiene un'entità. Le partizioni, come illustrato più avanti, sono integrali alla scalabilità della tabella. Le entità con lo stesso valore PartitionKey vengono archiviate nella stessa partizione.

  • RowKey: la proprietà RowKey archivia i valori stringa che identificano in modo univoco le entità all'interno di ogni partizione. PartitionKey e RowKey formano la chiave primaria per l'entità.

  • Timestamp: la proprietà Timestamp fornisce la tracciabilità per un'entità. Timestamp è un valore di data/ora che indica l'ultima volta che l'entità è stata modificata. Un timestamp viene talvolta definito come versione dell'entità. Le modifiche ai timestamp vengono ignorate perché il servizio tabelle mantiene il valore per questa proprietà durante tutte le operazioni di inserimento e aggiornamento.

Chiave primaria tabella

La chiave primaria per un'entità di Azure è costituita dalle proprietà PartitionKey e RowKey combinate. Le due proprietà formano un singolo indice cluster all'interno della tabella. Le proprietà PartitionKey e RowKey possono archiviare fino a 1 KiB di valori stringa. Sono consentite anche stringhe vuote; tuttavia, i valori Null non sono consentiti.

L'indice cluster ordina in base a PartitionKey in ordine crescente e quindi in ordine crescente di RowKey . L'ordinamento è rispettato in tutte le risposte di query. Durante l'operazione di ordinamento sono usati i confronti lessicali. Un valore stringa "111" viene visualizzato prima di un valore stringa "2". In alcuni casi, potrebbe essere necessario che l'ordine di ordinamento sia numerico. Per ordinare in un ordine numerico e crescente, è necessario usare stringhe a lunghezza fissa e con spaziatura zero. Nell'esempio precedente viene visualizzato "002" prima di "111".

Partizioni della tabella

Le partizioni rappresentano una raccolta di entità con gli stessi valori PartitionKey . Le partizioni vengono sempre gestite da un server di partizione. Ogni server di partizione può servire una o più partizioni. A un server partizione è applicato un limite di velocità per il numero di entità che possono essere servite da una partizione nel tempo. In particolare, una partizione ha una destinazione di scalabilità di 2000 entità al secondo. Questa velocità effettiva potrebbe essere maggiore durante il carico minimo nel nodo di archiviazione, ma è limitata quando il nodo diventa caldo o attivo.

Per illustrare meglio il concetto di partizionamento, la figura seguente mostra una tabella contenente un piccolo subset di dati per le registrazioni degli eventi di gara di piè di pagina. La figura presenta una visualizzazione concettuale del partizionamento in cui PartitionKey contiene tre valori diversi: il nome dell'evento combinato con tre distanze (maratona completa, mezza maratona e 10 km). In questo esempio vengono usati due server di partizione. Server A contiene registrazioni per le distanze di mezza maratona e 10 km. Server B contiene solo le distanze full-marathon. I valori RowKey vengono visualizzati per fornire il contesto, ma i valori non sono significativi per questo esempio.

Diagramma che mostra una tabella con tre partizioni
Tabella con tre partizioni

Scalabilità

Poiché una partizione è sempre servita da un singolo server partizione e ogni server partizione può servire una o più partizioni, l'efficienza delle entità corrispondenti è correlata all'integrità del server. I server che riscontrano un traffico elevato per le partizioni potrebbero non essere in grado di sostenere una velocità effettiva elevata. Ad esempio, nella figura precedente, se molte richieste per "2011 New York City Marathon__Half" vengono ricevute, il server A potrebbe diventare troppo frequente. Per aumentare la velocità effettiva del server, il sistema di archiviazione applica il bilanciamento del carico delle partizioni su altri server. Il traffico sarà quindi distribuito in molti altri server. Per il bilanciamento del carico ottimale del traffico, è consigliabile usare più partizioni in modo che l'archiviazione tabelle di Azure possa distribuire le partizioni a più server di partizione.

Transazioni di gruppi di entità

Una transazione del gruppo di entità è un set di operazioni di archiviazione implementate atomicamente nelle entità con lo stesso valore PartitionKey . Se un'operazione di archiviazione nel gruppo di entità ha esito negativo, tutte le operazioni di archiviazione nell'entità vengono eseguito il rollback. Una transazione del gruppo di entità è costituita da non più di 100 operazioni di archiviazione e potrebbe non essere superiore a 4 MiB di dimensioni. Le transazioni del gruppo di entità forniscono archiviazione tabelle di Azure con una forma limitata della semantica atomica, coerenza, isolamento e durabilità (ACID) fornita dai database relazionali.

Le transazioni del gruppo di entità migliorano la velocità effettiva perché riducono il numero di singole operazioni di archiviazione che devono essere inviate all'archiviazione tabelle di Azure. Le transazioni del gruppo di entità offrono anche un vantaggio economico. Una transazione del gruppo di entità viene fatturata come singola operazione di archiviazione indipendentemente dal numero di operazioni di archiviazione contenute. Poiché tutte le operazioni di archiviazione in una transazione del gruppo di entità influiscono sulle entità con lo stesso valore PartitionKey , è necessario usare le transazioni del gruppo di entità che possono guidare la selezione del valore PartitionKey .

Partizioni di intervallo

Se si usano valori PartitionKey univoci per le entità, ogni entità appartiene alla propria partizione. Se i valori univoci usati aumentano o riducono il valore, è possibile che Azure creerà partizioni di intervallo. Entità del gruppo di partizioni di intervallo con valori PartitionKey sequenziali e univoci per migliorare le prestazioni delle query di intervallo. Senza partizioni di intervallo, una query di intervallo deve superare i limiti di partizione o i limiti del server, che possono ridurre le prestazioni delle query. Si consideri un'applicazione che usa la tabella seguente, che ha un valore di sequenza crescente per PartitionKey:

PartitionKey RowKey
"0001" -
"0002" -
"0003" -
"0004" -
"0005" -
"0006" -

Azure potrebbe raggruppare le prime tre entità in una partizione di intervallo. Se si applica una query di intervallo alla tabella che usa PartitionKey come criteri e richieste entità da "0001" a "0003", la query potrebbe essere eseguita in modo efficiente perché le entità vengono gestite da un singolo server di partizione. Non esiste alcuna garanzia quando e come verrà creata una partizione di intervallo.

L'esistenza di partizioni di intervallo per la tabella può influire sulle prestazioni delle operazioni di inserimento se si inseriscono entità che hanno valori PartitionKey crescenti o decrescente. L'inserimento di entità con valori PartitionKey crescenti viene chiamato modello di sola accodamento. L'inserimento di entità con valori decrescente viene chiamato modello di solo prepend. Si consideri di non usare questi tipi di modelli perché la velocità effettiva complessiva delle richieste di inserimento è limitata da un singolo server di partizione. Questo perché, se esistono partizioni di intervallo, le partizioni first e last (range) contengono rispettivamente i valori di PartitionKey minimi e maggiori. Pertanto, l'inserimento di una nuova entità, una che ha un valore PartitionKey più basso o superiore in sequenza, è destinato a una delle partizioni finali. Nella figura seguente viene illustrato un possibile set di partizioni di intervallo basate sull'esempio precedente. Se sono state inserite entità "0007", "0008" e "0009", verranno assegnate all'ultima partizione (arancione).

Diagramma che mostra un set di partizioni di intervallo
Set di partizioni di intervallo

È importante notare che non esiste alcun effetto negativo sulle prestazioni se le operazioni di inserimento usano valori PartitionKey più a dispersione.

Analizzare i dati

A differenza di una tabella in un database relazionale che è possibile usare per gestire gli indici, le tabelle nell'archiviazione tabelle di Azure possono avere un solo indice. Un indice nell'archiviazione tabelle di Azure è sempre costituito dalle proprietà PartitionKey e RowKey .

In una tabella di Azure non è disponibile il lusso di ottimizzazione delle prestazioni della tabella aggiungendo altri indici o modificando una tabella esistente dopo l'implementazione. È necessario analizzare i dati durante la progettazione della tabella. Gli aspetti più importanti da considerare per la scalabilità ottimale e per l'efficienza di query e inserimento sono i valori PartitionKey e RowKey . Questo articolo sottolinea come scegliere PartitionKey perché si riferisce direttamente alla modalità di partizionamento delle tabelle.

Dimensionamento della partizione

Il dimensionamento di una partizione fa riferimento al numero di entità incluse in una partizione. Come illustrato in Scalabilità, avere più partizioni significa migliorare il bilanciamento del carico. La granularità del valore PartitionKey influisce sulle dimensioni delle partizioni. A livello grossolano, se un singolo valore viene usato come PartitionKey, tutte le entità si trovano in una singola partizione molto grande. Al livello più elevato di granularità, PartitionKey può contenere valori univoci per ogni entità. Il risultato è che è presente una partizione per ogni entità. La tabella seguente illustra i vantaggi e gli svantaggi per l'intervallo di granularità:

Granularità partitionKey Dimensioni della partizione Vantaggi Svantaggi
Valore singolo Numero ridotto di entità. Le transazioni batch sono possibili con qualsiasi entità.

Tutte le entità sono locali e gestite dallo stesso nodo di archiviazione.
Valore singolo Numero elevato di entità. Le transazioni del gruppo di entità potrebbero essere possibili con qualsiasi entità. Per altre informazioni sui limiti delle transazioni del gruppo di entità, vedere Esecuzione di transazioni del gruppo di entità. Scalabilità limitata.

Velocità effettiva limitata alle prestazioni di un singolo server.
Più valori Più partizioni

Le dimensioni delle partizioni dipendono dalla distribuzione delle entità.
Le transazioni batch sono possibili in alcune entità.

È possibile partizionamento dinamico.

Le query a richiesta singola sono possibili (nessun token di continuazione).

Il bilanciamento del carico tra più server di partizione è possibile.
Una distribuzione altamente irregolare delle entità tra partizioni potrebbe limitare le prestazioni delle partizioni più grandi e più attive.
Valori univoci Molte piccole partizioni La tabella è altamente scalabile.

Le partizioni di intervallo potrebbero migliorare le prestazioni delle query tra intervalli di partizioni.
Le query che coinvolgono intervalli potrebbero richiedere visite a più di un server.

Transazioni batch non possibili.

I modelli di sola aggiunta o prepend-only potrebbero influire sulla velocità effettiva di inserimento.

La tabella mostra come il ridimensionamento è interessato dai valori PartitionKey . È consigliabile favorire partizioni più piccole perché offrono un migliore bilanciamento del carico. Le partizioni più grandi potrebbero essere appropriate in alcuni scenari e non sono necessariamente svantaggiate. Ad esempio, se l'applicazione non richiede scalabilità, una singola partizione di grandi dimensioni potrebbe essere appropriata.

Determinare le query

Le query recuperano dati dalle tabelle. Quando si analizzano i dati per una tabella nell'archiviazione tabelle di Azure, è importante considerare quali query verranno usate dall'applicazione. Se un'applicazione ha diverse query, potrebbe essere necessario assegnarle priorità, anche se le decisioni potrebbero essere soggettive. In molti casi, le query dominanti sono individuabili da altre query. A livello di prestazioni, le query rientrano in diverse categorie. Poiché una tabella ha un solo indice, le prestazioni delle query in genere sono correlate alle proprietà PartitionKey e RowKey . La tabella seguente illustra i diversi tipi di query e le relative classificazioni delle prestazioni:

Tipo di query Corrispondenza di PartitionKey Corrispondenza rowkey Classificazione delle prestazioni
Analisi intervallo righe Exact Partial Meglio con partizioni di dimensioni inferiori.

Non è valido con le partizioni molto grandi.
Analisi intervallo partizioni Partial Partial Buono con un numero ridotto di server di partizione che vengono toccati.

Peggio con più server toccati.
Analisi completa tabella Parziale, nessuna Parziale, nessuna Peggio con un subset di partizioni analizzati.

Peggiore con tutte le partizioni analizzate.

Nota

La tabella definisce le valutazioni reciproche delle prestazioni. Il numero e le dimensioni delle partizioni potrebbero determinare in definitiva la modalità di esecuzione della query. Ad esempio, un'analisi dell'intervallo di partizione per una tabella con molte partizioni di grandi dimensioni potrebbe essere eseguita male rispetto a un'analisi completa della tabella con alcune partizioni di piccole dimensioni.

I tipi di query elencati nella tabella precedente mostrano una progressione dai tipi migliori di query da usare ai tipi peggiori, in base alle classificazioni delle prestazioni. Le query di tipo punto sono le query migliori da usare, poiché usano al meglio l'indice cluster della tabella. La query di punto seguente usa i dati della tabella di registrazione delle gare di piedi:

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)  
  

Se l'applicazione usa più query, non tutte le query potranno essere query di tipo punto. A livello di prestazioni, le query di intervallo seguono le query di tipo punto. Esistono due tipi di query di intervallo: l'analisi dell'intervallo di righe e l'analisi dell'intervallo di partizione. L'analisi dell'intervallo di righe specifica una singola partizione. Poiché l'operazione si verifica in un singolo server di partizione, le analisi dell'intervallo di righe sono in genere più efficienti rispetto alle analisi dell'intervallo di partizioni. Tuttavia, un fattore chiave nelle prestazioni delle analisi dell'intervallo di righe è il modo in cui una query è selettiva. che determina il numero di righe da scorrere per individuare le righe corrispondenti. Le query più selettive sono più efficienti durante le analisi dell'intervallo di righe.

Per valutare le priorità delle query, considerare i requisiti di frequenza e tempo di risposta per ogni query. È possibile che le query eseguite di frequente siano più elevate. Tuttavia, una query importante ma raramente usata potrebbe avere requisiti di bassa latenza che potrebbero classificarlo più alto nell'elenco di priorità.

Scegliere il valore PartitionKey

Il core della progettazione di qualsiasi tabella è la scalabilità, le query usate per accedervi e i requisiti dell'operazione di archiviazione. I valori PartitionKey scelti determinano la modalità di partizionamento di una tabella e il tipo di query che è possibile usare. Le operazioni di archiviazione e soprattutto gli inserimenti potrebbero influire sulla scelta dei valori PartitionKey . I valori PartitionKey possono variare da valori singoli a valori univoci. Possono anche essere creati usando più valori. È possibile usare le proprietà dell'entità per formare il valore PartitionKey . In alternativa, l'applicazione può calcolare il valore. Le sezioni seguenti illustrano considerazioni importanti.

Transazioni di gruppi di entità

Gli sviluppatori devono prima considerare se l'applicazione userà transazioni del gruppo di entità (aggiornamenti batch). Le transazioni del gruppo di entità richiedono che le entità abbiano lo stesso valore PartitionKey . Inoltre, poiché gli aggiornamenti batch sono per un intero gruppo, le scelte dei valori PartitionKey potrebbero essere limitate. Ad esempio, un'applicazione in ambito bancario che gestisce le transazioni in contanti deve inserire automaticamente le transazioni in contanti nella tabella. Le transazioni di cassa rappresentano sia il debito che i lati di credito e devono essere netti a zero. Questo requisito significa che il numero di account non può essere usato come parte del valore PartitionKey perché ogni lato della transazione usa numeri di account diversi. Invece, un ID transazione potrebbe essere una scelta migliore.

Partizioni

I numeri di partizione e le dimensioni influiscono sulla scalabilità di una tabella in fase di caricamento. Sono controllati anche dal modo in cui i valori PartitionKey sono granulari. Può essere difficile determinare PartitionKey in base alle dimensioni della partizione, soprattutto se la distribuzione dei valori è difficile da prevedere. È in genere consigliabile usare più partizioni di dimensioni ridotte. Molte partizioni di tabella semplificano l'archiviazione tabelle di Azure per gestire i nodi di archiviazione da cui vengono gestite le partizioni.

La scelta di valori univoci o più fine per PartitionKey comporta una dimensione più piccola ma maggiore di partizioni. Ciò è generalmente favorevole perché il sistema può bilanciare il carico delle molte partizioni per distribuire il carico tra molte partizioni. È tuttavia consigliabile valutare l'effetto della presenza di più partizioni sulle query di intervallo tra partizioni. Questi tipi di query devono visitare più partizioni per soddisfare una query. È possibile che le partizioni vengano distribuite in molti server di partizione. Se la query attraversa un limite di server, dovranno essere restituiti token di continuazione, I token di continuazione specificano i valori PartitionKey o RowKey successivi per recuperare il set successivo di dati per la query. In altre parole, i token di continuazione rappresentano almeno una richiesta al servizio, che può ridurre le prestazioni complessive della query.

La selettività della query è un altro fattore che può influire sulle prestazioni della query e rappresenta una misura del numero di query da scorrere per ogni partizione. La query più selettiva è, più efficiente è la query che restituisce le righe desiderate. Le prestazioni complessive delle query di intervallo possono dipendere dal numero di server di partizione che devono essere toccati o dal modo in cui è selettiva la query. È anche consigliabile evitare di usare i modelli di sola aggiunta o prepend-only quando si inseriscono i dati nella tabella. Se si usano questi modelli, nonostante la creazione di piccole e molte partizioni, è possibile limitare la velocità effettiva delle operazioni di inserimento. I modelli di sola accodamento e prepend-only vengono illustrati nelle partizioni Range.

Query

Conoscere le query usate consente di determinare quali proprietà sono importanti da considerare per il valore PartitionKey . Le proprietà usate nelle query sono candidati per il valore PartitionKey . La tabella seguente fornisce una linea guida generale su come determinare il valore PartitionKey :

Se l'entità… Azione
Include una proprietà chiave Usarlo come PartitionKey.
Include due proprietà chiave Usare una come PartitionKey e l'altra come RowKey.
Include più di due proprietà chiave Usare una chiave composita di valori concatenati.

Se è presente più di una query altrettanto dominante, è possibile inserire più volte le informazioni usando valori RowKey diversi necessari. L'applicazione gestirà righe secondarie (o terziarie) e così via. È possibile usare questo tipo di modello per soddisfare i requisiti di prestazioni delle query. Nell'esempio seguente vengono usati i dati dell'esempio di registrazione della gara di piè di pagina. Dispone di due query dominanti:

  • Query in base al numero di pettorina
  • Query in base all'età

Per servire entrambe le query dominanti, inserire due righe come transazioni dei gruppi di entità. Nella tabella seguente vengono illustrate le proprietà PartitionKey e RowKey per questo scenario. I valori RowKey forniscono un prefisso per la bib e l'età in modo che l'applicazione possa distinguere tra i due valori.

PartitionKey RowKey
2011 New York City Marathon__Full BIB:01234__John__M__55
2011 New York City Marathon__Full AGE:055__1234__John__M

In questo esempio è possibile una transazione di gruppo di entità perché i valori PartitionKey sono uguali. La transazione del gruppo fornisce l'atomicità dell'operazione di inserimento. Anche se è possibile usare questo modello con valori PartitionKey diversi, è consigliabile usare gli stessi valori per ottenere questo vantaggio. In caso contrario, potrebbe essere necessario scrivere logica aggiuntiva per garantire che le transazioni atomiche usino valori PartitionKey diversi.

Operazioni di archiviazione

Le tabelle nell'archiviazione tabelle di Azure potrebbero verificarsi non solo da query. Potrebbero anche verificarsi carichi da operazioni di archiviazione come inserimenti, aggiornamenti ed eliminazioni. Prendere in considerazione il tipo di operazioni di archiviazione eseguite nella tabella e a quale frequenza. Se si eseguono queste operazioni raramente, potrebbe non essere necessario preoccuparsi di esse. Tuttavia, per operazioni frequenti come l'esecuzione di molti inserimenti in breve tempo, è necessario considerare il modo in cui tali operazioni vengono gestite come risultato dei valori PartitionKey scelti. Esempi importanti sono i modelli di sola accodamento e prepend-only. I modelli di sola accodamento e prepend-only vengono illustrati nelle partizioni Range.

Quando si usa un modello di sola accodamento o prepend-only, si usano valori in aumento o decrescente univoci per PartitionKey negli inserimenti successivi. Se si combina questo modello con operazioni di inserimento frequenti, la tabella non sarà in grado di gestire le operazioni di inserimento con grande scalabilità. La scalabilità della tabella è interessata perché Azure non riesce a bilanciare il carico delle richieste di operazione ad altri server di partizione. In questo caso, potrebbe essere consigliabile usare valori casuali, ad esempio valori GUID. Le dimensioni delle partizioni possono quindi rimanere ridotte e mantenere comunque il bilanciamento del carico durante le operazioni di archiviazione.

Test di stress della partizione tabella

Quando il valore PartitionKey è complesso o richiede confronti con altri mapping PartitionKey , potrebbe essere necessario testare le prestazioni della tabella. Il test deve esaminare le prestazioni di una partizione in caso di picchi di carico.

Per eseguire un test di stress

  1. Creare una tabella di test.
  2. Caricare la tabella di test con dati in modo che contenga entità con il valore PartitionKey di destinazione.
  3. Usare l'applicazione per simulare il carico di picco nella tabella. Destinazione di una singola partizione usando il valore PartitionKey dal passaggio 2. Questo passaggio è diverso per ogni applicazione, ma la simulazione deve includere tutte le query e le operazioni di archiviazione necessarie. Potrebbe essere necessario modificare l'applicazione in modo che sia destinata a una singola partizione.
  4. Esaminare la velocità effettiva delle operazioni GET o PUT sulla tabella.

Per esaminare la velocità effettiva, confrontare i valori effettivi rispetto al limite specificato di una singola partizione in un singolo server. Le partizioni sono limitate a 2000 entità al secondo. Se la velocità effettiva supera 2000 entità al secondo per una partizione, il server potrebbe essere eseguito troppo caldo in un'impostazione di produzione. In questo caso, i valori PartitionKey potrebbero essere troppo grossolani, in modo che non siano presenti partizioni sufficienti o che le partizioni siano troppo grandi. Potrebbe essere necessario modificare il valore PartitionKey in modo che le partizioni vengano distribuite tra più server.

Bilanciamento del carico

Il bilanciamento del carico al livello di partizione si verifica quando una partizione viene troppo calda. Quando una partizione è troppo calda, la partizione, in particolare il server di partizione, opera oltre la scalabilità di destinazione. Per l'archiviazione di Azure, ogni partizione ha una destinazione di scalabilità di 2000 entità al secondo. Il bilanciamento del carico si verifica anche nel livello DFS (Distributed File System).

Il bilanciamento del carico al livello DFS gestisce il carico di I/O ed è esterno all'ambito di questo articolo. Il bilanciamento del carico al livello di partizione non si verifica immediatamente dopo il superamento della destinazione di scalabilità. Il sistema attende invece alcuni minuti prima di iniziare il processo di bilanciamento del carico. in modo da assicurare che il carico della partizione sia effettivamente eccessivo. Non è necessario prime partizioni con carico generato che attiva il bilanciamento del carico perché il sistema esegue automaticamente l'attività.

Se una tabella è stata attivata con un determinato carico, il sistema potrebbe essere in grado di bilanciare le partizioni in base al carico effettivo, che comporta una distribuzione significativamente diversa delle partizioni. Invece di partizioni di priming, prendere in considerazione la scrittura di codice che gestisce il timeout e gli errori occupato dal server. Gli errori vengono restituiti quando il sistema esegue il bilanciamento del carico. Gestendo questi errori usando una strategia di ripetizione dei tentativi, l'applicazione può gestire meglio i carichi di picco. Le strategie di ripetizione dei tentativi sono illustrate in modo più dettagliato nella sezione successiva.

Quando si verifica il bilanciamento del carico, la partizione diventa offline per alcuni secondi. Durante il periodo offline, il sistema riassegna la partizione a un server di partizione diverso. È importante notare che i dati non vengono archiviati dai server di partizione. che serve invece le entità dal livello DFS. Poiché i dati non vengono archiviati a livello di partizione, lo spostamento delle partizioni in server diversi è un processo rapido. Questa flessibilità limita notevolmente il tempo di inattività, se presente, che l'applicazione potrebbe riscontrare.

Strategia di ripetizione dei tentativi

È importante che l'applicazione gestisca gli errori delle operazioni di archiviazione per garantire che non si perdano aggiornamenti dei dati. Alcuni errori non richiedono una strategia di ripetizione dei tentativi. Ad esempio, gli aggiornamenti che restituiscono un errore 401 Non autorizzato non traggono vantaggio dalla ripetizione dell'operazione perché è probabile che lo stato dell'applicazione non cambierà tra i tentativi che risolvono l'errore 401. Tuttavia, gli errori come Server Occupato o Timeout sono correlati alle funzionalità di bilanciamento del carico di Azure che offrono scalabilità delle tabelle. Quando i nodi di archiviazione che servono le entità diventano ad accesso frequente, Azure bilancia il carico spostando le partizioni in altri nodi. Durante questo periodo, la partizione potrebbe essere inaccessibile, che genera errori di timeout o occupato dal server. Alla fine, la partizione viene riabilitabile e gli aggiornamenti riprendono.

Una strategia di ripetizione dei tentativi è appropriata per gli errori di timeout o occupato dal server. Nella maggior parte dei casi, è possibile escludere errori a livello di 400 e alcuni errori a livello di 500 dalla logica di ripetizione dei tentativi. Gli errori che possono essere esclusi includono 501 Non implementato e 505 versione HTTP non supportata. È quindi possibile implementare una strategia di ripetizione dei tentativi per un massimo di 500 errori di livello, ad esempio Server Occupato (503) e Timeout (504).

È possibile scegliere tra tre strategie comuni di ripetizione dei tentativi per l'applicazione:

  • Nessun tentativo: non viene eseguito alcun tentativo.
  • Correzione del backoff: l'operazione viene ritentata N volte con un valore backoff costante.
  • Backoff esponenziale: l'operazione viene ritentata N volte con un valore di backoff esponenziale.

La strategia di tipo nessun tentativo è un modo semplice ed evasivo di gestire gli errori delle operazioni, Tuttavia, una strategia no retry non è molto utile. Non imporre la ripetizione di tentativi pone un ovvio rischio, poiché i dati non sono archiviati correttamente dopo operazioni non riuscite. Una strategia migliore consiste nell'usare la strategia di backoff fisso. che consente di ripetere le operazioni con la stessa durata di backoff.

Tuttavia, la strategia non è ottimizzata per la gestione di tabelle altamente scalabili. Se molti thread o processi sono in attesa per la stessa durata, possono verificarsi conflitti. Una strategia di ripetizione dei tentativi consigliata è quella che usa un backoff esponenziale in cui ogni tentativo di ripetizione è più lungo dell'ultimo tentativo. È simile all'algoritmo di prevenzione della collisione usato nelle reti di computer, ad esempio Ethernet. Il backoff esponenziale usa un fattore casuale per offrire una varianza aggiuntiva all'intervallo risultante. Il valore di backoff è quindi vincolato al limite minimo e al limite massimo. La formula seguente può essere usata per il calcolo del successivo valore di backoff tramite un algoritmo esponenziale:

y = Rand(0.8z, 1.2z)(2x-1

y = Min(zmin + y, zmax

Dove:

z = backoff predefinito espresso in millisecondi

zmin = backoff minimo predefinito espresso in millisecondi

zmax = backoff massimo predefinito espresso in millisecondi

x = numero di nuovi tentativi

y = valore di backoff espresso in millisecondi

I moltiplicatori 0,8 e 1,2 usati nella funzione Rand (casuale) producono una varianza casuale del backoff predefinito entro ±20% del valore originale. L'intervallo ±20% è accettabile per la maggior parte delle strategie di ripetizione dei tentativi e impedisce ulteriori collisioni. La formula può essere implementata usando il codice seguente:

int retries = 1;  
  
// Initialize variables with default values  
var defaultBackoff = TimeSpan.FromSeconds(30);  
var backoffMin = TimeSpan.FromSeconds(3);  
var backoffMax = TimeSpan.FromSeconds(90);  
  
var random = new Random();  
  
double backoff = random.Next(  
    (int)(0.8D * defaultBackoff.TotalMilliseconds),   
    (int)(1.2D * defaultBackoff.TotalMilliseconds));  
backoff *= (Math.Pow(2, retries) - 1);  
backoff = Math.Min(  
    backoffMin.TotalMilliseconds + backoff,   
    backoffMax.TotalMilliseconds);  
  

Riepilogo

Un'applicazione nell'archiviazione tabelle di Azure può archiviare una grande quantità di dati perché l'archiviazione tabelle gestisce e riassegna le partizioni in molti nodi di archiviazione. È possibile usare il partizionamento dei dati per controllare la scalabilità della tabella. Pianificare in anticipo quando si definisce uno schema di tabella per assicurarsi di implementare strategie di partizionamento efficienti. In particolare, analizzare i requisiti, i dati e le query dell'applicazione prima di selezionare Valori PartitionKey . Ogni partizione potrebbe essere riassegnata a nodi di archiviazione diversi quando il sistema risponde al traffico. Usare un test di stress della partizione per assicurarsi che la tabella contenga i valori PartitionKey corretti. Questo test consente di determinare quando le partizioni sono troppo calde e consentono di apportare le modifiche necessarie alla partizione.

Per garantire che l'applicazione gestisca errori intermittenti e che i dati siano persistenti, usare una strategia di ripetizione dei tentativi con backoff. I criteri di ripetizione dei tentativi predefiniti usati dalla libreria client di Archiviazione di Azure hanno un backoff esponenziale che evita conflitti e ottimizza la velocità effettiva dell'applicazione.