Esporta (0) Stampa
Espandi tutto

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

Aggiornamento: agosto 2014

Autore: http://msdn.microsoft.com/it-it/library/hh307529

Immagine cui si fa riferimento

Altre informazioni su RBA Consulting.

Riepilogo Questo articolo illustra argomenti relativi al partizionamento di una tabella di Azure e le strategie usate per assicurare una scalabilità efficiente.

Azure offre un'archiviazione affidabile dei dati, sempre disponibile e a scalabilità elevata. Il sistema di archiviazione sottostante di Azure è fornito tramite un insieme di astrazioni oggetto, spesso indicate come servizi, che sono costituite dai servizi basati su tabelle, BLOB e code. Ogni servizio può supportare la maggior parte delle esigenze relative all'archiviazione. Se l'applicazione deve archiviare dati strutturati, l'opzione ottimale è offerta dall'archiviazione tabelle di Azure. Il servizio Archiviazione di Azure supporta un numero illimitato di tabelle e ogni tabella è scalabile a livelli estremamente elevati. È possibile scalare orizzontalmente una tabella in modo automatico per archiviare miliardi di entità, che possono rappresentare terabyte di archiviazione fisica. Per usufruire dei vantaggi offerti dalle tabelle, è consigliabile partizionare i dati tramite i valori PartitionKey ottimali. Questo articolo esamina le strategie che permettono di partizionare in modo efficiente i dati per l'archiviazione tabelle di Azure.

Le entità di tabella rappresentano le unità di dati archiviate in una tabella e sono simili alle righe in una tabella tipica di un database relazionale. Ogni entità definisce una raccolta di proprietà. Ogni proprietà corrisponde a una coppia chiave/valore definita da nome, valore e 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 l'entità. Le entità con valori PartitionKey uguali appartengono quindi alla stessa partizione. Come illustrato più avanti, le partizioni sono essenziali per la scalabilità della tabella.

  • RowKey: la proprietà RowKey archivia i valori stringa che identificano in modo univoco le entità in ogni partizione.

  • Timestamp: la proprietà Timestamp offre la tracciabilità per un'entità. Un timestamp è un valore DateTime che indica la data e l'ora dell'ultima modifica dell'entità. Il timestamp è a volte definito come la versione dell'entità. Le modifiche ai timestamp sono ignorate, poiché il servizio tabelle mantiene il valore per questa proprietà durante tutte le operazioni di inserimento e aggiornamento.

La chiave primaria per ogni tabella di database indica le colonne che definiscono in modo univoco ogni riga. Ciò è applicabile anche alle tabelle di Azure. Le chiavi primarie per una tabella di Azure sono le proprietà PartitionKey e RowKey, che costituiscono un singolo indice cluster nella tabella. Ogni proprietà PartitionKey e RowKey è in grado di archiviare fino a 1 KB di valori stringa. Sono ammesse anche le stringhe vuote, ma non sono accettati valori Null. L'indice cluster è ordinato da PartitionKey in ordine crescente e quindi da RowKey, sempre in ordine crescente. L'ordinamento è rispettato in tutte le risposte di query. Durante l'operazione di ordinamento sono usati i confronti lessicali. Un valore stringa "111" sarà quindi visualizzato prima di un valore stringa "2". In alcuni casi è possibile che si voglia usare un ordinamento numerico. Per applicare un ordinamento numerico e crescente, sarà necessario usare stringhe a lunghezza fissa e senza aggiunta di zeri. Se nell'esempio precedente si usa "002", questo valore sarà visualizzato prima di "111".

Le partizioni rappresentano una raccolta di entità con gli stessi valori PartitionKey. Le partizioni sono sempre servite da un server partizione e ogni server 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 un obiettivo di scalabilità pari a 500 entità al secondo. Questa velocità effettiva può risultare maggiore durante un carico minimo sul nodo di archiviazione, ma sarà ridotta quando il nodo di archiviazione è sottoposto a un carico eccessivo o è molto attivo. Per illustrare meglio il concetto di partizionamento, la figura seguente mostra una tabella che contiene un piccolo sottoinsieme di dati per iscrizioni a eventi relativi a gare podistiche. Presenta una visualizzazione concettuale del partizionamento, in cui PartitionKey contiene tre valori diversi, costituiti dal nome dell'evento e dalla distanza da percorrere. In questo esempio sono disponibili due server partizione. Il server A contiene le iscrizioni per distanze pari alla mezza maratona e a 10 Km, mentre il server B contiene solo le distanze relative all'intera maratona. I valori RowKey sono mostrati per offrire un contesto, ma non sono significativi per questo esempio.

