sql >> Databasteknik >  >> NoSQL >> Redis

Hur fungerar PubSub i BookSleeve/ Redis?

1:det finns bara en kanal i ditt exempel (Test ); en kanal är bara namnet som används för en viss pub/underbörs. Det är dock nödvändigt att använda 2 anslutningar på grund av detaljer om hur Redis API fungerar. En anslutning som har någon prenumerationer kan inte göra något annat än:

  • lyssna på meddelanden
  • hantera sina egna prenumerationer (subscribe , psubscribe , unsubscribe , punsubscribe )

Jag förstår dock inte detta:

private static Dictionary<string, RedisSubscriberConnection>

Du bör inte behöva mer än en abonnentanslutning om du inte sörjer för något specifikt för dig. En enskild abonnentanslutning kan hantera ett godtyckligt antal abonnemang. En snabb kontroll av client list på en av mina servrar, och jag har en anslutning med (i skrivande stund) 23 002 prenumerationer. Vilket förmodligen skulle kunna minskas, men:det fungerar.

2:mönsterprenumerationer stöder jokertecken; så istället för att prenumerera på /topic/1 , /topic/2/ etc kan du prenumerera på /topic/* . Namnet på den faktiska kanal som används av publish tillhandahålls till mottagaren som en del av återuppringningssignaturen.

Båda kan fungera. Det bör noteras att prestanda för publish påverkas av det totala antalet unika prenumerationer - men ärligt talat går det fortfarande dumt snabbt (som i:0ms) även om du har tiotusentals prenumererade kanaler som använder subscribe istället för psubscribe .

Men från publish

Tidskomplexitet:O(N+M) där N är antalet klienter som prenumererar på den mottagande kanalen och M är det totala antalet prenumererade mönster (av vilken klient som helst).

Jag rekommenderar att du läser redis-dokumentationen för pub/sub.

Redigera för att följa frågor:

a) Jag antar att jag måste "publicera" synkront (med Result eller Wait()) om jag vill garantera att ordningen för att skicka objekt från samma utgivare bevaras när jag tar emot objekt, eller hur?

det kommer inte att göra någon skillnad alls; eftersom du nämner Result / Wait() , jag antar att du pratar om BookSleeve - i vilket fall multiplexern redan bevarar kommandoordningen. Redis i sig är entrådad och kommer alltid att bearbeta kommandon på en enda anslutning i ordning. Emellertid:återuppringningarna på abonnenten kan utföras asynkront och kan lämnas (separat) till en arbetstråd. Jag undersöker för närvarande om jag kan tvinga detta att vara i ordning från RedisSubscriberConnection .

Uppdatering:från 1.3.22 och framåt kan du ställa in CompletionMode till PreserveOrder - då kommer alla återuppringningar att slutföras sekventiellt snarare än samtidigt.

b) efter att ha gjort justeringar enligt dina förslag får jag en bra prestanda när jag publicerar få artiklar oavsett storleken på nyttolasten. Men när du skickar 100 000 eller fler objekt från samma utgivare sjunker prestanda snabbt (ned till 7-8 sekunder bara för att skicka från min maskin).

För det första låter den tiden hög - när jag testar lokalt får jag (för 100 000 publikationer, inklusive att vänta på svar för alla) 1766ms (lokalt) eller 1219ms (fjärr) (det kan låta kontraintuitivt, men min "lokala" är inte köra samma version av redis; min "fjärrkontroll" är 2.6.12 på Centos; min "lokala" är 2.6.8-pre2 på Windows).

Jag kan inte göra din faktiska server snabbare eller påskynda nätverket, men:om detta är paketfragmentering har jag lagt till (bara för dig) en SuspendFlush() / ResumeFlush() par. Detta inaktiverar eager-spolning (dvs. när sändningskön är tom; andra typer av spolning sker fortfarande); du kanske tycker att det här hjälper:

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

Observera att du inte ska Wait tills du har återupptagit, för tills du anropar ResumeFlush() det kan finnas några operationer kvar i send-bufferten. Med allt på plats får jag (för 100 000 operationer):

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

Som du kan se hjälper det mer med fjärrservrar, eftersom det kommer att lägga färre paket genom nätverket.

Jag kan inte använda transaktioner eftersom de objekt som ska publiceras senare inte är tillgängliga på en gång. Finns det något sätt att optimera med den kunskapen i åtanke?

Jag tror som behandlas av ovanstående - men notera att nyligen CreateBatch lades till också. En batch fungerar mycket som en transaktion - bara:utan transaktionen. Återigen är det en annan mekanism för att minska paketfragmentering. I just ditt fall misstänker jag att avstängning/återuppta (vid spolning) är din bästa insats.

Rekommenderar du att ha en allmän RedisConnection och en RedisSubscriberConnection eller någon annan konfiguration för att ett sådant omslag ska utföra önskade funktioner?

Så länge du inte utför blockeringsåtgärder (blpop , brpop , brpoplpush etc), eller att lägga överdimensionerade BLOBs ner i tråden (potentiellt försena andra operationer medan det rensas), då fungerar vanligtvis en enkel anslutning av varje typ ganska bra. Men YMMV beroende på dina exakta användningskrav.




  1. Redis SYNC och EXEC

  2. Finns det någon låsmekanism i Azure Redis Cache när du uppdaterar ett objekt?

  3. Komma igång med MongoDB och Mongoose

  4. Kan jag serialisera ett ruby ​​Digest::SHA1-instansobjekt?