Redis
 sql >> Database >  >> NoSQL >> Redis

Come funziona PubSub in BookSleeve/ Redis?

1:c'è un solo canale nel tuo esempio (Test ); un canale è solo il nome utilizzato per un particolare scambio pub/sub. Tuttavia, è necessario utilizzare 2 connessioni a causa delle specifiche di come funziona l'API redis. Una connessione che ha qualsiasi gli abbonamenti non possono fare altro se non:

  • ascolta i messaggi
  • gestire le proprie iscrizioni (subscribe , psubscribe , unsubscribe , punsubscribe )

Tuttavia, non capisco questo:

private static Dictionary<string, RedisSubscriberConnection>

Non dovresti aver bisogno di più di una connessione di abbonati a meno che tu non stia provvedendo a qualcosa di specifico per te. Una singola connessione di abbonato può gestire un numero arbitrario di abbonamenti. Un rapido controllo su client list su uno dei miei server e ho una connessione con (al momento in cui scrivo) 23.002 abbonamenti. Che probabilmente potrebbe essere ridotto, ma:funziona.

2:le sottoscrizioni ai pattern supportano i caratteri jolly; quindi piuttosto che iscriversi a /topic/1 , /topic/2/ ecc potresti iscriverti a /topic/* . Il nome del effettivo canale utilizzato da publish viene fornito al destinatario come parte della firma di richiamata.

Entrambi possono funzionare. Va notato che le prestazioni di publish è influenzato dal numero totale di iscrizioni univoche, ma francamente è ancora stupidamente veloce (come in:0ms) anche se hai decine di migliaia di canali a cui sei iscritto usando subscribe anziché psubscribe .

Ma da publish

Complessità temporale:O(N+M) dove N è il numero di client iscritti al canale ricevente e M è il numero totale di pattern iscritti (da qualsiasi client).

Consiglio di leggere la documentazione redis di pub/sub.

Modifica per seguire le domande:

a) Presumo che dovrei "pubblicare" in modo sincrono (usando Result o Wait()) se voglio garantire che l'ordine di invio degli articoli dallo stesso editore venga mantenuto durante la ricezione degli articoli, corretto?

questo non farà alcuna differenza; poiché menzioni Result / Wait() , suppongo che tu stia parlando di BookSleeve, nel qual caso il multiplexer conserva già l'ordine dei comandi. Redis stesso è a thread singolo ed elaborerà sempre i comandi su una singola connessione in ordine. Tuttavia:i callback sull'abbonato possono essere eseguiti in modo asincrono e possono essere consegnati (separatamente) a un thread di lavoro. Attualmente sto valutando se posso forzare questo in ordine da RedisSubscriberConnection .

Aggiornamento:dalla 1.3.22 in poi puoi impostare il CompletionMode a PreserveOrder - quindi tutte le richiamate verranno completate in sequenza anziché contemporaneamente.

b) dopo aver apportato modifiche in base ai tuoi suggerimenti, ottengo un'ottima performance pubblicando pochi elementi indipendentemente dalle dimensioni del payload. Tuttavia, quando si inviano 100.000 o più articoli dallo stesso editore, le prestazioni diminuiscono rapidamente (fino a 7-8 secondi solo per l'invio dalla mia macchina).

In primo luogo, quel tempo sembra alto:testando localmente ottengo (per 100.000 pubblicazioni, inclusa l'attesa della risposta per tutte) 1766 ms (locale) o 1219 ms (remoto) (potrebbe sembrare controintuitivo, ma il mio "locale" non lo è t esegue la stessa versione di redis; il mio "telecomando" è 2.6.12 su Centos; il mio "locale" è 2.6.8-pre2 su Windows).

Non posso rendere il tuo server più veloce o velocizzare la rete, ma:nel caso si tratti di frammentazione di pacchetti, ho aggiunto (solo per te) un SuspendFlush() / ResumeFlush() paio. Questo disabilita lo svuotamento ansioso (cioè quando la coda di invio è vuota; si verificano ancora altri tipi di svuotamento); potresti scoprire che questo aiuta:

conn.SuspendFlush();
try {
    // start lots of operations...
} finally {
    conn.ResumeFlush();
}

Nota che non dovresti Wait fino a quando non hai ripreso, perché fino a quando non chiami ResumeFlush() potrebbero esserci ancora alcune operazioni nel buffer di invio. Con tutto ciò a posto, ottengo (per 100.000 operazioni):

local: 1766ms (eager-flush) vs 1554ms (suspend-flush)
remote: 1219ms (eager-flush) vs 796ms (suspend-flush)

Come puoi vedere, aiuta di più con i server remoti, poiché invierà meno pacchetti attraverso la rete.

Non posso utilizzare le transazioni perché in seguito gli elementi da pubblicare non sono tutti disponibili contemporaneamente. C'è un modo per ottimizzare tenendo presente questa conoscenza?

penso che è affrontato da quanto sopra - ma nota che recentemente CreateBatch è stato aggiunto anche. Un batch funziona in modo molto simile a una transazione, solo:senza la transazione. Ancora una volta, è un altro meccanismo per ridurre la frammentazione dei pacchetti. Nel tuo caso particolare, sospetto che la sospensione/ripresa (a colore) sia la soluzione migliore.

Consigli di avere un RedisConnection generale e un RedisSubscriberConnection o qualsiasi altra configurazione per fare in modo che tale wrapper esegua le funzioni desiderate?

Finché non stai eseguendo operazioni di blocco (blpop , brpop , brpoplpush ecc.), o mettendo BLOB di grandi dimensioni lungo il cavo (potenzialmente ritardando altre operazioni mentre si cancella), quindi una singola connessione di ogni tipo di solito funziona abbastanza bene. Ma YMMV dipende dai tuoi esatti requisiti di utilizzo.