Service Broker - Conversation Lifetime?


9

Stiamo cercando di far funzionare Service Broker nel nostro ambiente al fine di risolvere un caso aziendale. Non so se il titolo del messaggio sia buono, ma la mia domanda è sotto. Ma potrebbe non essere una buona domanda, quindi dopo è quello che stiamo facendo e perché penso che sia la domanda giusta.

Quanti messaggi devono essere inviati in una conversazione prima di terminare la conversazione?

Vogliamo utilizzare Service Broker per aggiornare in modo asincrono una tabella dei risultati. La tabella dei risultati è piatta e veloce. Abbiamo trigger sulle tabelle di base che inviano un messaggio con la loro tabella e chiave primaria. Abbiamo tre code:

  • Bassa latenza - l'obiettivo è l'elaborazione di 15 secondi. Gestisce gli articoli che cambiano in relazione a un articolo specifico.
  • Coda in blocco: l'elaborazione richiede 5 minuti. Gestisce quando cambia qualcosa che interessa molte centinaia (o migliaia) di oggetti. Separa l'elenco degli elementi interessati e li inserisce nella coda di latenza bassa posticipata
  • Bassa latenza differita - l'obiettivo è l'elaborazione di 30 minuti. Questo elabora gli elementi ma solo dalla coda in blocco.

Fondamentalmente, se le informazioni di un cliente vengono aggiornate; ciò influisce su molti prodotti in modo che venga inviato alla coda in blocco per un'elaborazione più lenta. Tuttavia, se un prodotto viene aggiornato, viene inviato alla coda a bassa latenza.

Riutilizziamo conversazioni simili al blog di Remus Rusanu http://rusanu.com/2007/04/25/reusing-conversations/ , con l'eccezione che lo facciamo in base al modulo della chiave primaria. Questo ha il vantaggio secondario di aiutare nella deduplicazione della chiave primaria.

Quindi, riutilizziamo le conversazioni e rientriamo nelle nostre linee guida. Con due thread, sono stato in grado di masterizzare 125 messaggi / secondo (calo artificiale di diverse migliaia di messaggi), che è più che in grado di tenere il passo con la produzione (circa 15 messaggi / sec).

Tuttavia, il problema che stiamo riscontrando è che dopo un periodo di tempo, ~ 4 ore o 120.000 messaggi, abbiamo iniziato a vedere blocchi e contese elevate su sysdesend e sulla tabella delle code. I blocchi sono LCK_M_U e sono blocchi KEY. A volte hobt si risolve in sysdesend e altre volte nella tabella delle code specifica (queue_).

Abbiamo un processo in atto che terminerà le conversazioni dopo 24 ore o 30 minuti di inattività già, quindi potremmo semplicemente aumentare il tempo prima di passare in rassegna le conversazioni.

Stiamo usando SQL 2016 Enterprise (13.0.4001.0)

  1. Attiva incendi (invia a bassa latenza o in blocco)
  2. Cerca o crea un handle di conversazione.
  3. invia messaggio
  4. Procedura attivata in coda
  5. Aggiorna la tabella dei risultati

Il processo di pulizia viene eseguito ogni 10 minuti per vedere se ci sono conversazioni inattive. se li trova più di tre volte di seguito, lo contrassegna come inattivo e termina le conversazioni.

Per favore fatemi sapere se ci sono ulteriori dettagli che potrebbero essere utili. Non ho molta esperienza con Service Broker, quindi non so se i nostri messaggi / sec sono bassi, alti o indifferenti.

AGGIORNARE

Quindi oggi abbiamo riprovato e abbiamo riscontrato lo stesso problema. Abbiamo modificato la durata della conversazione in 2 ore e questo non ha avuto alcun effetto. Quindi abbiamo implementato il trucco 150; che aveva lo stesso problema.

Tonnellate di attese su INVIO CONVERSAZIONE, in attesa su sysdesend. Qualcuno ha ulteriori idee?

AGGIORNAMENTO 2

