Apache Kafka - opis działania i zastosowania
Dlaczego powinieneś się zainteresować Kafką
Lockdown, miliony ludzi na całym Świecie zamykani są w domach. Krach na giełdzie i kolejne obostrzenia doprowadza ludzi do bankructwa. Rządy zaczynają odbierać kolejne wolności. Co robią ludzie w tej kafkowskiej rzeczywistości?
Łącza internetowy rozgrzewają się do czerwoności. Zakupy, gastronomia, nauczanie. Wszystko przenosi się do wirtualnej rzeczywistości. DevOpsi na całym Świecie robią w gacie. Mimo nieoczekiwanego i nagłego nasilenia ruchu nadal działają filmy na Netfliksie. DevOpsi kupują nowe gacie na Zalando, płacąc przez PayPal. Ludzie, którzy stracili pracę, mogą szybko stworzyć swoje profile na LinkedIn, dokształcać się na Coursera.
Co łączy te wszystkie firmy? Wiele rzeczy. Ale chodziło mi o wykorzystanie w mniejszym lub większym stopniu Apache Kafka. Platforma, która już na stałe wpisała się w krajobraz architektoniczny systemów muszących skalować się błyskawicznie, działać asynchronicznie i – z punktu widzenia użytkownika – w czasie rzeczywistym. Jeżeli przejrzysz ogłoszenia o pracę, na pewno znajdziesz też tam Kafkę. Więc warto coś o niej wiedzieć, zwłaszcza że najprostszy, użyteczny projekt możesz napisać w godzinę.
Takie języki jak Java, C#, C++, C, Go, Python posiadają oficjalnie wspierane biblioteki do integracji z Kafką. Sama Kafka napisana jest w większości w Scala. Confluent zostało złożone przez oryginalnych twórców, którzy zaczęli pracę nad Kafką w 2011 roku w LinkedIn, potem projekt przeszedł pod egidę Apache i stał się tym samym open source.
Confluent oferuje własne rozwiązania zapewniające wszystkie potrzebne komponenty do postawienia i zarządzania infrastrukturą w popularnych środowiskach chmurowych lub na serwerach dedykowanych. Podstawowe projekty od Confluence są open source lub mają tzw. Community License. Te bardziej złożone są już przeznaczone raczej dla większych organizacji i są płatne.
Czym jest Kafka
Czym jest Kafka? Jest to platforma do przetwarzania strumieni danych (event streaming platform). Pierwszy rzut na architekturę wskazuje, że jest to nic innego jak broker wiadomości, taki jak RabbitMQ, czy Amazon SQS. Mamy producentów i konsumentów, pomiędzy którymi możemy wymieniać asynchronicznie wiadomości.
Różnica tkwi w szczegółach. Kafka mocno stawia na wydajność i skalowalność. Pozwala na konfigurację wielu parametrów, dzięki czemu możemy dostosować sposób działania do specyfiki danych, którymi akurat operujemy, ich wielkości, częstotliwości potrzeby ich odczytu.
Do tego mamy możliwość konfiguracji tego, jak długo wysyłane wiadomości będą przechowywane. W odróżnieniu od typowego brokera wiadomości dane nie będą usunięte tuż po odebraniu wiadomości przez adresata. W Apache Kafka adresat nie jest znany przy wysyłaniu wiadomości. Model publish/subscribe nie opisuje dobrze tego, jak można wykorzystać Apache Kafka. Bardziej przypomina to bazę danych NoSQL.
Potrzebna infrastruktura
Potrzebujemy uruchomić co najmniej dwa serwery (w znaczeniu procesy), aby mieć działającą instancję Kafki.
Zookeeper
Serwer gdzie Kafka trzyma swoją aktualną konfigurację. Listę brokerów, listę topiców, ich rozlokowane między brokerami, informację o uprawnieniach (ACLs). Odpowiada za sprawdzanie dostępności brokerów. W razie wykrycia problemu wysyła komunikat do brokerów.
Gdy np. przestaje działać broker będący masterem dla partycji (leader) jedna z replik slave (replica) przejmuje jego role (więcej o algorytmie wybierania lidera). Zookeper musi być uruchomiony, zanim uruchomimy Kafkę. Konsumenci i producenci nie mają z nim żadnej interakcji. Trzeba tylko pamiętać o tym, żeby był uruchomiony w klastrze.
Zookeeper jest konieczny do prawidłowego działania klastra Kafki, więc warto w środowisku produkcyjnym mieć instancje zapasowe. Z uwagi na działanie replikacji w Zookeeper, rekomendowana jest nieparzysta liczba węzłów. Czyli minimalna sensowna wartość to trzy. Przy dużej liczbie brokerów można zwiększyć ich ilość do 5 lub 7.
Brokerzy
Serwery gdzie wysyła i odbiera się wiadomości. Przy tworzeniu klienta musimy podać w konfiguracji nazwy hostów i ich portów będących brokerami. Nie musimy podawać pełnej listy. Klient Kafki odpyta o nią brokera. Pisząc kod kliencki Kafki, nie odnosimy się do konkretnego brokera, tylko do topiku.
Jeżeli chcemy mieć działającą replikację danych, potrzebujemy kilku brokerów. Sensownie jest zacząć od trzech. Ich liczbę możemy potem w razie potrzeby zwiększyć nawet do kilkuset.
Wysyłanie wiadomości
Wiadomość, czyli odpowiednik rekordu z bazy danych składa się z klucza (opcjonalnego w przypadku nieużywania kompaktowania danych), nagłówków (opcjonalnych, do dowolnego wykorzystania), metadanych, oraz wartości z naszymi danymi.
Metadane zawierają docelowy topic. Jeżeli nie stworzymy klucza, to partycja będzie przydzielona losowo. Jeżeli klucz zostanie stworzony, to partycja będzie obliczona, domyślnie algorytmem round robin lub w jakikolwiek inny sposób, który sami wymyślimy i zaimplementujemy.
Wiadomość ma też timestamp będący czasem wysłania, jeżeli będzie pusty, to zostanie ustawiony przez brokera. W Java wiadomość, jaką wysyłam, reprezentuje klasa ProducerRecord. Wiadomość może mieć wielkość do około 1 MB. Domyślnie wszystkie ustawienia związane z wysyłaniem są zoptymalizowane pod wiadomości do 1K. W jednym topicu możemy teoretycznie przechowywać wiadomości o zupełnie różnym formacie.
W praktyce łatwiej umówić się na jeden schemat. Kafka nie zajmuje się walidacją danych. Danymi może być cokolwiek. Możemy to robić w momencie odbierania lub wysyłania danych w kodzie producenta, lub konsumenta.
Topic
Kluczowy element w Kafce. Zrozumienie jego budowy jest konieczne, aby zrozumieć wszystkie inne koncepty. Jest to odpowiednik kolejki komunikatów z klasycznych brokerów wiadomości. Nadawcy wiadomości wysyłają tam dane, a konsumenci je stamtąd czytają. W Kafce jednak nie działa on jak kolejka, a raczej jak tablica dwuwymiarowa składająca się z partycji i offsetu (indeksu).
Liczba partycji jest ustalana przez nas. Do większości zastosowań wystarczy 10 partycji na początek. Partycje możemy dokładać bez żadnych dodatkowych kosztów. Nie ma limitu partycji, jednak Kafka zacznie w pewnym momencie spowalniać, rzeczywiste maksimum to kilka tysięcy partycji na serwer i kilkaset tysięcy na cały klaster.
Producenci wysyłają wiadomość do konkretnej partycji w topicu. Offset jest przydzielany w brokerze i zawsze jest to kolejny numer. Nie można nadpisać wiadomości. Nie można też jej usunąć z pozycji konsumenta. Pisząc kodm nie musimy jednak sami ustalać partycji, na jaką ma trafić wiadomość. Kod producenta sam wybierze partycję na podstawie klucza wiadomości, a jeśli nie ma klucza, wyśle wiadomość do losowej partycji.
Odczytywanie wiadomości
Dane w topicu nie są usuwane po odczytaniu. Domyślnym zachowaniem jest automatyczne usuwanie wpisów starszych niż tydzień, możemy zmienić tę wartość w konfiguracji brokera lub topicu. Pozwala to konsumentom na wybranie samodzielnie, z jakiego miejsca chcą zacząć czytać. Pozwala to na czytanie tej samej partycji równocześnie, z różnych miejsc.
Nauka Kafki
Wasza ścieżka będzie zależeć od tego, w jakim języku programujecie i czy zdecydujecie się na platformę Kafki od Cloudera lub Confluent. Podstawy będą podobne. Poniżej przydatne linki:
- Na tej stronie można się zapisać na darmowy 1,5-godzinny kurs oraz wykonać test wiedzy. Są tu też płatne certyfikaty dla doświadczonych programistów lub administratorów Kafki.
- Dokumentacja Apache Kafka, która zawiera też wprowadzenie.
- Jeżeli nie chcecie uruchamiać własnej instancji Kafki, możecie stworzyć za darmo 5 topików we współdzielonym klastrze cloudkarafka. Max. 10 MB na topic.
- Przykładowe projektydla różnych zastosowań.
- Cała darmowa książka Kafka: The Definitive Guide (322 strony).
- Lista video i artykułów.
Przykładowe projekty TODO
https://github.com/dsu/kafka-streams-redis-lambda-poc
https://github.com/dsu/kafka-docker-subscription
Kiedy używać Kafki
Jeżeli nie możesz użyć bazy danych czy innego rozwiązania do komunikacji asynchronicznej. Apache Kafka nie nadaje się zbyt dobrze do małych projektów. Na starcie wymaga kilku serwerów, aby odczuć korzyści z jej używania, jednak w dużej organizacji jest to prostsze, niż próba zarządzania jedną wielką bazą danych lub wieloma różnymi.
Może wydawać się to śmieszne, ale po prostu w wielu tabelach w bazach danych wykorzystywanych w dużych korporacjach zaczęło brakować wolnych kluczy i architekci zaczęli szukać sposobów jak zarządzać danymi tak, aby nie były potrzebne skomplikowane migracje i przepisywanie systemów. W Kafce dane są wyspecjalizowane, każdy zapisuje dane do niezależnego topicu. Dane z jednego lub wielu tematów można przetworzyć i przesłać dalej. Jest to też oszczędność miejsca – nie każdy zbiór danych potrzebuje tak samo wysokiego współczynnika replikacji. Nie ma też problemu z zakleszczeniem czy liczbą połączeń do bazy.
Jeżeli potrzebujesz maksymalnej możliwej przepustowości, alternatywy to Apache Spark, Storm, Flink, Redis, RabbitMQ. Żadna z alternatyw jednak nie ma takich samych właściwości jak Kafka i jest stworzona do nieco innych celów.
Chyba największą wadą Kafki jest brak indeksowania. Nawet jeśli nasz projekt nie przewiduje analizy danych, wyszukiwania, łączenia to będzie nam to potrzebne w fazie testowania, debugowania oprogramowania. Nie możemy też odpytać Kafki o konkretne pole w wiadomości, zawsze musimy pobrać całą wiadomość, odkodować dane i dopiero dostajemy to, co potrzebne.
Nie ma też opcji filtracji tego, jakie dane pobierzemy z Kafki, możemy posłużyć się tylko numerem partycji i offsetem. Weryfikacja nowej funkcjonalności w środowisku SIT/ UAT, gdzie możemy już np. chcieć mieć topiki o wielkości kilkudziesięciu GB, oznacza każdą próbę weryfikacji czy dana wiadomość trafiła do danego topicu i może to trwać godziny dla pojedynczego zapytania. Oczywiście utrudnia to pracę.
Nie da się ukryć, że w przypadku podobnego zbioru danych w bazach relacyjnych nie byłoby tego problemu. Mamy przecież takie bazy jak AWS Aurora, która też jest szybka i się skaluje. Mamy też bazy NoSQL DynamoDB, Apache Cassandra , Redis, MongoDB 3.6 change streams, które mają indeksy, własny język zapytań.
Jeżeli używasz już RabbitMQ lub innego klasycznego message brokera to nie ma wielu powodów, aby przechodzić na Kafkę. Kafka ma szeregowanie wiadomości w ramach partycji, ma persystencję wiadomości out of the box, której właściwie możemy nie potrzebować. Kafka nie ma odpowiednika dla Exchanges, priorytetów wiadomości.
Ponadto implementacja metody subscribe konsumenta nie jest asynchroniczna. Używa mechanizmu on-demand pooling do odczytywania danych.
Narzędzia
GIT + Jenkins
Mowa o jakimkolwiek narzędziu CVS i CI. W dużej organizacji ułatwiają zarządzanie schematami. Tworzymy jedno repozytorium ze schematami, gdzie każdy może stworzyć PR z własnym schematem stworzonym na potrzeby projektu. Po zmerge’owaniu zmian Jenkins sam uaktualni schemat w rejestrze schematów.
Dzięki temu wystarczy udostępnić samo repozytorium, aby mieć możliwość podglądu istniejących schematów, dodanie nowego po weryfikacji, bez przyznawania każdemu użytkownikowi możliwości zarządzania schema registry.
kafka-topics
Podstawowym narzędziem jest Kafka topics. Pozwala na proste listowanie danych w topiku, partycji, proste wyszukiwanie.
Program jest na GitHubie, jest też wersja Live.
Lenses
Dużo większe możliwości ma płatny produkt, Lenses. Zawiera kompleksową możliwość monitorowania, tworzenia alertów, zarządzania schematami oraz dość zaawansowaną możliwość generowania zapytań typu SQL. Niestety Kafka nie używa żadnych indeksów, więc przeszukanie całego topiku może trwać wiele godzin.
Prometheus, Grafana
Prometheus pozwala na odbieranie danych statystycznych z różnych systemów. Dla Kafki można użyć Kafka Exportera. Grafana to jedno z najpopularniejszych narzędzi do wizualizacji pozwalające na przetworzeniu i wizualizacji danych z wielu rodzajów źródeł.
Standardowe wartości, które warto obserwować to lag – liczba nieprzetworzonych rekordów w temacie. Jeżeli konsument działa bez przerw, ta wartość powinna być zerowa przez większość czasu.
Liczba wiadomości tematu – w przykładzie poniżej widoczne są topiki, gdzie wysyłane są eventy w przypadku poprawnego przetworzenia, przetworzenia z błędem oraz temat z danymi wejściowymi.
Przechowywanie wiadomości z błędem to schemat znany też z innych tego typu platform – Dead Letter Queues (DLQs). Kafka nie zrobi tego automatycznie, możemy to zaimplementować w dowolny sposób, o ile jest to nam przydatne. Możemy przy przesyłaniu np. dodać dodatkową informację o rodzaju błędu do eventu. Takie dane możemy potem spróbować przetworzyć ponownie. Sprawdzenie liczby wiadomości w topiku jest możliwe natychmiast, łatwo stworzyć alert, który powiadomi nas o wystąpieniu problemu.
Można monitorować ilość danych wykorzystywanej przez topic. Będziemy tu mogli obserwować, jak Kafka radzi sobie z kompaktowaniem danych oraz usuwaniem przeterminowanych wpisów. Wiadomości, które są ukryte w wyniku kompaktowania, nie znikają od razu z dysku. Kafka co jakiś czas uruchamia proces podobny do vacuum w relacyjnych bazach danych, usuwa fizycznie takie dane w paczkach.
Inne wartości, które warto obserwować to lag z podziałem na grupy konsumentów, co pozwoli nam zlokalizować aplikację, która ma problemy z przetwarzaniem wiadomości.
Możemy obserwować przepustowość.
Instana
Instana to kombajn do DevOps. Nie jest darmowy, ma jednak wersję próbną. Nie ma problemu z rozpoznaniem tematów, konsumentów i producentów Kafki.
Oprócz tego, co oferują inne produkty, potrafi efektownie wizualizować praktycznie wszystkie komponenty aplikacji.
Kafka Connect
Jeżeli nie lubimy programować, to możemy wyklikać producentów i konsumentów. Możemy np. stworzyć connector, który wykona zadane przez nas zapytanie SQL i wrzuci dane do Kafki.
Oczywiście wszystko trzeba będzie skonfigurować – driver do bazy danych, parametry połączenia, mapowanie danych z tabeli do wiadomości w Kafce. Możemy wysłać wszystkie dane za jednym razem lub okresowo, z wykorzystaniem offsetów.
Warto zainteresować się tym tylko w przypadku, kiedy nie możemy napisać własnego komponentu. Jest to prostsze, jeżeli mamy już podobną aplikację. Mamy większe możliwości w kwestii wydajności, modyfikacji, monitorowania, debugowania.