Schermata cui si fa riferimento

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. È possibile che i server che gestiscono traffico elevato per le partizioni non siano in grado di sostenere una velocità effettiva elevata. Ad esempio, nella figura precedente, se il numero di richieste per "2011 New York City Marathon__Half" è elevato, è possibile che il carico del server A risulti eccessivo. 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 un bilanciamento ottimale del carico del traffico, è consigliabile usare più partizioni, poiché ciò permette al servizio tabelle di Azure di distribuire le partizioni in più server partizione.

Una transazione dei gruppi di entità è un insieme di operazioni di archiviazione implementate automaticamente su entità con lo stesso valore PartitionKey. In caso di errore di un'operazione di archiviazione nel gruppo di entità, sarà eseguito il rollback di tutte le operazioni di archiviazione nel gruppo specifico. Una transazione dei gruppi di entità include al massimo 100 operazioni di archiviazione e non può avere dimensioni superiori a 4 MB. Le transazioni dei gruppi di entità offrono al servizio tabelle di Azure una forma limitata della semantica ACID (Atomicity, Consistency, Isolation, Durability) fornita dai database relazionali. Le transazioni dei gruppi di entità migliorano la velocità effettiva, poiché riducono il numero di singole operazioni di archiviazione da inviare al servizio tabelle di Azure. Offrono anche un vantaggio economico, poiché una transazione dei gruppi di entità è fatturata come singola operazione di archiviazione, indipendente dal numero di operazioni di archiviazione incluse nel gruppo. Poiché tutte le operazioni di archiviazione in una transazione dei gruppi di entità interessano le entità con lo stesso valore PartitionKey, è possibile che la selezione del valore PartitionKey sia correlata al desiderio di usare le transazioni dei gruppi di entità.

Se si usano valori PartitionKey univoci per le entità, ogni entità apparterrà a una partizione specifica. Se i valori univoci usati sono crescenti o decrescenti, è possibile che Azure crei partizioni a intervalli. Le partizioni a intervalli raggruppano entità con valori PartitionKey sequenziali e univoci, in modo da migliorare le prestazioni delle query di intervallo. Senza le partizioni a intervalli, una query di intervallo dovrebbe attraversare i limiti delle partizioni o dei server e ciò potrebbe influire negativamente sulle prestazioni della query. Si prenda in considerazione un'applicazione che usa la tabella seguente con un valore sequenziale crescente per PartitionKey.

 

PartitionKey

RowKey

"0001"

-

"0002"

-

"0003"

-

"0004"

-

"0005"

-

"0006"

-

È possibile che Azure raggruppi le prime tre entità in una partizione a intervalli. Se si applica a questa tabella una query di intervallo che usa PartitionKey come criterio e richiede le entità da "0001" a "0003", è possibile che le prestazioni della query siano efficienti, poiché sarà servita da un singolo server partizione. Non è disponibile alcuna garanzia su quando e come sarà creata una partizione a intervalli.

L'esistenza di partizioni a intervalli per la tabella può influire sulle prestazioni delle operazioni di inserimento, se si inseriscono entità con valori PartitionKey crescenti o decrescenti. L'inserimento di entità con valori PartitionKey crescenti è un modello di tipo Solo accodamenti e l'inserimento con valori decrescenti è un modello di tipo Solo anteposizioni. Se possibile, non usare questi modelli, poiché la velocità effettiva complessiva delle richieste di inserimento sarà limitata da un singolo server partizione. Se sono infatti presenti partizioni a intervalli, la prima e l'ultima partizione (intervallo) includeranno rispettivamente il valore PartitionKey minimo e massimo. L'inserimento di una nuova entità con un valore PartitionKey sequenziale minore o maggiore farà quindi riferimento a una delle partizioni finali. La figura seguente mostra un possibile insieme di partizioni a intervalli basato sull'esempio precedente. Se è stato inserito un insieme di entità "0007", "0008" e "0009", a queste entità sarà assegnata l'ultima partizione (arancione).

Schermata cui si fa riferimento

