Redis i Python – dobrze dobrana para #5

Witam ponownie.

Poprzedni wpis z tej serii w zasadzie wyczerpał podstawowe typy danych dostępne w Redisie. W tym artykule przyjrzymy się więc mechanizmowi pub-sub. Skrót ten rozwija się do publish-subscribe i jest on implementacją wzorca o tej samej nazwie.

Słowem wstępu

Wzorzec publish-subscribe jest wzorcem wymiany komunikatów. Polega on na tym, że komponenty wysyłające wiadomości nie wysyłają ich do konkretnie określonej listy odbiorców. Można powiedzieć więcej – nie wiedzą nawet czy ktokolwiek wiadomość otrzyma. Podobnie ma się sprawa z komponentami odbierającymi wiadomości – nie wiedzą one kto wysyła daną wiadomość. Obie strony dzieli „kanał komunikatów”. To ten byt na który publikujący wypycha wiadomości i z którego subskrybent owe wiadomości odbiera.

Największą zaletą tego wzorca jest łatwość dodawania kolejnych elementów do już istniejącej układanki. Jest on bardzo odporny na rozbudowę „farmy” zarówno subskrybentów jak i publikujących. Zaleta ta, jeśli spojrzymy na nią pod innym kątem, jest również wadą. Tak silne rozdzielenie komponentów od siebie powoduje, że publikujący mogą wrzucać kolejne wiadomości gdy subskrybenci wcale nie nasłuchują na nie. Brakuje im po prostu wiedzy o tym ilu subskrybentów jest podłączonych.

Mówiąc obrazem, działa to tak:

A w naszym przypadku Message Broker to Redis.

Implementacja w Redisie

Kanał komunikatów, wspomniany przeze mnie w poprzednim rozdziale, w redisie jest po prostu pewnym kluczem. Załóżmy, że w naszym przykładzie będzie to klucz o nazwie „testowa_kanal_komunikacyjny”. Napiszmy subskrybenta:

1
2
3
4
5
6
7
8
9
from redis import Redis

redis_connection = Redis(decode_responses=True)

pubsub = redis_connection.pubsub()
pubsub.subscribe("testowa_kanal_komunikacyjny")

for message in pubsub.listen():
  print(message)

Po uruchomieniu tego kawałka kodu nasz subskrybent odbiera pierwszą wiadomość, tzw. powitalną, informującą, że się podłączyliśmy. Wygląda ona tak:

{'type': 'subscribe', 'pattern': None, 'channel': 'testowa_kanal_komunikacyjny', 'data': 1}

po czym blokuje się, w oczekiwaniu na kolejne komunikaty.

Teraz, jeśli skorzystamy z konsoli redis-cli i uruchomimy komendę:

publish testowa_kanal_komunikacyjny testowa_wiadomosc

to dostaniemy w naszym programie od razu wysłana wiadomość:

{'type': 'message', 'pattern': None, 'channel': 'testowa_kanal_komunikacyjny', 'data': 'testowa_wiadomosc'}

Czekaj, stop!

Podoba Ci się to co tworzę? Jeśli tak to zapraszam Cię do zapisania się na newsletter:

Aby potwierdzić swoją subskrypcję, odbierz pocztę i kliknij w link potwierdzający:) jeśli maila nie ma to poczekaj chwile i/lub sprawdź folder spam/inne/oferty itp :)

Aby potwierdzić swoją subskrypcję, odbierz pocztę i kliknij w link potwierdzający:) jeśli maila nie ma to poczekaj chwile i/lub sprawdź folder spam/inne/oferty itp :)
a w ramach prezentu otrzymasz całkowicie za darmo, dwa dokumenty PDF „6 (nie zawsze oczywistych) błędów popełnianych podczas nauki programowania” który jest jednym z efektów ponad siedmioletniej pracy i obserwacji rozwoju niejednego programisty oraz „Wstęp do testowania w Pythonie”, będący wprowadzeniem do biblioteki PyTest.
Jeśli to Cię interesuje to zapraszam również na swoje social media.

Jak i do ewentualnego postawienia mi kawy :)

