VENDITE: 1-800-867-1389

Procedure consigliate per ottimizzare la scalabilità e la convenienza delle soluzioni di messaggistica basata su coda in Azure

Aggiornamento: marzo 2015

Scritto da: Amit Srivastava e Valery Mizonov

Rivisto da: Brad Calder, Sidney Higa, Christian Martinez, Steve Marx, Curt Peterson, Paolo Salvatori e Trace Young

In questo articolo vengono indicate informazioni normative e procedure consigliate per compilare soluzioni di messaggistica basata su coda scalabili, economiche ed estremamente efficienti nella piattaforma Azure. Il gruppo di destinatari a cui è rivolto l'articolo include architetti e sviluppatori di soluzioni che progettano e implementano soluzioni basate sul cloud che usano i servizi di archiviazione delle code della piattaforma Azure.

In una tradizionale soluzione di messaggistica basata su coda viene impiegato il concetto di un percorso di archiviazione dei messaggi noto come coda di messaggi, un repository per i dati che verranno inviati o ricevuti da uno o più partecipanti, in genere tramite un meccanismo di comunicazione asincrona.

In questo articolo verranno esaminate le procedure con cui gli sviluppatori possono usufruire di particolari modelli di progettazione insieme alle funzionalità fornite dalla piattaforma Azure per compilare soluzioni di messaggistica basata su coda ottimizzate ed economiche. Nell'articolo vengono esaminati in dettaglio gli approcci più comuni all'implementazione di interazioni basate su code in soluzioni Azure e forniti consigli per migliorare le prestazioni, aumentare la scalabilità e ridurre le spese operative.

La discussione sottostante include procedure consigliate, suggerimenti e consigli, laddove appropriato. Nello scenario descritto in questo articolo viene illustrata un'implementazione tecnica basata su un progetto reale di un cliente.

Una tipica soluzione di messaggistica che prevede lo scambio di dati tra i relativi componenti distribuiti usando code di messaggi include server di pubblicazione che depositano messaggi nelle code e uno o più sottoscrittori a cui sono destinati questi messaggi. Nella maggior parte dei casi, i sottoscrittori, talvolta definiti listener della coda, vengono implementati come processi a thread singoli o multipli, costantemente in esecuzione oppure avviati su richiesta in base a un modello di pianificazione.

A un livello superiore sono disponibili due meccanismi principali di recapito per consentire a un listener della coda di ricevere messaggi archiviati in una coda:

  • Polling (modello basato su pull): un listener monitora una coda controllando a intervalli regolari la presenza di nuovi messaggi. Quando la coda è vuota, il listener continua a eseguirne il polling, con backoff periodico passando a uno stato di sospensione.

  • Attivazione (modello basato su push): un listener effettua la sottoscrizione a un evento attivato (dal server di pubblicazione stesso o da un gestore di servizi di accodamento) ogni volta che viene recapitato un messaggio in una coda. Il listener a sua volta può avviare l'elaborazione dei messaggi senza dover pertanto eseguire il polling della coda per determinare la disponibilità di un nuovo lavoro.

È inoltre importante segnalare che esistono diverse varianti per entrambi i meccanismi. Il polling può ad esempio essere bloccante e non bloccante. Con il blocco viene messa in attesa una richiesta finché in una coda non verrà visualizzato un nuovo messaggio (o si verificherà il timeout), mentre una richiesta non bloccante viene immediatamente completata se non sono presenti elementi in una coda. Con un modello di attivazione, una notifica può essere inserita nei listener della coda per ogni nuovo messaggio, solo quando il primo messaggio raggiunge una coda vuota oppure quando la profondità della coda raggiunge un determinato livello.

noteNota
Le operazioni di rimozione dalla coda supportate dall'API del servizio di accodamento di Azure sono non bloccanti. Ciò significa che il risultato di metodi API quali GetMessage o GetMessages viene immediatamente restituito se non è presente alcun messaggio in una coda. Al contrario, le code del bus di servizio di Azure offrono operazioni di ricezione che bloccano il thread chiamante finché un messaggio non raggiungerà una coda o non sarà trascorso un periodo di timeout specificato.