È importante notare che l'uso di valori PartitionKey sparsi da parte delle operazioni di inserimento non influisce negativamente sulle prestazioni.

A differenza di una tabella in database relazionali, che permettono di gestire gli indici, le tabelle di Azure possono includere solo un indice, che è sempre costituito dalle proprietà PartitionKey e RowKey. Non è quindi possibile perfezionare le prestazioni della tabella aggiungendo più indici o modificando un indice esistente dopo l'implementazione. Sarà quindi necessario analizzare i dati durante la progettazione della tabella. Gli aspetti più importanti da valutare per ottenere una scalabilità ideale e per assicurare query e inserimenti efficienti sono rappresentati dai valori PartitionKey e RowKey. Questo articolo esamina con maggiore dettaglio la scelta di PartitionKey poiché questo valore è direttamente correlato alla modalità di partizionamento delle tabelle.

Il dimensionamento di una partizione fa riferimento al numero di entità incluse in una partizione. Come indicato nella sezione "Scalabilità", più partizioni permettono un bilanciamento migliore del carico. La granularità del valore PartitionKey influisce sulla dimensione delle partizioni. Al livello minimo di granularità, se si usa un singolo valore come PartitionKey, tutte le entità si troveranno in un'unica partizione molto grande. In alternativa, al livello massimo di granularità, PartitionKey può includere valori univoci per ogni entità. Sarà quindi disponibile una partizione per ogni entità. La tabella seguente mostra i vantaggi e gli svantaggi relativi agli intervalli di granularità.

 

Granularità di PartitionKey

Dimensione della partizione

Vantaggi

Svantaggi

Valore singolo

Numero ridotto di entità.

Transazioni batch possibili con qualsiasi entità.

Tutte le entità sono locali e sono servite dallo stesso nodo di archiviazione.

 

Valore singolo

Numero elevato di entità.

Transazioni dei gruppi di entità possibili con qualsiasi entità. Per altre informazioni sui limiti delle transazioni dei gruppi di entità, vedere http://msdn.microsoft.com/it-it/library/dd894038.aspx.

Scalabilità limitata.

Velocità effettiva limitata alle prestazioni di un singolo server.

Più valori

Più partizioni disponibili.

Le dimensioni delle partizioni dipendono dalla distribuzione delle entità.

Transazioni batch possibili in alcune entità.

Partizionamento dinamico possibile.

Query a richiesta singola possibili (nessun token di continuazione).

Bilanciamento del carico possibile tra più server partizione.

Una distribuzione altamente irregolare delle entità nelle partizioni potrebbe limitare le prestazioni delle partizioni più grandi e più attive.

Valori univoci

Molte partizioni piccole.

Tabella a scalabilità elevata.

Le partizioni a intervalli possono migliorare le prestazioni delle query di intervallo tra partizioni.

Le query che interessano gli intervalli potrebbero richiedere visite a più server.

Transazioni batch non possibili.

I modelli di tipo accodamenti o anteposizioni possono influire sulla velocità effettiva degli inserimenti.

Questa tabella mostra l'impatto dei valori PartitionKey sulla scalabilità. È consigliabile usare partizioni di dimensioni ridotte, perché offrono un bilanciamento del carico migliore. Le partizioni di grandi dimensioni possono essere adatte ad alcuni scenari e non sono necessariamente svantaggiose. Se, ad esempio, l'applicazione non necessita di scalabilità, una singola partizione di grandi dimensioni potrebbe essere consigliabile.

Le query recuperano dati dalle tabelle. Quando si analizzano i dati per una tabella di Azure, è importante valutare le query che saranno usate dall'applicazione. Se un'applicazione usa diverse query, potrebbe essere necessario definirne la priorità, benché questa decisione possa risultare abbastanza soggettiva. In molti casi le query dominanti possono essere facilmente distinte dalle altre query. A livello di prestazioni, le query rientrano in diverse categorie. Poiché una tabella ha solo un indice, la prestazione delle query è in genere correlata alle proprietà PartitionKey e RowKey. La tabella seguente mostra i diversi tipi di query e le valutazioni corrispondenti a livello di prestazioni.

 

Tipo di query

Corrispondenza con PartitionKey

Corrispondenza con RowKey

Valutazione a livello di prestazioni

Punto

Esatta

Esatta

Ottimale

Analisi intervallo righe