Abbiamo eseguito il test più a lungo oggi e per uno dei periodi di esempio di 17 minuti, abbiamo elaborato 41K messaggi su 4 handle di conversazione. Siamo riusciti a tenere il passo tranne verso la fine quando i blocchi sul sysdesend e sul tavolo della coda sono diventati troppo e abbiamo iniziato a vagare dietro prima di fermarlo. Sembra che non abbiamo problemi nell'elaborare i messaggi, senza che le cose entrino nella coda, possiamo tirarli fuori ed elaborarli almeno 5 volte quella velocità. La nostra velocità sembra essere limitata in base all'aggiunta di messaggi.

In un test successivo, abbiamo rimosso uno dei trigger che rappresentavano l'80% dei messaggi. Anche con questo carico molto ridotto, abbiamo iniziato a vedere le stesse attese.

AGGIORNAMENTO 3

Grazie, Remus per il tuo consiglio (e grazie per aver pubblicato articoli di blog così eccellenti sull'argomento, sono stati fondamentali per arrivare a questo punto).

Lo abbiamo eseguito di nuovo oggi e abbiamo fatto di meglio (come siamo andati più a lungo prima di vedere le attese e anche più a lungo prima che ci paralizzasse). Quindi, i dettagli.

Abbiamo modificato: * Aumentato il numero di conversazioni mantenute per thread da 1: 1 a 2: 1. Fondamentalmente, avevamo 8 handle di conversazione per 4 thread.

  • consolidata la coda di massa (perché un messaggio in arrivo potrebbe significare centinaia di messaggi in uscita) per consolidare in un numero minore di messaggi più grandi.

Note su questo tentativo:

  • disabilitando la procedura di attivazione della coda di destinazione. nessun cambiamento nel blocco (abbiamo aspettato 5 minuti) e i messaggi sono stati inviati a sys.transmission_queues.

  • monitoraggio di sys.conversation_endpoints. Questo numero è passato da 0 a 13K molto rapidamente, e poi è aumentato più lentamente durante il giorno fino a circa 25K dopo ~ 5 ore. Il blocco non ha iniziato a verificarsi fino a quando non ha raggiunto 16K +/-

  • Sono entrato nel DAC ed ho eseguito i comandi DBREINDEX per le code, anche se da una query i record di fantasmi non hanno mai superato i 200 o giù di lì prima che arrivasse la pulizia e trascinavo il conteggio a 0.

  • sysdesend e sysdercv avevano conteggi identici di 24.932 quando ho terminato il test.

  • abbiamo elaborato ~ 310.000 messaggi in 5 ore.

Siamo andati così a lungo prima che le cose andassero in pezzi che pensavo davvero che ce l'avremmo fatta questa volta. Domani proveremo a forzare i messaggi a passare il filo.


1
we started seeing blocks and high contention on sysdesend and the queue table.-> Qual è il tipo di attesa - PAGELATCH_EX/SH and WRITELOG? Hai usato il trucco 150 ? Se le tabelle di sistema sono il tuo punto di contesa, il trucco di 150 sarà molto utile.
Kin Shah,

@kin, ho aggiornato la domanda, ma i tipi di blocco sono LCK_M_U o LCK_M_X. Avevo letto del trucco di 150 ma speravo che non fosse necessario nel 2016 (dal momento che avevano anche risolto il problema delle perdite di tempdb), ma anche perché sembra un tale hack. Faremo un'altra pugnalata all'entrata in produzione (purtroppo lo incontreremo solo con i carichi di lavoro di produzione) e proveremo prima conversazioni più brevi. Aggiornerò qui con i risultati. Il prossimo sarà il 150 trucco a cui hai fatto riferimento.
Jonathan Fite,

Ho chiesto a @RemusRusanu su Twitter: è l'esperto in materia di broker di servizi :-)
Kin Shah,

Questo non è qualcosa che ho visto prima (degrado di SEND dopo un lungo periodo di tempo). 1) per favore dimmi qual è il numero di righe sys.conversation_endpointsdurante il test (costante o in aumento, e quanto è grande quando si verifica il blocco). 2) Quando si verifica il blocco, la disabilitazione della coda di destinazione fa la differenza nel blocco SEND (la disabilitazione della coda deve indirizzare SEND a sys.transmission_queue). e 3) Forzare i messaggi a passare al cavo, anche localmente (impostare endpoint SSB, aggiungere percorsi) cambia il comportamento a lungo termine
Remus Rusanu,