L'approccio più comune all'implementazione di listener di code nelle soluzioni Azure moderne può essere riepilogato come segue:

  1. Un listener viene implementato come componente di applicazione di cui viene creata un'istanza e che viene eseguito nell'ambito di un'istanza del ruolo di lavoro.

  2. Il ciclo di vita del componente di listener della coda viene spesso associato al runtime dell'istanza del ruolo di hosting.

  3. La logica di elaborazione principale è costituita da un ciclo in cui i messaggi vengono rimossi dalla coda e recapitati per l'elaborazione.

  4. Se non viene ricevuto alcun messaggio, il thread di ascolto passa a uno stato di sospensione, la cui durata si basa spesso su un algoritmo di backoff specifico di un'applicazione.

  5. Viene eseguito il ciclo di ricezione e viene effettuato il polling di una coda finché il listener non riceverà la notifica di uscire dal ciclo e si interromperà.

Nel diagramma di flusso indicato di seguito viene illustrata la logica di uso comune nell'implementazione di un listener della coda con un meccanismo di polling in applicazioni Azure:

Soluzioni-di-messaggistica-delle-procedure-consigliate-Azure2
noteNota
Ai fini di questo articolo non verranno usati modelli di progettazione più complessi, ad esempio quelli che richiedono l'impiego di una gestione centrale delle code (Broker).

L'utilizzo di un tradizionale listener della coda con un meccanismo di polling potrebbe non rappresentare la scelta ottimale in caso di utilizzo di code di Azure, in quanto il modello di determinazione dei prezzi di Azure misura le transazioni di archiviazione in termini di richieste di applicazione eseguite nella coda, indipendentemente dal fatto che sia vuota o meno. Nelle sezioni successive verranno affrontate alcune tecniche per ottimizzare le prestazioni e ridurre il costo delle soluzioni di messaggistica basata su coda nella piattaforma Azure.

In questa sezione è necessario esaminare come migliorare gli aspetti di progettazione necessari per conseguire prestazioni migliori, maggiore scalabilità e costi ridotti.

Probabilmente, per stabilire nel modo più semplice se un modello di implementazione possa essere considerato una "soluzione più efficiente", deve soddisfare i seguenti obiettivi:

  • Riduzione delle spese operative grazie alla rimozione di una quantità significativa di transazioni di archiviazione che non derivano alcun lavoro utilizzabile.

  • Eliminazione di latenza eccessiva imposta da un intervallo di polling durante il controllo della presenza di nuovi messaggi in una coda.

  • Scalabilità dinamica verticale in modo che la potenza di elaborazione venga aumentata o diminuita in base a volumi volatili di lavoro.

Il modello di implementazione deve inoltre soddisfare questi obiettivi senza introdurre un livello di complessità superiore ai vantaggi associati.

In fase di valutazione del costo totale di proprietà e dell'utile sugli investimenti per una soluzione distribuita nella piattaforma Azure, il volume delle transazioni di archiviazione è una delle variabili principali nell'equazione del costo totale di proprietà. La riduzione del numero di transazioni rispetto alle code di Azure determina anche la riduzione dei costi operativi, in quanto si riferisce alle soluzioni in esecuzione in Azure.

Il costo dello spazio di archiviazione associato al servizio di accodamento di Azure può essere calcolato come indicato di seguito:

Spazio per le code: 24 byte + Lunghezza(NomeCoda) * 2 +  Metadati For-Each (4 byte + Lunghezza(NomeCoda) * 2 byte + Lunghezza(Valore) * 2 byte)

Spazio per il messaggio: 12 byte + Lunghezza(Messaggio)