Esatta

Parziale

Migliore con partizioni di dimensioni ridotte

Scarsa con partizioni di dimensioni molto grandi

Analisi intervallo partizioni

Parziale

Parziale

Buona con un numero ridotto di server partizione interessati

Peggiore con più server interessati

Analisi completa tabella

Parziale, nessuna

Parziale, nessuna

Peggiore con un sottoinsieme di partizioni da analizzare

Pessima con tutte le partizioni analizzate

noteNota
La tabella definisce le valutazioni reciproche delle prestazioni. In definitiva, il numero e le dimensioni delle partizioni possono determinare le prestazioni delle query. Ad esempio, un'analisi dell'intervallo di partizioni per una tabella con molte partizioni di grandi dimensioni potrebbe avere prestazioni peggiori rispetto a un'analisi completa della tabella per una tabella con poche partizioni di dimensioni ridotte.

I tipi di query elencati in questa tabella mostrano una progressione dai tipi migliori ai tipi peggiori di query da usare, in base alle valutazioni relative alle prestazioni. Le query di tipo punto sono le query migliori da usare, poiché usano al meglio l'indice cluster della tabella. La query di tipo punto seguente usa i dati della tabella di iscrizione alla gara podistica.

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. Sono disponibili due tipi di query di intervallo: l'analisi dell'intervallo di righe e l'analisi dell'intervallo di partizioni. L'analisi dell'intervallo di righe specifica una singola partizione. Poiché l'operazione è eseguita in un singolo server partizione, le analisi dell'intervallo di righe sono in genere più efficienti rispetto alle analisi dell'intervallo di partizioni. Un fattore essenziale delle prestazioni delle analisi dell'intervallo di righe è tuttavia costituito dalla selettività di una query, 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 stabilire le priorità delle query, è necessario valutare i requisiti relativi a frequenza e tempo di risposta per ogni query. Le query con esecuzione frequente potrebbero avere una priorità maggiore. È però possibile che una query importante ma usata raramente abbia requisiti relativi alla latenza che la rendono prioritaria rispetto alle altre.

La parte essenziale della progettazione di qualsiasi tabella è basata sulla scalabilità, sulle query usate per l'accesso alla tabella e sui requisiti relativi alle operazioni di archiviazione. I valori PartitionKey scelti determineranno il modo in cui una tabella sarà partizionata e il tipo delle query che potranno essere usate. Anche le operazioni di archiviazione, in particolare gli inserimenti, possono influire sulla scelta dei valori PartitionKey. Per PartitionKey possono essere usati valori singoli, valori univoci oppure più valori. Le proprietà delle entità possono essere composte per formare il valore PartitionKey. L'applicazione può anche calcolare il valore.

Gli sviluppatori dovrebbero stabilire prima di tutto se l'applicazione userà le transazioni dei gruppi di entità (aggiornamenti in batch). Per le transazioni dei gruppi di entità è necessario che le entità abbiano lo stesso valore PartitionKey. Poiché gli aggiornamenti in batch riguardano l'intero gruppo, è anche possibile limitare le opzioni per i valori PartitionKey. Ad esempio, un'applicazione in ambito bancario che gestisce le transazioni in contanti deve inserire automaticamente le transazioni in contanti nella tabella. Le transazioni in contanti, infatti, rappresentano sia il lato debito che il lato credito e il totale deve essere zero. Non è quindi possibile usare il numero di conto come parte di PartitionKey, poiché ogni lato della transazione usa numeri di conto diversi. Un ID transazione rappresenta invece una scelta più idonea.

I numeri e le dimensioni delle partizioni influiscono sulla scalabilità di una tabella sottoposta a caricamento e sono controllati dal livello di granularità dei valori PartitionKey. Determinare i valori PartitionKey in base alle dimensioni delle partizioni può risultare complesso, in particolare se la distribuzione dei valori è difficile da prevedere. È in genere consigliabile usare più partizioni di dimensioni ridotte. Molte partizioni di tabella semplificano la gestione da parte del servizio tabelle di Azure dei nodi di archiviazione da cui sono servite le partizioni.

