2009-08-12 13 views
15

Sono un novizio di SQL Server Service Broker e sto cercando di cogliere il modo migliore per impostare Service Broker per un (apparentemente) semplice caso d'uso: voglio creare una semplice coda di lavoro, dove una applicazione rilascia oggetti di lavoro nella coda e l'applicazione separata preleva gli articoli di lavoro da quella coda e li elabora. Non è necessario che la prima applicazione recuperi i messaggi di stato dal secondo. Voglio che la coda vada in una singola istanza di Sql Server.SQL Server Service Broker: come strutturare le conversazioni per uno scenario di coda semplice?

Ciò che più mi confonde è il modo in cui le conversazioni/i dialoghi si riferiscono a questa situazione. So che è possibile inviare/ricevere messaggi solo nel contesto di una conversazione/dialogo, ma poiché non vi sono chiacchiere tra le due applicazioni, mi sento perso quando è il momento giusto per creare una nuova conversazione. Le due alternative estreme sembrano essere:

  • Ogni volta che accodamento di un oggetto di lavoro, inizio una nuova conversazione. Quindi ogni conversazione finisce per avere esattamente un messaggio al suo interno.
  • Al momento della distribuzione, creo manualmente una singola conversazione con durata infinita. Quando è il momento di accodare un oggetto di lavoro, lo invio sempre come parte di quella singola conversazione.

Quali sarebbero le conseguenze di una di queste rotte?

Inoltre, nel primo caso, sembra che sia necessario eseguire alcune CONVERSAZIONI FINE, in modo che Sql Server sia in grado di pulire internamente le risorse. C'è qualche indicazione su quando sarebbe il posto giusto dove inserirli? (Oppure potrebbe essere preferibile affidarsi alla fine delle conversazioni?)

+0

Sembra che tu stia parlando di una singola coda, ma ... http://stackoverflow.com/questions/14643015/why-do-i-need-two-sql-server-service-broker-code-for-a-simple-task – cja

risposta

26

Si dovrebbe iniziare con ciascuna voce di lavoro nella propria conversazione. Il produttore (iniziatore) avvia una finestra di dialogo e invia il messaggio che descrive l'oggetto di lavoro, quindi esegue il commit. Il consumatore (obiettivo) riceve il messaggio (o viene attivato), ispeziona il carico utile per comprendere i dettagli dell'elemento di lavoro, esegue il lavoro, quindi chiude la finestra di dialogo e esegue il commit. Il messaggio EndDialog risultante viene rinviato alla coda di servizio initiator e una procedura attivata sulla coda del programma di inizializzazione risponde ad essa terminando la finestra di dialogo sul lato dell'iniziatore.

Questa è la distribuzione più semplice e la messa in funzione assicurerà una solida base su cui costruire. Non tagliare gli angoli e terminare la finestra di dialogo sul lato dell'iniziatore da quando il produttore accoda l'oggetto di lavoro, questo è fire-and-forget and has several draw backs.

Se si dispone di requisiti di prestazioni elevate (oltre 200 richieste al secondo), sarà necessario iniziare a gestire le conversazioni in modo più esplicito. Ho un post di blog su reusing conversations for performance reasons. Sul lato ricevente consiglio di leggere Writing Service Broker Procedures.

Ho anche un post di blog che fa praticamente tutto ciò di cui hai bisogno, anche se non pianifica gli elementi di lavoro ma avvia una procedura personalizzata: Asynchronous procedure execution.

Se si decide di utilizzare gli elementi di lavoro da un contesto attivato, sfruttando le funzionalità di auto bilanciamento dell'attivazione, è necessario disporre di understand the EXECUTE AS context under which activation occurs.

+0

Un altro vantaggio del riutilizzo delle conversazioni è che si evita il problema descritto in "Microsoft Internal Work Request 642585" (non pubblico). Vale a dire, ogni conversazione creata e distrutta perde una piccola quantità di spazio allocato in TempDB che non viene rilasciato finché non si rimbalza l'istanza. Nelle applicazioni ad alto throughput questo può far saltare le dimensioni di TempDB e forzare il riavvio dell'istanza a ridurlo di nuovo. –

+0

Un problema con l'utilizzo di una conversazione separata con ciascun messaggio è che le conversazioni possono comparire dall'altra parte fuori sequenza. Questo può accadere anche se hai solo un thread sul lato ricevente. Ricorda che Service Broker garantisce solo la sequenza all'interno di una conversazione. L'intera ragione delle conversazioni è gestire il sequenziamento quando ci sono più thread sul lato ricevente della coda. Se le conversazioni fossero mantenute in sequenza così come i messaggi proibirebbe l'uso di più thread di ricezione. –

9

Mi piace molto la risposta di Remus, anche se non tocca in particolare perché si potrebbe preferire l'avvio di una conversazione separata per elemento di lavoro, piuttosto che mettere tutti gli elementi di lavoro in una singola conversazione.Due note relative a questo:

Innanzitutto, mettere tutti gli elementi di lavoro in una singola conversazione causerà probabilmente problemi di concorrenza se si hanno più thread/processi che elaborano elementi di lavoro. Servizio processi di lavoro mediatore tendono ad assomigliare a questo (in pseudocodice):

begin transaction 
receive top n work items from queue 
process work items 
commit transaction 

(da non commettere fino a quando gli elementi di lavoro sono trattati con successo, ci si assicura, per esempio, che se il processo muore, allora gli elementi di lavoro che ha ricevuto

Il problema della concorrenza si verifica perché il broker di servizio è programmato in modo tale che ogni comando RECEIVE acquisisca un blocco di lettura esclusivo su tutti i messaggi nella coda che condividono la stessa conversazione (o gruppo di conversazione) come quelli che erano RECEIVEd. Questo blocco viene mantenuto fino a quando la transazione non viene eseguita. (Vedere Conversation Group Locks.) Quindi, se tutti gli elementi di lavoro in coda sono in una singola conversazione, mentre un processo di lavoro si trova nel passaggio "processi di lavoro", nessun altro processo di lavoro può svolgere alcun lavoro.

Un secondo problema con il mettere molti articoli in una singola conversazione è che aumenta la quantità di oggetti di lavoro che potresti perdere o dover rielaborare in determinate condizioni di errore. Per descriverlo correttamente, rimando a Remus; vedere il suo Recycling Conversations, in particolare la parte che dice "riutilizzare una singola finestra di dialogo per inviare tutti i messaggi [...] è come mettere tutte le uova in un unico cesto". Potresti riuscire a recuperare da alcune di queste situazioni di errore, ma probabilmente introdurrà più complessità al tuo codice.

Probabilmente ci sono alcuni argomenti in più contro l'utilizzo di una singola conversazione per tutti gli elementi di lavoro, ma non ho familiarità con loro.

Questo non vuol dire che la soluzione corretta è sempre quella di iniziare una conversazione separata per ogni singolo oggetto di lavoro. Dopo aver letto i post di Remus, però, il suo consiglio sembra valido; iniziare con un elemento di lavoro per conversazione, quindi aggiungere complessità se necessario. (Ma probabilmente in nessun caso dovresti andare all'estremo di mettere tutti i messaggi in una singola conversazione.)

Problemi correlati