Nel contesto di una soluzione di messaggistica basata su coda, il volume delle transazioni di archiviazione può essere ridotto mediante una combinazione dei seguenti metodi:

  1. In fase di inserimento di messaggi in una coda, raggruppare i messaggi correlati in un singolo batch di dimensioni superiori, comprimere e archiviare l'immagine compressa in un'Archiviazione BLOB e usare la coda per mantenere un riferimento al BLOB contenente i dati effettivi. Grazie a questo approccio è possibile ottimizzare il costo della transazione e il costo dello spazio di archiviazione.

  2. In fase di recupero di messaggi da una coda, raggruppare più messaggi in un'unica transazione di archiviazione. Il metodo GetMessages nell'API del servizio di accodamento consente di rimuovere dalla coda il numero di messaggi specificato in un'unica transazione (vedere la nota di seguito).

  3. In fase di verifica della presenza di elementi di lavoro in una coda, evitare intervalli di polling aggressivi e implementare un ritardo di backoff che aumenta il tempo che intercorre tra le richieste di polling se una coda rimane costantemente vuota.

  4. Riduzione del numero di listener della coda: quando si usa un modello basato su pull, usare solo un listener della coda per ogni istanza del ruolo quando una coda è vuota. Per ridurre a zero il numero di listener della coda per ogni istanza del ruolo, usare un meccanismo di notifica per creare un'istanza dei listener della coda quando la coda riceve elementi di lavoro.

  5. Se le code rimangono vuote per la maggior parte del tempo, ridurre automaticamente il numero di istanze del ruolo e continuare a monitorare la metrica di sistema rilevante per determinare se e quando l'applicazione dovrà applicare la scalabilità verticale per aumentare il numero di istanze al fine di gestire carichi di lavoro in espansione.

  6. Implementare un meccanismo per la rimozione di messaggi non elaborabili. I messaggi non elaborabili in genere sono messaggi in formato non corretto che non possono essere elaborati dall'applicazione. Se non vengono elaborati, i messaggi di questo tipo possono accumularsi e generare sistematicamente costi di transazione e di elaborazione. Un semplice meccanismo di implementazione può essere rappresentato dalla rimozione dalla coda dei messaggi precedenti rispetto a una determinata soglia temporale e dalla successiva scrittura di tali messaggi in un sistema di archiviazione per un'ulteriore valutazione.

  7. Ridurre gli errori di timeout previsti. Quando si invia una richiesta al servizio, è possibile specificare un determinato timeout e impostarlo in modo che risulti inferiore rispetto al timeout del contratto di servizio. In questo scenario, al momento del timeout della richiesta, questo viene classificato come previsto e la richiesta viene conteggiata come transazione fatturabile.

La maggior parte dei consigli sopra indicati possono tradursi in un'implementazione piuttosto generica che gestisce i batch di messaggi e incapsula numerose operazioni sottostanti di gestione dei thread e delle code/Archiviazioni BLOB. Affronteremo in dettaglio l'argomento più avanti in questo articolo.

ImportantImportante
In caso di recupero di messaggi tramite il metodo GetMessages, le dimensioni massime dei batch supportate dall'API del servizio di accodamento in una singola operazione di rimozione dalla coda sono limitate a 32.

In generale, il costo delle transazioni delle code di Azure aumenta in modo lineare proporzionalmente al numero dei client del servizio di accodamento, ad esempio quando viene applicata la scalabilità verticale per aumentare il numero di istanze del ruolo o dei thread di rimozione dalla coda. Per illustrare l'impatto potenziale dei costi di una progettazione di soluzione che non tiene conto dei consigli sopra indicati, verrà fornito un esempio supportato da numeri concreti.

Se l'architetto della soluzione non implementa ottimizzazioni rilevanti, l'architettura del sistema di fatturazione descritta in precedenza determinerà molto probabilmente spese operative eccessive una volta che la soluzione verrà distribuita e sarà in esecuzione nella piattaforma Azure. In questa sezione vengono descritti i motivi alla base di potenziali spese eccessive.