Se si scelgono valori univoci o a granularità elevata per PartitionKey, si otterranno partizioni più piccole ma più numerose. Questa soluzione è in genere preferibile, perché il sistema può bilanciare il carico delle partizioni in modo da distribuire il carico in più partizioni. È tuttavia consigliabile valutare l'effetto della presenza di più partizioni sulle query di intervallo tra partizioni. Questo tipo di query deve visitare più partizioni per arrivare al completamento. È possibile che le partizioni siano distribuite in più server partizione. Se la query attraversa un limite di server, dovranno essere restituiti token di continuazione, che specificano i valori PartitionKey o RowKey successivi che recupereranno il set di dati successivo per la query. In altri termini, i token di continuazione rappresentano almeno un'altra richiesta al servizio e ciò può influire negativamente sulle prestazioni 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. A una maggiore selettività della query corrisponde una maggiore efficienza nella restituzione delle righe desiderate. Le prestazioni complessive delle query di intervallo possono dipendere dal numero di server partizione interessati o dalla selettività della query. È anche consigliabile evitare di usare i modelli di tipo Solo accodamenti o Solo anteposizioni durante l'inserimento di dati nella tabella. L'uso di questi modelli, nonostante la creazione di molte partizioni di piccole dimensioni, può limitare la velocità effettiva delle operazioni di inserimento. I modelli di tipo Solo accodamenti o Solo anteposizioni sono illustrati nella sezione "Partizioni a intervalli".

Se si conoscono le query che saranno usate, sarà possibile determinare le proprietà importanti per PartitionKey. Le proprietà usate nelle query sono candidate per PartitionKey. La tabella seguente offre indicazioni generali per determinare i valori PartitionKey.

 

Se l'entità…

Azione

Include una proprietà chiave

Usarla come PartitionKey

Include due proprietà chiave

Usarne una come PartitionKey e l'altra come RowKey

Include più di due proprietà chiave

Usare una chiave composta di valori concatenati

Se sono presenti più query ugualmente dominanti, è possibile inserire più volte le informazioni con i diversi valori RowKey necessari. Le righe secondarie (o terziarie e così via) saranno gestite dall'applicazione. Questo modello permetterà di soddisfare i requisiti a livello di prestazioni delle query. L'esempio seguente usa i dati dell'esempio di iscrizione a una gara podistica. Include due valori delle query dominanti. Sono i seguenti:

  • 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à. La tabella seguente mostra le proprietà Partitionkey e RowKey per questo scenario. I valori RowKey offrono un prefisso per la pettorina e per l'età, in modo da permettere all'applicazione di distinguere 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, una transazione dei gruppi di entità è possibile poiché i valori PartitionKey sono uguali. La transazione dei gruppi offre l'atomicità dell'operazione di inserimento. Anche se è possibile usare questo modello con diversi valori PartitionKey, è consigliabile usare gli stessi valori per ottenere questo vantaggio. In caso contrario, potrebbe essere necessario scrivere logica aggiuntiva per assicurare transazioni atomiche con diversi valori PartitonKey.

Il servizio tabelle di Azure può essere sottoposto a carichi non solo dalle query, ma anche da operazioni di archiviazione quali inserimenti, aggiornamenti ed eliminazioni. È necessario determinare il tipo di operazioni di archiviazione che saranno eseguite sulla tabella e la relativa frequenza. Se queste operazioni saranno eseguite raramente, non sarà necessario occuparsene. Per le operazioni molto frequenti, tuttavia, ad esempio l'esecuzione di molti inserimenti in un breve periodo di tempo, potrebbe essere necessario prendere in considerazione il modo in cui queste operazioni saranno servite come risultato dei valori PartitionKey scelti. Un esempio importante è rappresentato dai modelli di tipo Solo accodamenti o Solo anteposizioni, illustrati nella sezione "Partizioni a intervalli" precedente. Se si usa il modello di tipo Solo accodamenti o Solo anteposizioni, si usano valori crescenti o decrescenti univoci per PartitionKey in inserimenti successivi. Se si associa questo modello a operazioni di inserimento frequenti, la tabella non sarà in grado di servire le operazioni di inserimento con scalabilità elevata. Ciò influisce sulla scalabilità della tabella, poiché Azure non sarà in grado di bilanciare il carico delle richieste di operazioni negli altri server partizione. In questo caso è pertanto consigliabile prendere in considerazione l'uso di valori casuali, ad esempio i valori GUID. Ciò permette di mantenere dimensioni ridotte per le partizioni, mantenendo al tempo stesso il bilanciamento del carico durante le operazioni di archiviazione.

