Dzisiaj zajmiemy się Kafką, czyli jednym z brokerów wiadomości. Na pierwszy rzut oka może być podobny do RabbitMQ czy ActiveMQ, ale szczegóły robią tutaj dużą różnice. W tym wpisie nie będziemy kodować i patrzeć jak wysyłać czy odbierać wiadomości, a omówimy sobie trochę architekturę Kafki oraz jak jest zaimplementowana.
Zaczniemy sobie patrzeć na to wszystko z góry i postaramy się zagłębiać w poszczególne elementy Kafki.
Główne elementy układanki
Przyjrzymy się najpierw główny elementom, które będą występować w każdym środowisku gdzie jest Kafka.
Producenci
Producenci są to aplikacje, które tworzą wiadomości oraz je wysyłają do Kafki.
Konsumenci
Konsumerami nazywamy aplikacje, które mają za zadanie odbieranie wiadomości wcześniej wysłanych przez Producentów.
Ekosystem Kafki
Przez ekosystem Kafki powinniśmy rozumieć Klaster Kafki, na który składają się Brokerzy, oraz Zookeepera.
Opis zaczniemy od opisu Ekosystemu Kafki, żebyśmy mogli zapoznać się z głównymi pojęciami, których będziemy używać przy opisywaniu Producentów i Konsumentów.
Topic
Topic jest kluczowym pojęciem w kwestii zrozumienia jak działa Kafka. Jest on odpowiednikiem kolejki w innych brokerach wiadomości. Czyli jest to miejsce gdzie wiadomości są wysyłane, a następnie odbierane.
Najpierw zacznijmy od tego, jak wiadomości są przechowywane przez Kafkę. Kafką tworzy plik logów (dlatego czasami możemy się spotkać z uzyciem pojęcia logów w kontekście Kafki), do którego kolejne wiadomości są dopisywane na koniec tego pliku. Na powyższym obrazku możemy zobaczyć prosty przykład Topica, który przechowuje w tej chwili 8 otrzymanych wiadomości zapisanych w ten kolejności, w której zostały otrzymane. Kolejna wiadomość, w naszym przykładzie 9, będzie zapisana na końcu tego pliku.
Partycje
Kafka zapewnia nam skalowalność, wysoką wydajność czy odporność na błędy. Na naszym ostatnim przykładzie możemy zauważyć, iż mogłoby to być ciężkie do osiągnięcia gdyby budowa Topica, była taka prosta. Z pomocą tutaj przychodzą partycje.
Każdy Topic jest podzielony na 1 lub więcej partycji. Nasz pierwszy przykład pokazywał Topic, w którym była tylko jedna partycja. W naszym obecnym przykładzie możemy zauważyć, iż nasz Topic w tej chwili posiada 3 partycje. Każda z partycji jest osobnym plikiem logów, do którego zapisywane są kolejne wiadomości. Architektura ta wymusza, iż kolejność wysłanych wiadomości jest zachowana tylko w obrębie jednej partycji, a nie całego Topicu.
Jak widać, dzięki zastotowaniu partycji Kafka zyskuje na skalowalności oraz wydajności przetwarzania eventów. Do odporności na błędy wrócimy za kilka chwil. Najpierw powiedzmy sobie jeszcze na jakiej podstawie jest wybierana partycja dla wysłanej wiadomości.
Wybór partycji
Partycja dla wysyłanej wiadomości jest wybierana na jeden z poniższych sposobów
Round-Robin
Domyślnym algorytmem wybory partycji jest algorytm Round-Robin. Oznacza to, iż kolejne wiadomości będę trafiały do kolejnych partycji.
Partition Key
Kolejnym sposobem wyboru partcji jest tak zwany Partition Key. Przy wysyłaniu wiadomości Procudent może zdefiniować klucz, dła którego zostanie wyliczony hash, a następnie na tej podstawie wiadomość trafi do konkretnej partycji. Zasada działania jest tutaj podobna do mechanizmu, który jest w HashMapie.
Algorytm ten jest przydatny wtedy, kiedy zależy nam na zachowaniu kolejności przetwarzanych wiadomości dla eventów wygenerowanych na przykład dla tego samego usera.
Custom Partitioner
Ostatnim sposobem wybory partycji jest customowy partitioner napisany przez deweloperów uwzgledniający logikę biznesową aplikacji.
Replikacja
I teraz wracamy do wspomnianej wcześniej odporności na błędy i tego jak Kafka sobie z nimi radzi. Kafka posiada mechanizm replikacji, który tworzy repliki danych, dzięki którym choćby gdy jeden z brokerów padnie to żadne dane nie są tracone oraz wciąż pozostają dostępne.
Na powyższym przykładzie możemy zobaczyc sytuacje gdzie dla jednego Topica mamy 3 partycje. Każda z partycji ma dodatkowo jednę replike, która jest na innym brokerze. Każda z partycji ma swojego lidera, który odpowiada za zapis danych oraz za ich replikacje do innych brokerów. W przypadku awarii lidera jedna z replik (follower) przejmuje jego rolę.
Zookeeper
Jednym z elementów ekosystemu Kafki jest Zookeeper. Zookeeper jest odpowidzialny między innymi za:
- wybór lidera partycji – w przypadku awarii brokera, który zawiera Lidera partycji wybierany jest nowy Lider
- konfiguracje Topiców – zawiera informacje o wszystkich Topicach, liczbie replik, liderach, itp.
- konfiguracje Brokerów – zawiera informacje o wszystkich Brokerach, które wchodzą w skład naszego klastra
- ustawienia kontroli dostępu
Warto tutaj zaznaczyć również, iż od wersji 3.2.0 Kafka nie wymaga Zookeepera do prawidłowego działania.
Producent
Producent, czyli aplikacja odpowiadająca za wysyłanie wiadomości, publikuje wiadomość na jeden z Topiców.
Wiadomość
Każda wiadomość może składać się z następujących części:
- klucz (opcjonalnie) – o ile klucz jest podany wtedy jest używany do wyboru partycji, na który trafia wiadomość (czyli wszystkie wiadomości opublikowane z tym samym kluczem trafią na te samą partycję, a co za tym idzie będzie zachowana ich kolejność wysłania w obrębie właśnie tej partycji); o ile klucz nie jest podany to wiadomość będzie opublikowana w partycji zgodnie ze wspomnianym algorytmem Round-Robin lub przy użyciu Custom Partitionera, o ile taki jest zaimplementowany.
- wartość – część wiadomości, zawierająca dane biznesowe
- nagłowki (opcjonalnie) – dowolne nagłówki, które możey ustawić, a następnie wykorzystać przy obieraniu wiadomości
- timestamp – po prostu znacznik czasu
Wysyłka
Gdy producent ma już przygotowaną wiadomość to nie pozostaje mu nic innego jak jak wysłanie jej na wybrany Topic.
Konsument
Ostatnim elementem w naszej układance są konsumenci. Na początku musimy zaznaczyć, iż Kafka w odróżnienia od innych implementacji kolejek nie wypycha wiadomości do konsumentów. W Kafce to konsumenci muszą odczytywać wiadomości z poszczególnych partycji w ramach wybranego tematu.
Każdy Konsument posiada swój kursor, który wskazuje na kolejną wiadomość w partycji, która będzie odczytana. Po odczytaniu wiadomości rolą Konsumenta jest przesunięcie kursora, na kolejną wiadomość. Mechanizm ten zapewnia, iż wiadomości z danej partycji są odczytywane dokładnie w tej kolejności w jakiej zotały na nią zapisane.
Grupa Konsumentów
Consumer groups to mechanizm w Kafce, który umożliwia wielu klientom jednoczesne odbieranie danych z tematów. Grupa konsumentów to logiczna jednostka, która składa się z jednego lub więcej konsumentów, którzy odbierają wiadomości z tematu. Każdy konsument może odbierać wiadomości z dowolnej liczby partycji. Natomiast z jednej partycji może wiadomości odbierać maksymalnie jeden Konsument w ramach jednej Grupy Konsumentów. Może to brzmieć trochę zawile, ale jak zerkniemy na poniższe przykłady to wszystko powinno stać się jasne.
Na powyższym przykładzie widzimy 3 Grupy Konsumentów, które odczytują wiadomości z jednego Tematu. Jak możemy zauważyć każda z Grup ma inną liczbę Konsumentów, a każdy z nich ma przypisany jedną lub więcej partycji do odczytu.
Na powyższym obrazku mamy z kolei przykład gdzie Grupa Konsumentów, zawiera więcej Konsumentów niż jest partycji w danym Temacie. W takim przypadku jeden z Konsumentów pozostaje nieaktywny i nie wykonuje żadnej pracy związanej z odczytywaniem wiadomości.
Podsumowanie
W tym wpisie przeanalizowaliśmy z jakich elementów składa się Ekosystem Kafki. Poznaliśmy również jakie elementy powodują to, iż Kafka może byc tak wydajna, w jaki sposób się skaluje oraz dzięki czemu jest zapewniona trwałość danych w Kafce.