Come accennato nella definizione dello scenario, i dati delle transazioni aziendali vengono recapitati a intervalli regolari. Si presupponga, tuttavia, che la soluzione sia impegnata nell'elaborazione del carico di lavoro per appena il 25% del tempo di una giornata lavorativa standard di 8 ore. Vale a dire 6 ore (8 ore * 75%) di "tempo di inattività" in cui non si verificherà alcuna transazione nel sistema. Inoltre, la soluzione non riceverà dati durante le 16 ore giornaliere non lavorative.

Durante il periodo di inattività complessivo di 22 ore, la soluzione tenterà comunque di rimuovere lavori dalla coda, in quanto non è in grado di determinare in modo esplicito il momento in cui verranno recapitati nuovi dati. Durante questo periodo, ogni singolo thread di rimozione dalla coda eseguirà fino a 79.200 transazioni (22 ore * 60 minuti * 60 transazioni/min) su una coda di input, presupponendo un intervallo di polling predefinito di 1 secondo.

Come accennato in precedenza, il modello di determinazione dei prezzi nella piattaforma Azure si basa su singole "transazioni di archiviazione". Una transazione di archiviazione è una richiesta effettuata da un'applicazione utente per aggiungere, leggere, aggiornare o eliminare dati di archiviazione. Al momento della creazione di questo white paper, le transazioni di archiviazione sono fatturate a un costo di $ 0,01 per 10.000 transazioni (escluse eventuali offerte promozionali o contratti speciali).

ImportantImportante
In fase di calcolo del numero di transazioni della coda, tenere presente che l'inserimento di un messaggio in una coda verrà considerato come 1 transazione, mentre l'utilizzo di un messaggio consiste spesso in un processo a 2 fasi, costituito dal recupero seguito da una richiesta di rimozione del messaggio dalla coda. Di conseguenza, un'operazione di rimozione dalla coda completata coinvolgerà 2 transazioni di archiviazione. Tenere presente che, anche se una richiesta di rimozione dalla coda non determina il recupero di dati, verrà comunque conteggiata come una transazione fatturabile.

Le transazioni di archiviazione generate da un singolo thread di rimozione dalla coda nello scenario sopra indicato comporteranno un aumento in una fattura mensile di circa $ 2,38 (79.200/10.000 * $ 0,01 * 30 giorni). In confronto, 200 thread di rimozione dalla coda (o, in alternativa, 1 thread di rimozione in 200 istanze del ruolo di lavoro) determineranno un aumento mensile dei costi di $ 457,20, ovvero i costi accumulati nel momento in cui la soluzione non esegue alcun calcolo, ma si limita a verificare la disponibilità di elementi di lavoro nelle code. L'esempio precedente è astratto, in quanto difficilmente verrebbe implementato un servizio in questo modo. Ecco per quale motivo è importante eseguire le ottimizzazioni descritte di seguito.

Per ottimizzare le prestazioni delle soluzioni di messaggistica di Azure basate su coda, un approccio consiste nell'usare il livello di messaggistica di pubblicazione/sottoscrizione fornito con il bus di servizio di Azure, come descritto in questa sezione.

In questo approccio gli sviluppatori dovranno concentrarsi sulla creazione di una combinazione di notifiche basate su push in tempo reale e polling, consentendo ai listener di effettuare la sottoscrizione a un evento di notifica (trigger) generato in determinate condizioni per indicare che un nuovo carico di lavoro viene inserito in una coda. Questo approccio consente di ottimizzare il ciclo tradizionale di polling della coda con un livello di messaggistica di pubblicazione/sottoscrizione per il recapito di notifiche.

In un sistema distribuito complesso questo approccio necessiterebbe dell'impiego di un "bus di messaggi" o di un "middleware orientato a messaggi" per garantire che le notifiche possano essere inoltrate in modo affidabile a uno o più sottoscrittori a regime di controllo libero. Service Bus di Azure rappresenta una scelta naturale per soddisfare i requisiti di messaggistica tra servizi di applicazione distribuiti a regime di controllo libero in esecuzione in Azure e in locale. È inoltre ideale per un'architettura di "bus di messaggi" che consentirà lo scambio di notifiche tra i processi coinvolti nelle comunicazioni basate su coda.