Se il valore PartitionKey è complesso o richiede confronti con altri mapping di 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 i dati nella tabella di test, in modo che contenga entità con la proprietà PartitionKey da testare.

  3. Usare l'applicazione per simulare un picco di carico nella tabella, quindi fare riferimento a 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 faccia riferimento 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 500 entità al secondo. Se la velocità effettiva supera le 500 entità al secondo per una partizione, è possibile che il carico del server sia eccessivo in un ambiente di produzione. In questo caso, è possibile che il livello di granularità dei valori PartitionKey sia troppo basso e che non siano quindi disponibili partizioni sufficienti o che le partizioni siano troppo grandi. Potrebbe essere necessario modificare il valore PartitionKey, in modo che le partizioni possano essere distribuite tra più server.

Il bilanciamento del carico a livello di partizione si verifica quando il carico della partizione è eccessivo, ovvero quando la partizione, e in particolare il server partizione, sta operando oltre il rispettivo obiettivo di scalabilità. Per l'archiviazione di Azure ogni partizione ha un obiettivo di scalabilità pari a 500 entità al secondo. Il bilanciamento del carico si verifica anche a livello di file system distribuito (DFS, Distributed File System). Il bilanciamento del carico a livello DFS si occupa del carico I/O e non rientra nell'ambito di questo articolo. Il bilanciamento del carico a livello di partizione non si verifica immediatamente dopo il superamento dell'obiettivo di scalabilità. Il sistema attende alcuni minuti prima di avviare il processo di bilanciamento del carico, in modo da assicurare che il carico della partizione sia effettivamente eccessivo. Non è necessario preparare le partizioni con un carico generato che attiva il bilanciamento del carico, poiché l'attività sarà eseguita automaticamente dal sistema. Se una tabella è stata preparata con un determinato carico, è possibile che il sistema applichi il bilanciamento alle partizioni in base al carico effettivo e che ciò provochi una distribuzione molto diversa delle partizioni. Invece di preparare le partizioni, prendere in considerazione la scrittura di codice per la gestione degli errori di timeout e di server occupato. Questi errori sono restituiti quando il sistema esegue il bilanciamento del carico. La gestione di questi errori tramite una strategia di ripetizione dei tentativi permette all'applicazione di gestire meglio i picchi di carico. Le strategie di ripetizione dei tentativi sono illustrate in modo più dettagliato nella sezione successiva. Quando si verifica il bilanciamento del carico, la partizione risulterà offline per alcuni secondi. Durante il periodo offline, il sistema riassegna la partizione a un server partizione diverso. È importante notare che i dati non sono archiviati dai server partizione, che serve invece le entità dal livello DFS. Poiché i dati non sono archiviati a livello di partizioni, lo spostamento di partizioni in server diversi è un processo molto rapido e riduce notevolmente l'eventuale periodo di inattività dell'applicazione.

È importante che l'applicazione gestisca gli errori delle operazioni di archiviazione, in modo da assicurare che non vada perso alcun aggiornamento dei dati. Alcuni errori non richiedono una strategia di ripetizione dei tentativi. Ad esempio, gli aggiornamenti che restituiscono un errore di tipo 401 - Non autorizzato non otterranno alcun vantaggio da un nuovo tentativo di eseguire l'operazione, poiché è probabile che tra i diversi tentativi lo stato dell'applicazione non subisca modifiche in grado di risolvere l'errore 401. Alcuni errori, tuttavia, ad esempio gli errori di server occupato o di timeout, sono correlati alle funzionalità di bilanciamento del carico di Azure che offrono la scalabilità della tabella. Quando il carico dei nodi di archiviazione che servono le entità risulta troppo elevato, Azure applicherà il bilanciamento del carico tramite lo spostamento di partizioni in altri nodi. È possibile che la partizione non sia accessibile durante lo spostamento e che ciò provochi errori di tipo server occupato o di timeout. La partizione sarà infine riabilitata e sarà possibile riprendere gli aggiornamenti. Una strategia di ripetizione dei tentativi è adatta agli errori di tipo server occupato e di timeout. Nella maggior parte dei casi è possibile escludere gli errori di livello 400 e alcuni errori di livello 500 dalla logica di ripetizione dei tentativi, ad esempio l'errore 501 - Non implementato o 505 - Versione HTTP Non supportata, e implementare una strategia di ripetizione dei tentativi per alcuni errori di livello 500, ad esempio Server occupato (503) e Timeout (504).

