1:er is maar één kanaal in uw voorbeeld (Test
); een kanaal is gewoon de naam die wordt gebruikt voor een bepaalde pub/sub-uitwisseling. Het is echter noodzakelijk om 2 verbindingen . te gebruiken vanwege details over hoe de redis-API werkt. Een connectie die elke . heeft abonnementen kunnen niets anders doen dan:
- luister naar berichten
- zijn eigen abonnementen beheren (
subscribe
,psubscribe
,unsubscribe
,punsubscribe
)
Ik begrijp dit echter niet:
private static Dictionary<string, RedisSubscriberConnection>
U zou niet meer dan één abonneeverbinding nodig moeten hebben, tenzij u voor iets specifieks voor u zorgt. Een enkele abonneeverbinding kan een willekeurig aantal abonnementen aan. Een snelle controle op client list
op een van mijn servers, en ik heb één verbinding met (op het moment van schrijven) 23.002 abonnementen. Dat kan waarschijnlijk worden verminderd, maar:het werkt.
2:patroonabonnementen ondersteunen wildcards; dus in plaats van je te abonneren op /topic/1
, /topic/2/
enz. je zou je kunnen abonneren op /topic/*
. De naam van de echte kanaal gebruikt door publish
wordt aan de ontvanger verstrekt als onderdeel van de terugbelhandtekening.
Beide kunnen werken. Opgemerkt moet worden dat de prestaties van publish
wordt beïnvloed door het totale aantal unieke abonnementen - maar eerlijk gezegd is het nog steeds idioot snel (zoals in:0ms), zelfs als je tienduizenden duizenden geabonneerde kanalen hebt die subscribe
gebruiken in plaats van psubscribe
.
Maar van publish
Tijdcomplexiteit:O(N+M) waarbij N het aantal klanten is dat is geabonneerd op het ontvangende kanaal en M het totale aantal geabonneerde patronen is (door elke klant).
Ik raad aan om de redis-documentatie van pub/sub te lezen.
Bewerken voor vervolgvragen:
a) Ik neem aan dat ik synchroon moet "publiceren" (met behulp van Result of Wait()) als ik wil garanderen dat de volgorde van het verzenden van items van dezelfde uitgever behouden blijft bij het ontvangen van items, correct?
dat maakt helemaal niets uit; aangezien u Result
. vermeldt / Wait()
, ik neem aan dat je het over BookSleeve hebt - in dat geval behoudt de multiplexer de opdrachtvolgorde al. Redis zelf is single-threaded en zal opdrachten altijd op een enkele verbinding in volgorde verwerken. Echter:de callbacks op de abonnee kunnen asynchroon worden uitgevoerd en (afzonderlijk) worden overgedragen aan een worker-thread. Ik ben momenteel aan het onderzoeken of ik dit kan afdwingen vanuit RedisSubscriberConnection
.
Update:vanaf 1.3.22 kun je de CompletionMode
. instellen naar PreserveOrder
- dan worden alle callbacks opeenvolgend voltooid in plaats van gelijktijdig.
b) na het maken van aanpassingen volgens uw suggesties krijg ik een geweldige prestatie bij het publiceren van weinig items, ongeacht de grootte van de payload. Wanneer echter 100.000 of meer items door dezelfde uitgever worden verzonden, daalt de prestatie snel (tot 7-8 seconden om vanaf mijn computer te verzenden).
Ten eerste klinkt die tijd hoog - lokaal testen krijg ik (voor 100.000 publicaties, inclusief wachten op de reactie voor allemaal) 1766 ms (lokaal) of 1219 ms (op afstand) (dat klinkt misschien contra-intuïtief, maar mijn "lokale" is' ik gebruik niet dezelfde versie van redis; mijn "remote" is 2.6.12 op Centos; mijn "lokale" is 2.6.8-pre2 op Windows).
Ik kan je eigenlijke server niet sneller maken of het netwerk versnellen, maar:voor het geval dit pakketfragmentatie is, heb ik (alleen voor jou) een SuspendFlush()
toegevoegd / ResumeFlush()
paar. Dit schakelt gretig doorspoelen uit (d.w.z. wanneer de verzendwachtrij leeg is; andere soorten doorspoelen gebeuren nog steeds); je zou kunnen merken dat dit helpt:
conn.SuspendFlush();
try {
// start lots of operations...
} finally {
conn.ResumeFlush();
}
Houd er rekening mee dat u niet moet Wait
totdat u bent hervat, want totdat u ResumeFlush()
. aanroept er kunnen nog enkele bewerkingen in de verzendbuffer zitten. Als dat allemaal op zijn plaats is, krijg ik (voor 100.000 bewerkingen):
local: 1766ms (eager-flush) vs 1554ms (suspend-flush)
remote: 1219ms (eager-flush) vs 796ms (suspend-flush)
Zoals je kunt zien, helpt het meer met externe servers, omdat het minder pakketten door het netwerk zal sturen.
Ik kan geen transacties gebruiken omdat de later te publiceren items niet allemaal tegelijk beschikbaar zijn. Is er een manier om te optimaliseren met die kennis in gedachten?
Ik denk dat wordt behandeld door het bovenstaande - maar merk op dat onlangs CreateBatch
werd ook toegevoegd. Een batch werkt veel als een transactie - alleen:zonder de transactie. Nogmaals, het is een ander mechanisme om pakketfragmentatie te verminderen. In jouw specifieke geval vermoed ik dat de onderbreking/hervatting (bij flush) de beste keuze is.
Beveelt u aan om één algemene RedisConnection en één RedisSubscriberConnection of een andere configuratie te hebben om een dergelijke wrapper de gewenste functies te laten uitvoeren?
Zolang u geen blokkeerbewerkingen uitvoert (blpop
, brpop
, brpoplpush
enz.), of het plaatsen van te grote BLOB's door de draad (mogelijk andere bewerkingen vertragen terwijl het wordt gewist), dan werkt een enkele verbinding van elk type meestal redelijk goed. Maar YMMV hangt af van uw exacte gebruiksvereisten.