I processi coinvolti in uno scambio di messaggi basato su coda potrebbero usare il seguente modello:

Soluzioni-di-messaggistica-delle-procedure-consigliate-Azure3

In particolare, e poiché si riferiscono all'interazione tra i server di pubblicazione e i sottoscrittori del servizio di accodamento, gli stessi principi applicabili alla comunicazione tra le istanze del ruolo di Azure soddisferebbero la maggior parte dei requisiti per gli scambi di messaggi di notifiche basate su push.

ImportantImportante
L'utilizzo del bus di servizio di Azure è soggetto a un modello di determinazione dei prezzi che considera il volume di operazioni di messaggistica a fronte di un'entità di messaggistica del bus di servizio, ad esempio una coda o un argomento.

È pertanto importante eseguire un'analisi del rapporto tra costi e benefici per valutare i pro e i contro relativi all'introduzione del bus di servizio in un'architettura specificata. In questo ambito è opportuno valutare se l'introduzione del livello di recapito delle notifiche basato sul bus di servizio determinerebbe in effetti una riduzione dei costi che giustifichi gli investimenti e ulteriori sforzi di sviluppo.

Per altre informazioni sul modello di determinazione dei prezzi del bus di servizio, fare riferimento alle relative sezioni in Domande frequenti sulla piattaforma Azure.

Mentre l'impatto sulla latenza è relativamente semplice da risolvere con un livello di messaggistica di pubblicazione/sottoscrizione, è possibile conseguire un'ulteriore riduzione dei costi mediante la scalabilità dinamica (elastica), come descritto nella sezione successiva.

L'archiviazione di Azure definisce gli obiettivi di scalabilità a livello di account generale e a livello di partizione. Una coda di Azure costituisce una singola partizione distinta e pertanto è in grado di elaborare fino a 2000 messaggi al secondo. Quando il numero di messaggi supera questa quota, il servizio di archiviazione risponde con un messaggio HTTP 503 indicante che il server è occupato e che la piattaforma limita la coda. È necessario che gli sviluppatori di applicazioni usino la pianificazione della capacità per assicurarsi che il numero di code sia sufficiente per supportare la frequenza di richieste dell'applicazione. Se una singola coda non è in grado di gestire la frequenza di richieste di un'applicazione, per garantire la scalabilità è necessario progettare un'architettura di accodamento partizionata in cui siano presenti più code.

Un'applicazione può inoltre sfruttare diverse code per tipi di messaggi diversi. In questo modo la scalabilità dell'applicazione viene garantita dalla compresenza di più code e dall'impossibilità di ostruirne una sola. Questa soluzione garantisce inoltre il controllo discreto dell'elaborazione delle code in base al livello di riservatezza e alla priorità dei messaggi archiviati in code diverse. Alle code con priorità elevata può essere dedicato un numero maggiore di thread di lavoro rispetto alle code con priorità bassa.

La piattaforma Azure consente ai clienti di applicare la scalabilità verticale in modo più rapido e più semplice che mai. La capacità di adattarsi a carichi di lavoro volatili e traffico variabile è una delle proposte di valore principali della piattaforma cloud. "Scalabilità" quindi non è più un termine IT dispendioso, ma una funzionalità predefinita che può essere abilitata a livello di codice su richiesta in una soluzione cloud con un'architettura adeguata.

La scalabilità dinamica è la capacità tecnica di una specifica soluzione di adattarsi a carichi di lavoro dinamici aumentando e riducendo la capacità del carico di lavoro e la potenza di elaborazione in fase di esecuzione. La piattaforma Azure supporta in modalità nativa la scalabilità dinamica tramite il provisioning di un'infrastruttura di calcolo distribuita in cui le ore di calcolo possono essere acquisite in base alle esigenze.