Qualche altro pensiero: 4) quando si verifica un blocco, l'arresto di RECEIVE sul target fa la differenza (disabilita l'eventuale proc attivato) e 5) quanti record fantasma sono nella coda target? La corsa ALTER QUEUE ... REBUILDfa la differenza una volta iniziato il blocco?
Remus Rusanu,

Risposte:


3

So che è una cattiva forma rispondere alla tua domanda, ma volevo chiuderlo per chiunque fosse interessato. Finalmente siamo riusciti a risolvere il problema, o almeno a risolverlo abbastanza per soddisfare i nostri requisiti. Voglio ringraziare tutti coloro che hanno contribuito con i commenti; Remus Rusanu e Kin sono stati molto utili.

Il nostro database è piuttosto occupato ed è in modalità RCSI. Abbiamo più (migliaia) di dispositivi mobili che aggiornano le informazioni sulla loro posizione ogni 45 secondi. Attraverso questi aggiornamenti, più tabelle ottengono le loro informazioni aggiornate (design scadente, poiché avrei limitato le informazioni volatili a una singola tabella e poi le avrei unite per i risultati). Queste tabelle sono le stesse per le quali stavamo tentando di generare in modo asincrono le informazioni sui rapporti anziché fare in modo che gli utenti finali vadano direttamente contro le tabelle di base.

Inizialmente abbiamo avuto i trigger facendo un cursore sui record modificati in ogni istruzione update / insert (nella maggior parte dei casi avrebbe dovuto essere una riga) e inviando ogni chiave primaria in un messaggio al broker del servizio. All'interno del broker di servizi, in particolare la coda di massa, c'erano ulteriori cursori che eseguivano la procedura di aggiornamento per il report (un'esecuzione per chiave primaria).

Cosa ci ha fatto finalmente lavorare:

  • Abbiamo rimosso i cursori e deciso di inviare messaggi più grandi. Ancora un messaggio per transazione dell'utente per tabella, ma ora inviamo messaggi con più di una chiave primaria.

  • Il processore di massa invia inoltre più chiavi per messaggio, il che ha ridotto il numero di CONVERSAZIONI DI INVIO in corso mentre mescolava i messaggi all'altra coda, a seconda dei casi.

  • La tabella più volatile (la nostra tabella di dati del dispositivo mobile) è stata rimossa dai trigger. Abbiamo aggiornato la procedura di upsert per includere le chiavi esterne appropriate e ora ci uniamo nuovamente a quella tabella quando recuperiamo i risultati per gli utenti. Questa tabella ha contribuito facilmente all'80% dei messaggi che abbiamo dovuto elaborare in un giorno.

Elaboriamo ~ 1 milione di messaggi al giorno (senza la tabella Mobile) e la stragrande maggioranza (99% +) dei nostri messaggi viene elaborata all'interno del nostro obiettivo. Abbiamo ancora qualche anomalia occasionale, ma data la natura rara di ciò che è ritenuto accettabile.

Fattori contribuenti:

  • Ho trovato un bug nella procedura di pulizia delle conversazioni menzionata in precedenza che in realtà non puliva le conversazioni in modo appropriato e le terminava prematuramente. Ciò ha portato ora il nostro conteggio del sysdesend a non essere mai più di qualche migliaio (la maggior parte di ciò deriva dall'uso del trucco 150).

  • I cursori nei trigger sembrano contenere più blocchi del previsto (anche con static, forward_only). la rimozione di questi sembra aver reso le serrature che vediamo su INVIA CONVERSAZIONE in natura più transitorie (o almeno le volte che vediamo sono molto più basse).

  • Stavamo essenzialmente eseguendo due soluzioni affiancate (il back-end della soluzione di Service Broker (per i test sotto carico di produzione)) e la soluzione attuale (terribile query che si estende su molte tabelle).

Come vantaggio collaterale, questo ha scoperto un problema di pulizia dei record di Ghost e sebbene non si trovasse sulle tabelle di Service Broker (sistema o coda), è piuttosto dilagante nel nostro sistema e i sintomi si allineano molto bene con la nostra "causa non chiara" problemi che sperimentiamo a volte. Sono in corso delle indagini su questo, stiamo cercando di trovare le tabelle che stanno contribuendo ad esso e probabilmente ricostruiremo regolarmente i loro indici.

Grazie ancora.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.