I co, tylko tyle?

Aż tyle! Pozwala nam to na szybką komunikację międzyprocesową, a jeśli zachodzi potrzeba, to i pomiędzy osobnymi maszynami komunikacja zajdzie. Dodatkowo można się subskrybować nie na konkretny kanał, a na pattern, tzn jeśli w naszej aplikacji mamy kanały:

  • tasks_1
  • tasks_2
  • tasks_3

i chcielibyśmy, korzystając z jednego subskrybenta, podłączyć się do tych kanałów, możemy po prostu podłączyć się pod pattern „tasks_*”:

1
2
3
4
5
6
7
8
9
from redis import Redis

redis_connection = Redis(decode_responses=True)

pubsub = redis_connection.pubsub()
pubsub.psubscribe("tasks_*")

for message in pubsub.listen():
  print(message)

i teraz, jeśli z konsoli wykonamy:

127.0.0.1:6379> publish tasks_1 test
(integer) 1
127.0.0.1:6379> publish tasks_2 test
(integer) 1
127.0.0.1:6379> publish tasks_3 test
(integer) 1

to dostaniemy w programie:

{’type’: 'pmessage’, 'pattern’: 'tasks_*’, 'channel’: 'tasks_1′, 'data’: 'test’}
{’type’: 'pmessage’, 'pattern’: 'tasks_*’, 'channel’: 'tasks_2′, 'data’: 'test’}
{’type’: 'pmessage’, 'pattern’: 'tasks_*’, 'channel’: 'tasks_3′, 'data’: 'test’}

Kilka ważnych cech

  • Jeśli wyślemy wiadomość, gdy subskrybent nie będzie podłączony, to nie otrzyma on jej po podłączeniu (brak kolejkowania jak w przypadku list).
  • Kanały są dzielone pomiędzy bazami, tzn jeśli wypchniemy wiadomość na kanał na jednej bazie, to obserwując kanał na innej, otrzymamy ją.
  • Złożoność obliczeniowa:
    • PUBLISH: O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
    • SUBSCRIBE: O(N) where N is the number of channels to subscribe to.
  • Wydajność rozwiązania jest ładnie opisana tutaj – nie ma sensu powielać, ale jest sens zlinkować.
  • Nie stoi nic na przeszkodzie żeby subskrybent coś wypychał na ten sam lub inny kanał.
  • Publikujący nie dostają żadnej informacji zwrotnej.
Dzięki za wizytę,
Mateusz Mazurek
Mateusz M.

Ostatnie wpisy

Podsumowanie: maj, czerwiec, lipiec i sierpień 2024

Oj daaawnoo mnie tu nie było. Ale wakacje to był czas dużej liczby intensywnych wyjazdów i tak naprawdę, dopiero jakoś… Read More

2 miesiące ago

Podsumowanie: kwiecień 2024

Cześć! Zapraszam na krótkie podsumowanie kwietnia. Wyjazd do Niemiec A dokładniej pod granicę z Francją. Chrześnica miała pierwszą komunię. Po… Read More

6 miesięcy ago

Podsumowanie: luty i marzec 2024

Ostatnio tygodnie były tak bardzo wypełnione, że nie udało mi się napisać nawet krótkiego podsumowanie. Więc dziś zbiorczo podsumuję luty… Read More

7 miesięcy ago

Podsumowanie: styczeń 2024

Zapraszam na krótkie podsumowanie miesiąca. Książki W styczniu przeczytałem "Homo Deus: Historia jutra". Książka łudząco podoba do wcześniejszej książki tego… Read More

9 miesięcy ago

Podsumowanie roku 2023

Cześć! Zapraszam na podsumowanie roku 2023. Książki Zacznijmy od książek. W tym roku cel 35 książek nie został osiągnięty. Niemniej… Read More

10 miesięcy ago

Podsumowanie: grudzień 2023

Zapraszam na krótkie podsumowanie miesiąca. Książki W grudniu skończyłem czytać Mein Kampf. Nudna książka. Ciekawsze fragmenty można by było streścić… Read More

10 miesięcy ago