È importante distinguere tra i due seguenti tipi di scalabilità dinamica nella piattaforma Azure:

  • Con scalabilità dell'istanza del ruolo si fa riferimento all'aggiunta e alla rimozione di ulteriori istanze Web o del ruolo di lavoro per gestire il carico di lavoro temporizzato. Ciò include spesso la modifica del numero di istanze nella configurazione del servizio. L'aumento del numero di istanze determinerà l'avvio da parte del runtime di Azure di nuove istanze, mentre la riduzione del numero di istanze determinerà l'arresto delle istanze in esecuzione.

  • Con scalabilità del processo (thread) si fa riferimento alla gestione di una capacità sufficiente in termini di thread di elaborazione in una determinata istanza del ruolo attraverso l'aumento o la diminuzione del numero di thread a seconda del carico di lavoro corrente.

Per la scalabilità dinamica in una soluzione di messaggistica basata su coda è opportuno considerare i consigli generali indicati di seguito.

  1. Monitoraggio degli indicatori di prestazioni chiave, tra cui utilizzo della CPU, profondità della coda, tempi di risposta e latenza di elaborazione dei messaggi.

  2. Aumento o diminuzione dinamica del numero di istanze del ruolo per gestire i picchi stimabili o imprevedibili nel carico di lavoro.

  3. Espansione e riduzione a livello di codice del numero di thread di elaborazione per adattarsi a condizioni di caricamento variabili gestite da una determinata istanza del ruolo.

  4. Partizionamento ed elaborazione contemporanei di carichi di lavoro con granularità fine mediante la Task Parallel Library in .NET Framework 4.

  5. Gestione di una capacità possibile in soluzioni con carico di lavoro estremamente volatile in previsione di punte improvvise per poterle gestire senza l'overhead correlato alla configurazione di istanze aggiuntive.

L'API di gestione dei servizi consente a un servizio ospitato di Azure di variare il numero delle istanze del ruolo modificando la configurazione di distribuzione in fase di esecuzione.

noteNota
Il numero massimo di istanze di calcolo piccole di Azure (o il numero equivalente di altre istanze di calcolo ridimensionate in termini di numero dei core) in una sottoscrizione tipica è limitato a 20 per impostazione predefinita. Eventuali richieste di aumento della quota devono essere sottoposte al team del supporto di Azure. Per altre informazioni, vedere le domande frequenti della piattaforma Azure

Grazie all'introduzione di Azure Auto Scaling, la piattaforma è in grado di aumentare o diminuire il numero di istanze in base alla profondità dei messaggi in coda. Questa opzione si adatta in maniera del tutto naturale alla scalabilità dinamica. Il vantaggio è costituito dal fatto che la piattaforma Azure può monitorare e scalare le attività per l'applicazione.

La scalabilità dinamica del numero di istanze del ruolo potrebbe non rappresentare sempre la scelta ideale per la gestione di picchi del carico. Una nuova istanza del ruolo può ad esempio richiedere alcuni secondi per lo spin-up e al momento non sono disponibili metriche del contratto di servizio rispetto alla durata di spin-up. Una soluzione potrebbe invece dover aumentare semplicemente il numero di thread di lavoro per gestire l'aumento del carico di lavoro volatile. In fase di elaborazione del carico di lavoro, la soluzione monitorerà la metrica di caricamento pertinente e determina se è necessario ridurre o aumentare in modo dinamico il numero di processi di lavoro.

ImportantImportante
Attualmente l'obiettivo di scalabilità per una singola coda di Azure è "vincolato" a 2000 transazioni al secondo. Se un'applicazione tenta di superare questo obiettivo, ad esempio attraverso l'esecuzione di operazioni della coda da più istanze del ruolo che eseguono centinaia di thread di rimozione dalla coda, il servizio di archiviazione potrebbe restituire una risposta di server occupato (HTTP 503). In questo caso, tramite l'applicazione deve essere implementato un meccanismo di ripetizione tentativi con algoritmo di ritardo esponenziale di backoff. Se tuttavia gli errori HTTP 503 si verificano con regolarità, è consigliabile usare più code e implementare una strategia basata su partizionamento per eseguire la scalabilità tra più code.

