1:Der er kun én kanal i dit eksempel (Test
); en kanal er blot det navn, der bruges til en bestemt pub/underbørs. Det er dog nødvendigt at bruge 2 forbindelser på grund af detaljer om, hvordan Redis API fungerer. En forbindelse, der har enhver abonnementer kan ikke gøre andet end:
- lyt til beskeder
- administrere sine egne abonnementer (
subscribe
,psubscribe
,unsubscribe
,punsubscribe
)
Jeg forstår dog ikke dette:
private static Dictionary<string, RedisSubscriberConnection>
Du bør ikke have brug for mere end én abonnentforbindelse, medmindre du sørger for noget specifikt for dig. En enkelt abonnentforbindelse kan håndtere et vilkårligt antal abonnementer. Et hurtigt tjek på client list
på en af mine servere, og jeg har én forbindelse med (i skrivende stund) 23.002 abonnementer. Hvilket nok kunne reduceres, men:det virker.
2:mønsterabonnementer understøtter jokertegn; så i stedet for at abonnere på /topic/1
, /topic/2/
osv. du kan abonnere på /topic/*
. Navnet på den faktiske kanal brugt af publish
leveres til modtageren som en del af tilbagekaldssignaturen.
Begge kan virke. Det skal bemærkes, at udførelsen af publish
er påvirket af det samlede antal unikke abonnementer - men ærligt talt er det stadig dumt hurtigt (som i:0ms), selvom du har titusindvis af flere tusinde abonnenter, der bruger subscribe
i stedet for psubscribe
.
Men fra publish
Tidskompleksitet:O(N+M), hvor N er antallet af klienter, der abonnerer på den modtagende kanal, og M er det samlede antal abonnerede mønstre (af enhver klient).
Jeg anbefaler at læse redis-dokumentationen af pub/sub.
Rediger for at følge spørgsmål:
a) Jeg går ud fra, at jeg bliver nødt til at "publicere" synkront (ved hjælp af Resultat eller Wait()), hvis jeg vil garantere, at rækkefølgen af afsendelse af elementer fra samme udgiver bevares, når jeg modtager varer, ikke?
det vil ikke gøre nogen forskel overhovedet; siden du nævner Result
/ Wait()
, jeg antager, at du taler om BookSleeve - i hvilket tilfælde multiplexeren allerede bevarer kommandorækkefølgen. Redis selv er enkelttrådet og vil altid behandle kommandoer på en enkelt forbindelse i rækkefølge. Dog:tilbagekaldene på abonnenten kan udføres asynkront og kan overføres (separat) til en arbejdstråd. Jeg er i øjeblikket ved at undersøge, om jeg kan tvinge dette til at være i orden fra RedisSubscriberConnection
.
Opdatering:fra 1.3.22 og fremefter kan du indstille CompletionMode
til PreserveOrder
- så vil alle tilbagekald blive gennemført sekventielt i stedet for samtidigt.
b) efter at have foretaget justeringer i henhold til dine forslag, opnår jeg en fantastisk ydeevne, når jeg udgiver få elementer, uanset størrelsen af nyttelasten. Men når du sender 100.000 eller flere elementer fra den samme udgiver, falder ydeevnen hurtigt (ned til 7-8 sekunder bare at sende fra min maskine).
For det første lyder den tid høj - ved at teste lokalt får jeg (for 100.000 publikationer, inklusive at vente på svar for dem alle) 1766 ms (lokalt) eller 1219 ms (fjernbetjening) (det lyder måske kontraintuitivt, men mit "lokale" er ikke kører den samme version af redis; min "fjernbetjening" er 2.6.12 på Centos; min "lokal" er 2.6.8-pre2 på Windows).
Jeg kan ikke gøre din egentlige server hurtigere eller fremskynde netværket, men:hvis dette er pakkefragmentering, har jeg tilføjet (kun for dig) en SuspendFlush()
/ ResumeFlush()
par. Dette deaktiverer ivrig skylning (dvs. når sendekøen er tom; andre typer skylning sker stadig); du kan finde, at dette hjælper:
conn.SuspendFlush();
try {
// start lots of operations...
} finally {
conn.ResumeFlush();
}
Bemærk, at du ikke bør Wait
indtil du er genoptaget, fordi indtil du kalder ResumeFlush()
der kan stadig være nogle operationer i send-bufferen. Med det hele på plads får jeg (for 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 mere med fjernservere, da det vil lægge færre pakker gennem netværket.
Jeg kan ikke bruge transaktioner, fordi de emner, der skal offentliggøres senere, ikke er alle tilgængelige på én gang. Er der en måde at optimere med den viden i tankerne?
Jeg tror som er adresseret af ovenstående - men bemærk, at CreateBatch
for nyligt blev også tilføjet. En batch fungerer meget som en transaktion - bare:uden transaktionen. Igen er det en anden mekanisme til at reducere pakkefragmentering. I dit særlige tilfælde formoder jeg, at suspendering/genoptagelse (ved flush) er dit bedste bud.
Anbefaler du at have én generel RedisConnection og én RedisSubscriberConnection eller en hvilken som helst anden konfiguration for at få en sådan indpakning til at udføre de ønskede funktioner?
Så længe du ikke udfører blokeringsoperationer (blpop
, brpop
, brpoplpush
osv.), eller sætter overdimensionerede BLOB'er ned i ledningen (potentielt forsinker andre operationer, mens det rydder), så fungerer en enkelt forbindelse af hver type normalt ret godt. Men YMMV afhængig af dine nøjagtige brugskrav.