Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Jak działa PubSub w BookSleeve/Redis?

1:w twoim przykładzie jest tylko jeden kanał (Test ); kanał to tylko nazwa używana dla określonej giełdy pub/sub. Konieczne jest jednak użycie 2 połączeń ze względu na specyfikę działania redis API. Połączenie, które ma dowolne subskrypcje nie mogą robić nic innego oprócz:

  • odsłuchaj wiadomości
  • zarządzaj własnymi subskrypcjami (subscribe , psubscribe , unsubscribe , unsubscribe )

Jednak nie rozumiem tego:

private static Dictionary<string, RedisSubscriberConnection>

Nie powinieneś potrzebować więcej niż jednego połączenia abonenckiego, chyba że zaspokajasz coś konkretnego. Pojedyncze połączenie abonenckie może obsłużyć dowolną liczbę subskrypcji. Szybkie sprawdzenie client list na jednym z moich serwerów i mam jedno połączenie z (w chwili pisania tego tekstu) 23 002 subskrypcjami. Który prawdopodobnie można by zmniejszyć, ale:to działa.

2:subskrypcje wzorców obsługują symbole wieloznaczne; więc zamiast subskrybować /topic/1 , /topic/2/ itp. możesz subskrybować /topic/* . Nazwa rzeczywistego kanał używany przez publish jest dostarczana do odbiorcy jako część sygnatury wywołania zwrotnego.

Albo może działać. Należy zauważyć, że wydajność publish ma wpływ na całkowitą liczbę unikalnych subskrypcji - ale szczerze mówiąc, nadal jest idiotycznie szybki (na przykład:0 ms), nawet jeśli masz dziesiątki tysięcy subskrybowanych kanałów za pomocą subscribe zamiast psubscribe .

Ale od publish

Złożoność czasowa:O(N+M), gdzie N to liczba klientów zasubskrybowanych do kanału odbiorczego, a M to całkowita liczba subskrybowanych wzorców (przez dowolnego klienta).

Polecam przeczytanie dokumentacji redis pub/sub.

Edytuj w celu śledzenia pytań:

a) Zakładam, że musiałbym „publikować” synchronicznie (za pomocą Result lub Wait()), jeśli chcę zagwarantować, że kolejność wysyłania elementów od tego samego wydawcy zostanie zachowana podczas odbierania elementów, prawda?

to nie zrobi żadnej różnicy; skoro wspominasz Result / Wait() , zakładam, że mówisz o BookSleeve - w takim przypadku multiplekser już zachowuje kolejność poleceń. Sam Redis jest jednowątkowy i zawsze przetwarza polecenia w jednym połączeniu w kolejności. Jednak:wywołania zwrotne na subskrybencie mogą być wykonywane asynchronicznie i mogą być przekazywane (oddzielnie) do wątku roboczego. Obecnie sprawdzam, czy mogę wymusić to, aby to było w porządku z RedisSubscriberConnection .

Aktualizacja:od 1.3.22 możesz ustawić CompletionMode do PreserveOrder - wtedy wszystkie wywołania zwrotne będą realizowane sekwencyjnie, a nie jednocześnie.

b) po wprowadzeniu poprawek zgodnie z Waszymi sugestiami uzyskuję świetne wyniki przy publikowaniu kilku pozycji bez względu na wielkość ładunku. Jednak przy wysyłaniu 100 000 lub więcej elementów przez tego samego wydawcę wydajność gwałtownie spada (do 7-8 sekund tylko po to, aby wysłać z mojego komputera).

Po pierwsze, ten czas brzmi wysoko - testuję lokalnie (na 100 000 publikacji, wliczając w to oczekiwanie na odpowiedź na wszystkie z nich) 1766 ms (lokalnie) lub 1219 ms (zdalnie) (to może brzmieć sprzecznie z intuicją, ale mój „lokalny” nie jest t z tą samą wersją redis; mój "zdalny" to 2.6.12 na Centos; mój "lokalny" to 2.6.8-pre2 na Windows).

Nie mogę przyspieszyć twojego rzeczywistego serwera ani przyspieszyć sieci, ale:na wypadek fragmentacji pakietów, dodałem (tylko dla ciebie) SuspendFlush() / ResumeFlush() para. Wyłącza to zachłanne opróżnianie (tj. gdy kolejka wysyłania jest pusta; inne rodzaje opróżniania nadal się zdarzają); może się okazać, że to pomoże:

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

Pamiętaj, że nie powinieneś Wait dopóki nie wznowisz, ponieważ dopóki nie wywołasz funkcji ResumeFlush() w buforze wysyłania mogą nadal znajdować się pewne operacje. Mając to wszystko na miejscu, otrzymuję (za 100 000 operacji):

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

Jak widać, bardziej pomaga w przypadku serwerów zdalnych, ponieważ będzie przesyłać mniej pakietów przez sieć.

Nie mogę użyć transakcji, ponieważ później pozycje, które mają zostać opublikowane, nie są dostępne od razu. Czy istnieje sposób na optymalizację, mając na uwadze tę wiedzę?

myślę jest to adresowane przez powyższe - ale zauważ, że ostatnio CreateBatch został również dodany. Paczka działa bardzo podobnie do transakcji - po prostu:bez transakcji. Ponownie, jest to kolejny mechanizm zmniejszania fragmentacji pakietów. Podejrzewam, że w twoim konkretnym przypadku zawieszenie/wznowienie (przy spłukaniu) jest najlepszym wyborem.

Czy zaleca się posiadanie jednego ogólnego połączenia RedisConnection i jednego połączenia RedisSubscriberConnection lub jakiejkolwiek innej konfiguracji, aby takie opakowanie spełniało pożądane funkcje?

Dopóki nie wykonujesz operacji blokujących (blpop , brpop , brpoplpush itp.) lub umieszczając zbyt duże obiekty BLOB w sieci (potencjalnie opóźniając inne operacje podczas ich czyszczenia), wtedy pojedyncze połączenie każdego typu zwykle działa całkiem nieźle. Ale YMMV w zależności od dokładnych wymagań użytkowania.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mechanizm blokady magazynu Redis (lub dowolnej bazy danych?) (NodeJS)

  2. Trwałe dane z Redis do MongoDB dla magazynu danych

  3. Nie można połączyć klastra Redis w Elasticache z PHP za pomocą biblioteki phpredis

  4. StackExchange.Redis:dostęp wsadowy dla wielu skrótów

  5. Python - Jak sprawdzić, czy serwer Redis jest dostępny?