Nella maggior parte dei casi, la scalabilità automatica dei processi di lavoro è responsabilità di una singola istanza del ruolo. Al contrario, la scalabilità dell'istanza del ruolo include spesso un elemento centrale dell'architettura della soluzione responsabile del monitoraggio della metrica delle prestazioni e dell'esecuzione di azioni di scalabilità appropriate. Il seguente diagramma illustra un componente del servizio denominato agente di scalabilità dinamica che raccoglie e analizza la metrica di caricamento per determinare se è necessario effettuare il provisioning di nuove istanze o il decomissioning delle istanze inattive.

Soluzioni-di-messaggistica-delle-procedure-consigliate-Azure4

È interessante notare che il servizio agente di scalabilità può essere distribuito come ruolo di lavoro in esecuzione in Azure o come servizio in locale. Indipendentemente dalla topologia di distribuzione, il servizio sarà in grado di accedere alle code di Azure.

noteNota
Come alternativa alla scalabilità dinamica manuale si consiglia di usare la funzionalità di scalabilità automatica incorporata di Azure.

Dopo aver affrontato l'impatto della latenza, i costi relativi alle transazioni di archiviazione e i requisiti di scalabilità dinamica, è giunto il momento di consolidare questi consigli in un'implementazione tecnica.

Per un esempio concreto, generalizzeremo uno scenario realistico di un cliente nel modo indicato di seguito.

Un provider di soluzioni SaaS avvia un nuovo sistema di fatturazione implementato come applicazione Azure in grado di soddisfare le esigenze aziendali per l'elaborazione delle transazioni del cliente in scala. Il presupposto principale alla base della soluzione risiede nella capacità di ripartire nel cloud carichi di lavoro che richiedono una notevole quantità di calcoli e sfruttare l'elasticità dell'infrastruttura Azure per eseguire le attività particolarmente dispendiose a livello di calcolo.

L'elemento locale dell'architettura end-to-end consolida e recapita regolarmente volumi elevati di transazioni a un servizio ospitato di Azure durante tutto il giorno. I volumi variano da alcune migliaia a centinaia di migliaia di transazioni a invio, raggiungendo milioni di transazioni al giorno. Si presuppone inoltre che la soluzione debba soddisfare un requisito basato su un contratto di servizio per una latenza massima di elaborazione garantita.

L'architettura della soluzione è fondata sul modello di progettazione MapReduce distribuito e comprende un livello cloud basato su ruolo di lavoro a più istanze che usa l'archiviazione delle code di Azure per il recapito di lavoro. I batch di transazione vengono ricevuti dall'istanza del ruolo di lavoro Process Initiator, decomposti (rimossi dai batch) in elementi di lavoro di dimensioni inferiori e accodati in una raccolta di code di Azure ai fini di distribuzione del carico.

L'elaborazione del carico di lavoro viene gestita da più istanze del ruolo di lavoro di elaborazione che recuperano gli elementi di lavoro dalle code per sottoporli a procedure di calcolo. Le istanze di elaborazione impiegano listener di coda multithread per implementare l'elaborazione parallela dei dati per ottenere prestazioni ottimali.

Gli elementi di lavoro elaborati vengono instradati in una coda dedicata da cui vengono quindi rimossi da parte dell'istanza del ruolo di lavoro Process Controller, aggregati e resi persistenti in un archivio dati per il data mining, la generazione di report e l'analisi.

L'architettura della soluzione può essere descritta come segue:

AzureGuidance_MaxScale

