sql >> Databáze >  >> NoSQL >> Redis

Jak funguje PubSub v BookSleeve/Redis?

1:ve vašem příkladu je pouze jeden kanál (Test ); kanál je pouze název používaný pro konkrétní burzu pub/sub. Je však nutné použít 2 spojení kvůli specifikům toho, jak redis API funguje. Připojení, které má jakékoli odběry nemohou dělat nic jiného než:

  • poslouchat zprávy
  • spravovat vlastní odběry (subscribe , psubscribe , unsubscribe , punsubscribe )

Tomu však nerozumím:

private static Dictionary<string, RedisSubscriberConnection>

Neměli byste potřebovat více než jedno účastnické připojení, pokud nezajišťujete něco specifického pro vás. Jedno připojení předplatitele může zpracovat libovolný počet předplatných. Rychlá kontrola client list na jednom z mých serverů a mám jedno připojení s (v době psaní tohoto článku) 23 002 předplatnými. Což by se asi dalo snížit, ale:funguje to.

2:předplatné vzorů podporuje zástupné znaky; takže raději než se přihlásit k odběru /topic/1 , /topic/2/ atd. můžete se přihlásit k odběru /topic/* . Název skutečného kanál používaný publish je poskytován příjemci jako součást podpisu zpětného volání.

Obojí může fungovat. Je třeba poznamenat, že výkon publish je ovlivněno celkovým počtem unikátních odběrů – ale upřímně řečeno je to stále hloupě rychlé (např.:0 ms), i když máte desítky tisíc odebíraných kanálů pomocí subscribe spíše než psubscribe .

Ale z publish

Časová složitost:O(N+M), kde N je počet klientů přihlášených k přijímacímu kanálu a M je celkový počet vzorů předplatitelů (jakýmkoli klientem).

Doporučuji přečíst si dokumentaci redis pub/sub.

Upravit pro sledování otázek:

a) Předpokládám, že bych musel "publikovat" synchronně (pomocí Result nebo Wait()), pokud chci zaručit, že pořadí odesílání položek od stejného vydavatele bude zachováno i při příjmu položek, že?

to nebude mít vůbec žádný rozdíl; protože jste zmínil Result / Wait() Předpokládám, že mluvíte o BookSleeve - v takovém případě multiplexer již zachovává příkazový řád. Samotný Redis je jednovláknový a vždy zpracuje příkazy na jednom připojení v pořadí. Nicméně:zpětná volání na účastníkovi mohou být prováděna asynchronně a mohou být předána (samostatně) pracovnímu vláknu. Momentálně zjišťuji, zda mohu vynutit, aby to bylo v pořádku z RedisSubscriberConnection .

Aktualizace:od 1.3.22 můžete nastavit CompletionMode na PreserveOrder - pak budou všechna zpětná volání dokončena postupně, nikoli souběžně.

b) po úpravách podle vašich návrhů dosahuji skvělého výkonu při publikování několika položek bez ohledu na velikost užitečného zatížení. Při odesílání 100 000 nebo více položek stejným vydavatelem však výkon rapidně klesá (až na 7–8 sekund, stačí odeslat z mého počítače).

Za prvé, ta doba zní hodně – při místním testování dostanu (pro 100 000 publikací, včetně čekání na odezvu na všechny z nich) 1766 ms (místní) nebo 1219 ms (vzdálené) (to může znít neintuitivně, ale moje „místní“ není Používám stejnou verzi redis; můj „vzdálený“ je 2.6.12 na Centos; můj „místní“ je 2.6.8-pre2 na Windows).

Nemohu váš skutečný server zrychlit ani zrychlit síť, ale:v případě, že se jedná o fragmentaci paketů, přidal jsem (jen pro vás) SuspendFlush() / ResumeFlush() pár. Tím se zakáže eager-flushing (tj. když je fronta odesílání prázdná; stále dochází k jiným typům splachování); možná vám pomůže toto:

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

Pamatujte, že byste neměli Wait dokud nebudete pokračovat, protože dokud nezavoláte ResumeFlush() v send-bufferu mohou být stále nějaké operace. Když je vše na místě, dostávám (za 100 000 operací):

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

Jak můžete vidět, pomáhá to více se vzdálenými servery, protože to bude dávat méně paketů přes síť.

Nemohu použít transakce, protože později položky, které mají být zveřejněny, nejsou všechny dostupné najednou. Existuje způsob optimalizace s ohledem na tyto znalosti?

Myslím to je řešeno výše - ale všimněte si, že nedávno CreateBatch byl také přidán. Dávka funguje velmi podobně jako transakce – jen:bez transakce. Opět je to další mechanismus pro snížení fragmentace paketů. Ve vašem konkrétním případě se domnívám, že pozastavení/obnovení (na flush) je vaše nejlepší sázka.

Doporučujete mít jedno obecné připojení RedisConnection a jedno připojení RedisSubscriberConnection nebo jakoukoli jinou konfiguraci, aby takový obal mohl provádět požadované funkce?

Dokud neprovádíte operace blokování (blpop , brpop , brpoplpush atd.), nebo položením příliš velkých objektů BLOB dolů (potenciálně zdržením jiných operací, zatímco se vyčistí), pak jediné připojení každého typu obvykle funguje docela dobře. Ale YMMV v závislosti na vašich přesných požadavcích na použití.




  1. Jak nakonfigurujete Embedded MongDB pro testování integrace v aplikaci Spring Boot?

  2. Porovnání mangoose _id a řetězců

  3. Automatické zvýšení sekvence v mongodb pomocí Java

  4. Jak nainstalovat Redis