2012-02-16 6 views
8

Quando un ruolo Web inserisce un messaggio in una coda di archiviazione, come può eseguire il polling di una risposta correlata specifica? Vorrei che il ruolo del lavoratore di back-end inserisse un messaggio in una coda di risposta, con l'intento che il chiamante avrebbe raccolto la risposta e sarebbe partito da lì.Coda di archiviazione di Azure - correlazione della risposta alla richiesta

Il nostro intento è quello di sfruttare la coda per scaricare alcune elaborazioni pesanti sui ruoli di lavoro back-end al fine di garantire prestazioni elevate sui ruoli Web. Tuttavia, non desideriamo rispondere alle richieste HTTP finché i Worker back-end non hanno finito e hanno risposto.

risposta

4

Sono davvero nel bel mezzo di prendere una decisione simile. Nel mio caso ho un servizio WCF in esecuzione in un ruolo web che dovrebbe scaricare i calcoli sui ruoli dei lavoratori. Quando il risultato è stato calcolato, il ruolo web restituirà la risposta al cliente.

La conoscenza della struttura dati di base mi dice che dovrei evitare di usare qualcosa che è stato progettato come una coda in modo non di coda. Ciò significa che una coda dovrebbe sempre essere revisionata in modo FIFO. Quindi, in pratica, se si utilizzano le code per entrambe le richieste e le risposte, i thread in attesa di restituire i dati al client dovranno attendere fino a quando il messaggio di calcolo si troverà nella "top" della coda di risposta, che non è ottimale.Se si memorizzano le risposte utilizzando le tabelle di Azure, i thread eseguono il polling per i messaggi che creano un sovraccarico non necessario

Ciò che credo sia una possibile soluzione a questo problema è l'utilizzo di una coda per le richieste. Ciò consente l'utilizzo del modello di consumatori in competizione e quindi il bilanciamento del carico. Sui messaggi inviati in questa coda si imposta correlationId property sul messaggio. Per rispondere, la parte pub/sub ("argomenti") del bus di servizio di Azure viene utilizzata insieme a correlation filter. Quando il tuo back-end ha elaborato la richiesta, ha pubblicato un risultato su "responseSubject" con la correlationId fornita nella richiesta originale. Ora questa risposta può essere recuperata dal tuo cliente chiamando CreateSubscribtion (Spiacente, non posso pubblicare più di due link apparentemente, google) usando quel filtro di correlazione, e dovrebbe ricevere una notifica quando la risposta è pubblicata. Si noti che la parte CreateSubscribtion deve essere eseguita una sola volta nel metodo OnStart. Quindi puoi eseguire un'async BeginRecieve su quella sottoscrizione e il ruolo verrà notificato nel callback specificato quando è disponibile una risposta per una sua richiesta. Il correlationId ti dirà a quale richiesta è rivolta la risposta. Quindi la tua ultima sfida è restituire questa risposta al thread che mantiene la connessione client.

Questo può essere ottenuto creando un dizionario con i valori di correlazione (probabilmente GUID) come chiave e le risposte come valore. Quando il tuo ruolo web riceve una richiesta, crea il guid, lo imposta come correlationId, lo aggiunge hashset, attiva il messaggio in coda e chiama Monitor.Wait() sull'oggetto Guid. Quindi fare in modo che il metodo di ricezione richiamato dalla sottoscrizione dell'argomento aggiunga la risposta al dizionario e quindi chiama Monitor.Notify() su quello stesso oggetto guid. Questo risveglia il thread di richiesta originale e ora puoi restituire la risposta al tuo cliente (O qualcosa.) Fondamentalmente vuoi solo che il tuo thread dorme e non consumare risorse mentre aspetti)

1

Non c'è nulla di intrinseco alle code di Windows Azure che fa ciò che stai chiedendo. Tuttavia, potresti costruirlo da solo abbastanza facilmente. Includere un ID messaggio (GUID) nel push alla coda e al termine dell'elaborazione, chiedere al lavoratore di inviare un nuovo messaggio con quell'ID messaggio in una coda canale di risposta. La tua app Web può eseguire il polling di questa coda per determinare quando l'elaborazione è stata completata per un dato comando.

Abbiamo fatto qualcosa di simile e stiamo cercando di utilizzare qualcosa come SignalR per aiutare a rispondere al client quando i comandi sono completati.

+0

Questo è quello che stavo pensando. Stiamo già includendo una strategia GUID per la correlazione, ma sembra che ci sia un sacco di polling su quella coda di risposta in cui il ruolo Web attira risposte irrilevanti. Quando chiamo GetMessage() c'è un modo per rilasciarlo rapidamente nel probabile evento che non è la risposta che stavo aspettando? Oppure, in alternativa, potrei dare a ogni istanza di ruolo Web una coda dedicata. Anche allora, queste code non sono FIFO, quindi dovrei comunque verificare l'id di correlazione. Pensieri? –