Sono disponibili tre strategie di ripetizione dei tentativi comuni da usare per l'applicazione. L'elenco seguente include le strategie di ripetizione dei tentativi e le rispettive descrizioni:

  • Nessun tentativo: non saranno effettuati nuovi tentativi

  • Backoff fisso: sono eseguiti N tentativi con un valore di backoff costante

  • Backoff esponenziale: sono effettuati N tentativi con un valore di backoff esponenziale

La strategia di tipo nessun tentativo è un modo semplice ed evasivo di gestire gli errori delle operazioni, ma non è molto utile. Non imporre la ripetizione di tentativi pone un ovvio rischio, poiché i dati non sono archiviati correttamente dopo operazioni non riuscite. È quindi consigliabile usare la strategia di tipo backoff fisso, che offre la possibilità di tentare di nuovo le operazioni con la stessa durata di backoff. Questa strategia, tuttavia, non è ottimizzata per la gestione di tabelle a scalabilità elevata, poiché può provocare conflitti in caso di molti thread o processi in attesa per la stessa durata di backoff. La strategia di ripetizione dei tentativi consigliata è quella di tipo backoff esponenziale, in cui ogni nuovo tentativo è più lungo del tentativo precedente. È simile all'algoritmo di prevenzione dei conflitti 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 (random) producono una varianza casuale del backoff predefinito compresa nell'intervallo ±20% del valore originale. L'intervallo ±20% è accettabile per la maggior parte delle strategie di ripetizione dei tentativi e previene altri conflitti. Questa formula può essere implementata tramite 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);


Se si sviluppa l'applicazione usando la libreria gestita di Azure, sarà possibile avvalersi dei criteri di ripetizione di tentativi inclusi nella libreria client di archiviazione. Il meccanismo di ripetizione di tentativi nella libreria permette anche di estendere la funzionalità con i criteri di ripetizione di tentativi personalizzati. La classe RetryPolicies nello spazio dei nomi Microsoft.WindowsAzure.StorageClient offre metodi statici che restituiscono un oggetto RetryPolicy. L'oggetto RetryPolicy è usato insieme al metodo SaveChangesWithRetries nella classe TableServiceContext. Il criterio predefinito usato da un oggetto TableServiceContext è un'istanza di una classe RetryExponential creata usando i valori RetryPolicies.DefaultClientRetryCount e RetryPolicies.DefaultClientBackoff. Il codice seguente mostra come creare una classe TableServiceContext con un oggetto RetryPolicy diverso.

class MyTableServiceContext : TableServiceContext
{
    public MyTableServiceContext(string baseAddress, CloudStorageAccount account)
        : base(baseAddress, account)
    {
        int retryCount = 5; // Default is 3
        var backoff = TimeSpan.FromSeconds(45); // Default is 30 seconds

        RetryPolicy = RetryPolicies.RetryExponential(retryCount, backoff);
    }
    ...
}

L'archiviazione tabelle di Azure permette alle applicazioni di archiviare una quantità molto elevata di dati, poiché gestisce e riassegna le partizioni in molti nodi di archiviazione. È possibile usare il partizionamento dei dati per controllare la scalabilità della tabella. Eseguire una pianificazione accurata quando si definisce lo schema di una tabella, in modo da assicurare strategie di partizionamento efficienti. In particolare, analizzare i requisiti, i dati e le query dell'applicazione prima di selezionare i valori di PartitionKey. Ogni partizione potrebbe essere riassegnata a diversi nodi di archiviazione, in base alla risposta del sistema al traffico. Usare un test di stress della partizione per assicurare che i valori PartitionKey per la tabella siano corretti. Il test permetterà di capire quando il carico delle partizioni è troppo elevato e di apportare le modifiche necessarie alla partizione. Per assicurare che l'applicazione gestisca gli errori intermittenti e che i dati siano persistenti, è consigliabile usare una strategia di ripetizione di tentativi con backoff. I criteri di ripetizione di tentativi predefiniti usati dalla libreria client di archiviazione di Azure usano un backoff esponenziale che evita i conflitti e massimizza la velocità effettiva dell'applicazione.

Mostra:
© 2014 Microsoft