Il diagramma in alto rappresenta un'architettura tipica per la scalabilità orizzontale di carichi di lavoro di calcolo complessi o di grandi dimensioni. Il modello di scambio di messaggi basato su coda adottato in quest'architettura è tipico di molti altri servizi e applicazioni Azure che necessitano di comunicare reciprocamente tramite code. In questo modo è possibile adottare un approccio canonico all'esame di specifici componenti fondamentali coinvolti in uno scambio di messaggi basato su coda.

Per ottimizzare l'efficienza e la convenienza delle soluzioni di messaggistica basate su coda in esecuzione nella piattaforma Azure, gli architetti e gli sviluppatori di soluzioni devono tenere presenti le seguenti indicazioni:

Gli architetti di soluzioni dovranno:

  • Eseguire il provisioning di un'architettura di messaggistica basata su coda che usa il servizio di archiviazione di accodamento di Azure per la comunicazione asincrona su ampia scala tra i livelli e i servizi nelle soluzioni ibride o basate sul cloud.

  • Consigliare un'architettura di accodamento partizionata per una scalabilità superiore a 2000 messaggi al secondo.

  • Comprendere le nozioni fondamentali sul modello di determinazione dei prezzi di Azure e ottimizzare la soluzione per ridurre i costi di transazione tramite una serie di procedure consigliate e modelli di progettazione.

  • Considerare i requisiti di scalabilità dinamica effettuando il provisioning di un'architettura adattabile a carichi di lavoro volatili e dinamici.

  • Usare le tecniche e gli approcci appropriati di scalabilità automatica per espandere e ridurre in modo elastico la potenza di calcolo al fine di ottimizzare ulteriormente le spese operative.

  • Valutare la funzionalità di scalabilità automatica di Azure per verificare che sia idonea al tipo di scalabilità dinamica richiesto dall'applicazione.

  • Valutare il rapporto tra costi/benefici alla base di una riduzione della latenza attraverso l'impiego del Bus di servizio di Azure per il recapito di notifiche basate su push in tempo reale.

Gli sviluppatori dovranno:

  • Progettare una soluzione di messaggistica che impieghi l'invio in batch durante l'archiviazione e il recupero di dati dalle code di Azure.

  • Valutare la funzionalità di scalabilità automatica di Azure per verificare che sia idonea al tipo di scalabilità dinamica richiesto dall'applicazione.

  • Implementare un servizio di listener della coda efficace affinché venga eseguito il polling delle code da un massimo di un thread di rimozione dalla coda se vuote.

  • Ridurre in modo dinamico il numero di istanze di ruoli di lavoro se le code rimangono vuote per un periodo prolungato.

  • Implementare un algoritmo di backoff esponenziale casuale specifico dell'applicazione per ridurre l'effetto del polling delle code inattive sui costi delle transazioni di archiviazione.

  • Adottare le tecniche appropriate che impediranno di superare gli obiettivi di scalabilità per una singola coda in fase di implementazione di consumer e server di pubblicazione di code a più istanze multithread.

  • Impiegare criteri di tentativi efficaci in grado di gestire varie condizioni temporanee quando si pubblicano e utilizzano i dati da code di Azure.

  • Usare la funzionalità di gestione degli eventi unidirezionale fornita dal bus di servizio di Azure per supportare le notifiche basate su push al fine di ridurre la latenza e migliorare le prestazioni della soluzione di messaggistica basata su coda.

  • Esplorare le nuove caratteristiche di .NET Framework 4, tra cui TPL, PLINQ e il modello Observer, per ottimizzare il grado di parallelismo, migliorare la concorrenza e semplificare la progettazione di servizi multithread.

Il codice di esempio è disponibile per il download da MSDN Code Gallery. Include inoltre tutti i componenti dell'infrastruttura necessari, tra cui il livello di astrazione basato su generics per il servizio di accodamento di Azure, non disponibili nei frammenti di codice precedenti. Tutti i file di codice sorgente sono regolati da Microsoft Public License, come illustrato nelle note legali corrispondenti.

Il documento è risultato utile?
(1500 caratteri rimanenti)
Grazie per i commenti inviati.
Mostra:
© 2015 Microsoft