+0

Il problema è che se si dispone di più di un'istanza di webrole (o anche di richieste diff in esecuzione sullo stesso ruolo Web), esiste la possibilità che il messaggio destinato all'istanza 1 venga prelevato dall'istanza 2, che verrà controlla l'id di correlazione, renditi conto che non lo sta aspettando e devi rimetterlo in coda. Ho provato questo e non scala molto bene. L'idea del tavolo è molto meglio. – knightpfhor

+0

Grazie per aver aggiunto questo commento. Ero preoccupato di questa cosa, considerando che IIS può elaborare molte richieste contemporaneamente nella stessa casella. –

2

Consenti al ruolo del lavoratore di continuare a eseguire il polling e di elaborare il messaggio. Non appena il messaggio viene elaborato, aggiungere una voce in Archiviazione tabella con CorelationId richiesto (RowKey) e il risultato dell'elaborazione, prima di eliminare il messaggio elaborato dalla coda.

Poi WebRoles solo bisogno di fare uno sguardo up del tavolo con il desiderato correlationId (RowKey) & PartitionKey

+0

Idea molto interessante. Mi piace questo adattamento, perché solo il ruolo Web che ha avviato la richiesta deve vedere la risposta. Avrò bisogno di una sorta di garbage collector per le voci di Storage di tabella orfane che non vengono mai visualizzate in caso di errori di Web Role. –

+0

Non penso che sia una buona idea. Quindi, in pratica, stai creando un nuovo sistema di coda (utilizzando la memorizzazione della tabella) anziché utilizzare le funzioni dedicate coda/argomento in Azure. Inoltre dovresti eseguire il polling della memoria della tabella per la risposta = molto inefficiente e non scalabile. – Haukman

3

Le code sul bus Azure Servizio hanno molte più funzionalità e paradigmi tra cui pub/sub Funzioni che possono risolvere i problemi relativi alla manutenzione delle code su più istanze.

Un approccio con pub/sub, è avere una coda per le richieste e una per le risposte. Ogni istanza richiedente sarebbe anche iscriversi alla coda di risposta con un filtro sull'intestazione in modo tale da ricevere solo le risposte a esso indirizzate. Il messaggio di richiesta, ovviamente, contiene il valore per il posto nell'intestazione della risposta per guidare il filtro.

+0

Benvenuti in StackOverflow.Apprezzo la tua risposta e controllerò l'opzione Bus di servizio. Ho notato che le altre risposte erano correlate ad Azure. Spero di leggere molti come loro! –

+0

Grazie per l'ottima accoglienza. Spero di dare più contributi. Sì, la mia attuale esperienza è tutta legata all'azzurro. – hocho

2

Dai un'occhiata a SignalR tra il ruolo di lavoratore e il client del browser. Quindi il tuo ruolo web mette un messaggio in coda e restituisce un risultato al browser (qualcosa di semplice come 'attesa ...') e collegalo al ruolo di lavoratore con SignalR. In questo modo il tuo ruolo Web continua a fare altre cose e non deve aspettare un risultato dall'elaborazione asincrona, solo il browser deve.

3

Per la soluzione basata Service Bus ci sono campioni disponibili per l'attuazione del modello di richiesta/risposta con Queues e Topics (pub-sub)

+0

Grazie. Ha una funzione per garantire che, mentre la risposta è destinata all'abbonato, la risposta sia effettivamente correlata alla richiesta originale? –

+1

Allo stesso modo in cui una coda semplice consente di competere per i messaggi, una coda di bus di servizio abilitata per la sessione consente di competere per le sessioni. Qui puoi specificare un SessionId e quindi bloccare quella sessione. Tutti i messaggi inviati a quella sessione verranno consegnati solo a te. Pertanto, se ogni sottoscrittore ha il proprio ID univoco che utilizza come SessionID e quindi lo invia nei messaggi come ReplyToSessionId, l'unico codice necessario per garantire che la risposta sia correlata è quello per il messaggio di risposta impostato: ReplyMessage.SessionId = RequestMessage. ReplyToSessionId. Questo modello è mostrato nei campioni. –

+1

Grazie per la risposta. Ti ho votato Ho scelto la risposta da [@Henrikmh] (http://stackoverflow.com/users/859401/henrikmh) a causa dell'ultimo paragrafo sull'utilizzo del dizionario come meccanismo di correlazione. Avremo molte richieste simultanee dallo stesso host. La Sessione risolve il problema di iscrizione per l'host specificato, ma non per ogni richiesta concorrente. Credo che tu possa averlo lasciato come esercizio per il lettore. :-) –