RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność

В ostatni artykuł przyjrzeliśmy się klastrowaniu RabbitMQ pod kątem odporności na awarie i wysokiej dostępności. Teraz zagłębmy się w Apache Kafka.

Tutaj jednostką replikacji jest partycja. Każdy temat ma jedną lub więcej sekcji. Każda sekcja ma lidera z naśladowcami lub bez. Tworząc temat, określasz liczbę partycji i współczynnik replikacji. Zwykle wartością jest 3, co oznacza trzy repliki: jednego lidera i dwóch zwolenników.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 1. Cztery sekcje są rozdzielane pomiędzy trzech brokerów

Wszystkie żądania odczytu i zapisu trafiają do lidera. Obserwujący okresowo wysyłają prośby do lidera o otrzymywanie najnowszych wiadomości. Konsumenci nigdy nie zwracają się do naśladowców; ci drudzy istnieją jedynie ze względu na redundancję i tolerancję na błędy.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność

Awaria partycji

Kiedy broker zawodzi, często zawodzą liderzy kilku sekcji. W każdym z nich liderem zostaje naśladowca z innego węzła. W rzeczywistości nie zawsze tak jest, ponieważ czynnik synchronizacji wpływa również na: to, czy istnieją zsynchronizowani obserwatorzy, a jeśli nie, to czy dozwolone jest przejście na niezsynchronizowaną replikę. Ale na razie nie komplikujmy sprawy.

Broker 3 opuszcza sieć, a u brokera 2 wybierany jest nowy lider sekcji 2.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 2. Broker 3 umiera, a jego zwolennik u brokera 2 zostaje wybrany na nowego przywódcę partycji 2

Następnie broker 1 odchodzi, a sekcja 1 również traci swojego lidera, którego rola przechodzi na brokera 2.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 3. Pozostał jeden broker. Wszyscy liderzy korzystają z jednego brokera z zerową redundancją

Kiedy broker 1 wraca do trybu online, dodaje czterech obserwujących, zapewniając pewną redundancję każdej partycji. Jednak wszyscy liderzy nadal pozostali na brokerze 2.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 4. Liderzy pozostają na brokerze 2

Kiedy pojawi się broker 3, wracamy do trzech replik na partycję. Ale wszyscy liderzy nadal korzystają z brokera 2.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 5. Niezrównoważone rozmieszczenie liderów po przywróceniu brokerów 1 i 3

Kafka ma narzędzie do lepszego równoważenia lidera niż RabbitMQ. Tam trzeba było użyć wtyczki lub skryptu innej firmy, który zmienił zasady migracji węzła głównego, zmniejszając redundancję podczas migracji. Dodatkowo w przypadku dużych kolejek musieliśmy zaakceptować niedostępność podczas synchronizacji.

Kafka ma koncepcję „preferowanych replik” roli lidera. Kiedy tworzone są partycje tematyczne, Kafka próbuje równomiernie rozmieścić liderów pomiędzy węzłami i zaznacza tych pierwszych liderów jako preferowanych. Z biegiem czasu, z powodu restartów serwerów, awarii i przerw w łączności, liderzy mogą wylądować na innych węzłach, jak w skrajnym przypadku opisanym powyżej.

Aby rozwiązać ten problem, Kafka oferuje dwie opcje:

  • Opcja auto.leader.rebalance.enable=true pozwala węzłowi sterującemu automatycznie przypisać liderów z powrotem do preferowanych replik i w ten sposób przywrócić równomierną dystrybucję.
  • Administrator może uruchomić skrypt kafka-preferred-replica-election.sh do ręcznego przypisania.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 6. Repliki po rebalansowaniu

To była uproszczona wersja awarii, ale rzeczywistość jest bardziej złożona, chociaż nie ma tu nic specjalnie skomplikowanego. Wszystko sprowadza się do replik zsynchronizowanych (In-Sync Replicas, ISR).

Zsynchronizowane repliki (ISR)

ISR to zestaw replik partycji, który jest uważany za „zsynchronizowany” (zsynchronizowany). Jest przywódca, ale może nie być naśladowców. Obserwatora uważa się za zsynchronizowanego, jeśli przed upływem tego czasu wykonał dokładne kopie wszystkich wiadomości lidera replika.opóźnienia.max.ms.

Obserwator jest usuwany ze zbioru ISR, jeżeli:

  • nie złożył prośby o wybranie interwału replika.opóźnienia.max.ms (uznany za martwego)
  • nie udało się zaktualizować w przerwie replika.opóźnienia.max.ms (uważany za powolny)

Obserwujący wysyłają prośby o pobranie próbek w określonym przedziale czasu replika.pobierz.wait.max.ms, która domyślnie wynosi 500 ms.

Aby jasno wyjaśnić cel ISR, musimy przyjrzeć się potwierdzeniom producenta i niektórym scenariuszom awarii. Producenci mogą wybrać, kiedy broker wyśle ​​potwierdzenie:

  • acks=0, potwierdzenie nie jest wysyłane
  • acks=1, potwierdzenie jest wysyłane po tym, jak lider zapisze wiadomość w swoim lokalnym dzienniku
  • acks=all, potwierdzenie jest wysyłane po zapisaniu wiadomości przez wszystkie repliki w ISR w lokalnych dziennikach

W terminologii Kafki, jeśli ISR ​​zapisał wiadomość, jest ona „zatwierdzona”. Acks=all jest najbezpieczniejszą opcją, ale dodaje również dodatkowe opóźnienie. Przyjrzyjmy się dwóm przykładom niepowodzeń i temu, jak różne opcje „potwierdzeń” współdziałają z koncepcją ISR.

Acks=1 i ISR

Na tym przykładzie zobaczymy, że jeśli lider nie będzie czekał na zapisanie każdej wiadomości od wszystkich obserwujących, wówczas w przypadku niepowodzenia lidera możliwa jest utrata danych. Nawigację do niezsynchronizowanego obserwującego można włączyć lub wyłączyć w ustawieniach nieczysty.przywódca.wybór.włącz.

W tym przykładzie producent ma wartość acks=1. Sekcja jest dystrybuowana wśród wszystkich trzech brokerów. Broker 3 jest opóźniony, zsynchronizował się z liderem osiem sekund temu i obecnie ma 7456 wiadomości opóźnionych. Broker 1 był tylko sekundę do tyłu. Nasz producent wysyła wiadomość i szybko otrzymuje odpowiedź zwrotną, bez narzutu w postaci powolnych lub martwych obserwujących, na które lider nie czeka.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 7. ISR z trzema replikami

Broker 2 ulega awarii i producent otrzymuje błąd połączenia. Po przejściu przywództwa na brokera 1 tracimy 123 wiadomości. Podążający na brokerze 1 był częścią ISR, ale nie był w pełni zsynchronizowany z liderem, gdy upadł.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 8. W przypadku awarii wiadomości zostaną utracone

W konfiguracji serwery startowe Producent ma na liście kilku brokerów i może zapytać innego brokera, który jest nowym liderem sekcji. Następnie ustanawia połączenie z brokerem 1 i kontynuuje wysyłanie wiadomości.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 9. Wysyłanie wiadomości zostaje wznowione po krótkiej przerwie

Broker 3 jest jeszcze bardziej w tyle. Wysyła żądania pobrania, ale nie może przeprowadzić synchronizacji. Może to wynikać z wolnego połączenia sieciowego pomiędzy brokerami, problemów z pamięcią masową itp. Zostało usunięte z ISR. Teraz ISR składa się z jednej repliki - lidera! Producent w dalszym ciągu wysyła wiadomości i otrzymuje potwierdzenia.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 10. Follower na brokerze 3 zostaje usunięty z ISR

Broker 1 przestaje działać, a rola lidera przypada brokerowi 3, co powoduje utratę 15286 wiadomości! Producent otrzymuje komunikat o błędzie połączenia. Przejście na lidera spoza ISR było możliwe jedynie dzięki oprawie unclean.leader.election.enable=true. Jeśli jest zainstalowany w fałszywy, wówczas przejście nie nastąpi, a wszystkie żądania odczytu i zapisu zostaną odrzucone. W tym przypadku czekamy, aż broker 1 wróci z nienaruszonymi danymi w replice, który ponownie przejmie dowodzenie.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 11. Broker 1 upada. W przypadku awarii duża liczba wiadomości zostaje utracona

Producent nawiązuje połączenie z ostatnim brokerem i widzi, że jest teraz liderem sekcji. Zaczyna wysyłać wiadomości do brokera 3.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 12. Po krótkiej przerwie komunikaty wysyłane są ponownie do sekcji 0

Widzieliśmy, że poza krótkimi przerwami na nawiązanie nowych połączeń i poszukiwanie nowego lidera, producent cały czas wysyłał komunikaty. Taka konfiguracja zapewnia dostępność kosztem spójności (bezpieczeństwa danych). Kafka stracił tysiące wiadomości, ale nadal przyjmował nowe zapisy.

Acks=wszystko i ISR

Powtórzmy ten scenariusz jeszcze raz, ale z acks=wszystko. Broker 3 ma średnie opóźnienie wynoszące cztery sekundy. Producent wysyła wiadomość z acks=wszystkoi teraz nie otrzymuje szybkiej odpowiedzi. Lider czeka na zapisanie wiadomości przez wszystkie repliki w ISR.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 13. ISR z trzema replikami. Jeden jest powolny, co powoduje opóźnienia w nagrywaniu

Po czterech sekundach dodatkowego opóźnienia broker 2 wysyła potwierdzenie. Wszystkie repliki są teraz w pełni zaktualizowane.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 14. Wszystkie repliki zapisują wiadomości i wysyłają potwierdzenie

Broker 3 pozostaje teraz w tyle i zostaje usunięty z ISR. Opóźnienie jest znacznie zmniejszone, ponieważ w ISR nie ma już wolnych replik. Broker 2 czeka teraz tylko na brokera 1, a jego średnie opóźnienie wynosi 500 ms.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 15. Replika na brokerze 3 zostaje usunięta z ISR

Następnie broker 2 upada, a przywództwo przechodzi na brokera 1 bez utraty komunikatów.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 16. Broker 2 upada

Producent znajduje nowego lidera i zaczyna do niego wysyłać wiadomości. Opóźnienie jest jeszcze bardziej zmniejszone, ponieważ ISR składa się teraz z jednej repliki! Dlatego opcja acks=wszystko nie dodaje redundancji.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 17. Replika na brokerze 1 przejmuje prowadzenie bez utraty wiadomości

Następnie broker 1 ulega awarii i lead trafia do brokera 3 ze stratą 14238 wiadomości!

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 18. Broker 1 umiera, a zmiana przywództwa z nieczystymi ustawieniami powoduje rozległą utratę danych

Nie mogliśmy zainstalować tej opcji nieczysty.przywódca.wybór.włącz w znaczenie prawdziwy. Domyślnie jest równa fałszywy. Ustawienia acks=wszystko с unclean.leader.election.enable=true zapewnia dostępność i dodatkowe bezpieczeństwo danych. Ale jak widać, nadal możemy stracić wiadomości.

Co jednak, jeśli chcemy zwiększyć bezpieczeństwo danych? Możesz włożyć unclean.leader.election.enable = fałsz, ale niekoniecznie uchroni nas to przed utratą danych. Jeśli lider upadnie i zabierze ze sobą dane, wiadomości nadal będą tracone, a dostępność zostanie utracona do czasu przywrócenia sytuacji przez administratora.

Lepiej upewnić się, że wszystkie wiadomości są zbędne, a w przeciwnym razie odrzucić nagranie. Wtedy, przynajmniej z punktu widzenia brokera, utrata danych możliwa jest tylko w przypadku dwóch lub więcej jednoczesnych awarii.

Acks=all, min.insync.replicas i ISR

Z konfiguracją tematu repliki min.insync Podnosimy poziom bezpieczeństwa danych. Przejdźmy jeszcze raz przez ostatnią część poprzedniego scenariusza, ale tym razem z min.insync.replicas=2.

Zatem broker 2 ma lidera repliki, a obserwator na brokerze 3 jest usuwany z ISR.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 19. ISR z dwóch replik

Broker 2 upada, a przywództwo przechodzi na brokera 1 bez utraty wiadomości. Ale teraz ISR składa się tylko z jednej repliki. Nie spełnia to minimalnej liczby rekordów do odbioru, dlatego broker odpowiada na próbę zapisu z błędem Niewystarczająca liczba replik.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 20. Liczba ISR jest o jeden mniejsza niż określona w min.insync.replicas

Ta konfiguracja poświęca dostępność na rzecz spójności. Przed potwierdzeniem wiadomości upewniamy się, że jest ona zapisana w co najmniej dwóch replikach. Daje to producentowi znacznie większą pewność. W tym przypadku utrata wiadomości jest możliwa tylko wtedy, gdy dwie repliki zawiodą jednocześnie w krótkim odstępie czasu, dopóki wiadomość nie zostanie zreplikowana do dodatkowego obserwatora, co jest mało prawdopodobne. Ale jeśli masz wielką paranoję, możesz ustawić współczynnik replikacji na 5 i repliki min.insync o 3. Tutaj trzech brokerów musi upaść w tym samym momencie, aby stracić rekord! Oczywiście za tę niezawodność płacisz dodatkowym opóźnieniem.

Gdy dostępność jest konieczna dla bezpieczeństwa danych

Jak w sprawa z RabbitMQ, czasami dostępność jest konieczna ze względu na bezpieczeństwo danych. Oto, o czym musisz pomyśleć:

  • Czy wydawca może po prostu zwrócić błąd i poprosić usługę nadrzędną lub użytkownika o ponowną próbę później?
  • Czy wydawca może zapisać wiadomość lokalnie lub w bazie danych, aby spróbować ponownie później?

Jeśli odpowiedź brzmi nie, optymalizacja dostępności poprawia bezpieczeństwo danych. Jeśli wybierzesz dostępność zamiast nie nagrywać, stracisz mniej danych. Wszystko sprowadza się więc do znalezienia równowagi, a decyzja zależy od konkretnej sytuacji.

Znaczenie ISR

Pakiet ISR pozwala wybrać optymalną równowagę pomiędzy bezpieczeństwem danych a opóźnieniami. Na przykład zapewnij dostępność w przypadku awarii większości replik, minimalizując wpływ martwych lub wolnych replik pod względem opóźnień.

Sami wybieramy znaczenie replika.opóźnienia.max.ms zgodnie z Twoimi potrzebami. Zasadniczo ten parametr oznacza, ile opóźnienia jesteśmy skłonni zaakceptować, kiedy acks=wszystko. Wartość domyślna to dziesięć sekund. Jeżeli jest to dla Ciebie za długie, możesz je skrócić. Wtedy częstotliwość zmian w ISR wzrośnie, ponieważ obserwujący będą częściej usuwani i dodawani.

RabbitMQ to po prostu zestaw serwerów lustrzanych, które należy replikować. Powolne serwery lustrzane wprowadzają dodatkowe opóźnienia, a martwe serwery lustrzane mogą poczekać, aż pakiety sprawdzające dostępność każdego węzła (tik sieci) odpowiedzą. ISR to ciekawy sposób na uniknięcie problemów z opóźnieniami. Ryzykujemy jednak utratę zwolnień, ponieważ ISR może jedynie skurczyć się do lidera. Aby uniknąć tego ryzyka, użyj tego ustawienia repliki min.insync.

Gwarancja połączenia klienta

W ustawieniach serwery startowe producent i konsument mogą określić wielu brokerów do łączenia klientów. Pomysł jest taki, że gdy jeden węzeł ulegnie awarii, istnieje kilka zapasowych, z którymi klient może otworzyć połączenie. Niekoniecznie są to liderzy sekcji, ale po prostu odskocznia do wstępnego załadunku. Klient może zapytać, który węzeł obsługuje lidera partycji do odczytu/zapisu.

W RabbitMQ klienci mogą łączyć się z dowolnym węzłem, a routing wewnętrzny wysyła żądanie tam, gdzie ma się udać. Oznacza to, że możesz zainstalować moduł równoważenia obciążenia przed RabbitMQ. Kafka wymaga od klientów połączenia z węzłem, który obsługuje odpowiedniego lidera partycji. W takiej sytuacji nie można zainstalować modułu równoważenia obciążenia. Lista serwery startowe Bardzo ważne jest, aby klienci mogli uzyskać dostęp do właściwych węzłów i znaleźć je po awarii.

Architektura konsensusu Kafki

Do tej pory nie zastanawialiśmy się, w jaki sposób klaster dowiaduje się o upadku brokera i w jaki sposób zostaje wybrany nowy lider. Aby zrozumieć, jak Kafka współpracuje z partycjami sieciowymi, należy najpierw zrozumieć architekturę konsensusu.

Każdy klaster Kafki jest wdrażany wraz z klastrem Zookeeper, który jest rozproszoną usługą konsensusu, która umożliwia systemowi osiągnięcie konsensusu w sprawie określonego stanu, przedkładając spójność nad dostępność. Do zatwierdzenia operacji odczytu i zapisu wymagana jest zgoda większości węzłów Zookeepera.

Zookeeper przechowuje stan klastra:

  • Lista tematów, sekcji, konfiguracji, aktualnych replik liderów, preferowanych replik.
  • Członkowie klastra. Każdy broker wysyła polecenie ping do klastra Zookeeper. Jeśli w określonym czasie nie otrzyma sygnału ping, Zookeeper zarejestruje brokera jako niedostępnego.
  • Wybór węzła głównego i zapasowego dla sterownika.

Węzeł kontrolera to jeden z brokerów Kafki odpowiedzialny za wybór liderów replik. Zookeeper wysyła powiadomienia do kontrolera o członkostwie w klastrze i zmianach tematów, a kontroler musi zareagować na te zmiany.

Weźmy na przykład nowy temat z dziesięcioma partycjami i współczynnikiem replikacji 3. Kontroler musi wybrać lidera dla każdej partycji, starając się optymalnie rozdzielić liderów pomiędzy brokerów.

Dla każdego sterownika sekcji:

  • aktualizuje informacje w Zookeeperze o ISR i liderze;
  • Wysyła polecenie LeaderAndISRCommand do każdego brokera hostującego replikę tej partycji, informując brokerów o ISR i liderze.

Kiedy broker posiadający lidera upadnie, Zookeeper wysyła powiadomienie do kontrolera, a ten wybiera nowego lidera. Ponownie, kontroler najpierw aktualizuje Zookeepera, a następnie wysyła polecenie do każdego brokera, powiadamiając ich o zmianie przywództwa.

Każdy lider jest odpowiedzialny za rekrutację ISR. Ustawienia replika.opóźnienia.max.ms decyduje, kto tam wejdzie. Kiedy ISR się zmienia, lider przekazuje nowe informacje Zookeeperowi.

Zookeeper jest zawsze informowany o wszelkich zmianach, aby w przypadku awarii kierownictwo płynnie przeszło do nowego lidera.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 21. Konsensus Kafki

Protokół replikacji

Zrozumienie szczegółów replikacji pomaga lepiej zrozumieć potencjalne scenariusze utraty danych.

Zapytania dotyczące pobierania próbek, przesunięcie końca kłody (LEO) i znak wysokiego poziomu wody (HW)

Uznaliśmy, że obserwujący okresowo wysyłają żądania pobrania do lidera. Domyślny interwał wynosi 500 ms. Różni się to od RabbitMQ tym, że w RabbitMQ replikacja nie jest inicjowana przez lustro kolejki, ale przez master. Mistrz wciska zmiany w lusterka.

Lider i wszyscy obserwujący zapisują przesunięcie końca kłody (LEO) i etykietę Highwater (HW). Znak LEO przechowuje przesunięcie ostatniej wiadomości w lokalnej replice, a sprzęt przechowuje przesunięcie ostatniego zatwierdzenia. Pamiętaj, że aby uzyskać status zatwierdzenia, komunikat musi być utrwalony we wszystkich replikach ISR. Oznacza to, że LEO zwykle nieznacznie wyprzedza HW.

Kiedy lider otrzymuje wiadomość, przechowuje ją lokalnie. Obserwator składa żądanie pobrania, przesyłając swój LEO. Lider następnie wysyła partię komunikatów, zaczynając od tego LEO, a także przesyła bieżący sprzęt. Gdy lider otrzyma informację, że wszystkie repliki przechowały wiadomość w danym przesunięciu, przesuwa znacznik HW. Tylko lider może przesunąć sprzęt, dzięki czemu wszyscy obserwujący będą znać aktualną wartość w odpowiedziach na ich żądanie. Oznacza to, że naśladowcy mogą pozostawać w tyle za liderem zarówno pod względem przekazu, jak i wiedzy na temat sprzętu. Konsumenci otrzymują wiadomości tylko do aktualnego sprzętu.

Należy pamiętać, że „utrwalony” oznacza zapisany w pamięci, a nie na dysku. Aby zapewnić wydajność, Kafka synchronizuje się z dyskiem w określonych odstępach czasu. RabbitMQ również ma taki odstęp, ale wyśle ​​potwierdzenie do wydawcy dopiero wtedy, gdy master i wszystkie serwery lustrzane zapiszą wiadomość na dysk. Twórcy Kafki, ze względu na wydajność, zdecydowali się wysłać potwierdzenie, gdy tylko wiadomość zostanie zapisana w pamięci. Kafka zakłada, że ​​nadmiarowość równoważy ryzyko krótkotrwałego przechowywania potwierdzonych wiadomości wyłącznie w pamięci.

Porażka lidera

Kiedy lider upadnie, Zookeeper powiadamia kontrolera, który wybiera nową replikę lidera. Nowy lider ustanawia nowy znak HW zgodnie ze swoim LEO. Obserwujący otrzymują wówczas informację o nowym liderze. W zależności od wersji Kafki obserwujący wybierze jeden z dwóch scenariuszy:

  1. Obetnie dziennik lokalny do znanego sprzętu i wyśle ​​żądanie do nowego lidera o wiadomości po tym znaku.
  2. Wyśle prośbę do lidera o sprawdzenie sprzętu w momencie jego wyboru na lidera, a następnie skróci dziennik do tego przesunięcia. Następnie rozpocznie okresowe żądania pobrania, zaczynając od tego przesunięcia.

Obserwator może potrzebować obciąć dziennik z następujących powodów:

  • W przypadku niepowodzenia lidera, pierwszy obserwujący w zestawie ISR zarejestrowany w Zookeeperze wygrywa wybory i zostaje liderem. Wszyscy obserwujący w ISR, choć uważani za „zsynchronizowanych”, mogli nie otrzymać kopii wszystkich wiadomości od byłego przywódcy. Jest całkiem możliwe, że polecany obserwujący nie ma najbardziej aktualnej kopii. Kafka dba o to, aby pomiędzy replikami nie było rozbieżności. Zatem, aby uniknąć rozbieżności, każdy zwolennik musi obciąć swój dziennik do wartości HW nowego lidera w momencie jego wyboru. To kolejny powód, dla którego warto to ustawić acks=wszystko tak ważne dla spójności.
  • Wiadomości są okresowo zapisywane na dysku. Jeżeli wszystkie węzły klastra ulegną awarii w tym samym czasie, na dyskach zostaną zapisane repliki z różnymi offsetami. Możliwe, że kiedy brokerzy wrócą do trybu online, wybrany nowy lider będzie stał za swoimi zwolennikami, ponieważ został zapisany na dysku przed innymi.

Spotkanie z klastrem

Po ponownym dołączeniu do klastra repliki robią to samo, co w przypadku niepowodzenia lidera: sprawdzają replikę lidera i obcinają swój dziennik do jego sprzętu (w momencie wyboru). Dla porównania RabbitMQ w równym stopniu traktuje ponownie połączone węzły jako zupełnie nowe. W obu przypadkach broker odrzuca istniejący stan. Jeśli używana jest automatyczna synchronizacja, mistrz musi całkowicie zreplikować całą bieżącą zawartość do nowego serwera lustrzanego metodą „niech cały świat poczeka”. Podczas tej operacji master nie akceptuje żadnych operacji odczytu ani zapisu. Takie podejście stwarza problemy w dużych kolejkach.

Kafka jest dziennikiem rozproszonym i generalnie przechowuje więcej komunikatów niż kolejka RabbitMQ, w której dane są usuwane z kolejki po ich odczytaniu. Aktywne kolejki powinny pozostać stosunkowo małe. Ale Kafka to dziennik z własną polityką przechowywania, która może ustawić okres dni lub tygodni. Podejście polegające na blokowaniu kolejek i pełnej synchronizacji jest absolutnie nie do przyjęcia w przypadku dziennika rozproszonego. Zamiast tego zwolennicy Kafki po prostu przycinają swój dziennik do HW lidera (w momencie jego wyboru), jeśli ich kopia wyprzedza lidera. W bardziej prawdopodobnym przypadku, gdy obserwujący pozostaje w tyle, po prostu zaczyna wysyłać żądania pobrania, zaczynając od aktualnego LEO.

Nowi lub ponownie dołączeni obserwatorzy zaczynają poza ISR i nie biorą udziału w zatwierdzeniach. Po prostu współpracują z grupą, otrzymując wiadomości tak szybko, jak to możliwe, dopóki nie dogonią lidera i nie wejdą do ISR. Nie ma blokady i nie ma potrzeby wyrzucania wszystkich danych.

Utrata łączności

Kafka ma więcej komponentów niż RabbitMQ, więc ma bardziej złożony zestaw zachowań, gdy klaster zostanie odłączony. Ale Kafka została pierwotnie zaprojektowana dla klastrów, więc rozwiązania są bardzo dobrze przemyślane.

Poniżej znajduje się kilka scenariuszy awarii połączenia:

  • Scenariusz 1: Obserwujący nie widzi lidera, ale nadal widzi Strażnika Zoo.
  • Scenariusz 2: Lider nie widzi żadnych obserwujących, ale nadal widzi Zookeepera.
  • Scenariusz 3: Podążający widzi lidera, ale nie widzi Opiekuna Zoo.
  • Scenariusz 4: Lider widzi zwolenników, ale nie widzi Opiekuna Zoo.
  • Scenariusz 5: Obserwator jest całkowicie oddzielony od innych węzłów Kafki i Zookeepera.
  • Scenariusz 6: Lider jest całkowicie oddzielony od pozostałych węzłów Kafki i Zookeepera.
  • Scenariusz 7: węzeł kontrolera Kafka nie widzi innego węzła Kafka.
  • Scenariusz 8: Kontroler Kafki nie widzi Zookeepera.

Każdy scenariusz ma swoje własne zachowanie.

Scenariusz 1: Obserwujący nie widzi lidera, ale nadal widzi Zookeepera

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 22. Scenariusz 1: ISR trzech replik

Awaria połączenia oddziela brokera 3 od brokerów 1 i 2, ale nie od Zookeepera. Broker 3 nie może już wysyłać żądań pobrania. Po upływie czasu replika.opóźnienia.max.ms jest usuwany z ISR i nie uczestniczy w zatwierdzaniu komunikatów. Po przywróceniu łączności wznowi żądania pobierania i dołączy do ISR, gdy dogoni lidera. Zookeeper będzie nadal odbierał pingi i zakładał, że broker żyje i ma się dobrze.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 23. Scenariusz 1: Broker zostaje usunięty z ISR, jeśli nie otrzyma od niego żądania pobrania w przedziale repliki.lag.time.max.ms

Nie ma zawieszenia typu split-mózg lub węzła, jak w RabbitMQ. Zamiast tego zmniejsza się redundancję.

Scenariusz 2: Lider nie widzi żadnych obserwujących, ale nadal widzi Zookeepera

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 24. Scenariusz 2. Lider i dwóch naśladowców

Awaria połączenia sieciowego oddziela lidera od obserwujących, ale broker nadal może zobaczyć Zookeepera. Podobnie jak w pierwszym scenariuszu, ISR się kurczy, ale tym razem tylko do lidera, ponieważ wszyscy obserwujący przestają wysyłać żądania pobrania. Znowu nie ma logicznego podziału. Zamiast tego następuje utrata redundancji nowych wiadomości do czasu przywrócenia łączności. Zookeeper w dalszym ciągu otrzymuje sygnały „ping” i uważa, że ​​broker żyje i ma się dobrze.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 25. Scenariusz 2. ISR skurczyło się tylko do lidera

Scenariusz 3. Podążający widzi lidera, ale nie widzi Opiekuna Zoo

Obserwujący jest oddzielony od Zookeepera, ale nie od brokera z liderem. W rezultacie obserwujący nadal wysyła żądania pobrania i jest członkiem ISR. Zookeeper nie otrzymuje już pingów i rejestruje awarię brokera, ale ponieważ jest tylko obserwatorem, po odzyskaniu nie ma żadnych konsekwencji.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 26. Scenariusz 3: Obserwator nadal wysyła żądania pobrania do lidera

Scenariusz 4. Lider widzi obserwujących, ale nie widzi Zookeepera

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 27. Scenariusz 4. Lider i dwóch naśladowców

Lider jest oddzielony od Zookeepera, ale nie od brokerów mających zwolenników.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 28. Scenariusz 4: Lider odizolowany od Zookeepera

Po pewnym czasie Zookeeper zarejestruje awarię brokera i powiadomi o tym administratora. Spośród swoich zwolenników wybierze nowego przywódcę. Jednakże pierwotny lider będzie nadal myślał, że jest liderem i będzie nadal akceptował wpisy od niego potwierdzenie = 1. Obserwujący nie wysyłają mu już żądań pobrania, więc uzna ich za martwych i spróbuje zmniejszyć ISR do siebie. Ponieważ jednak nie ma połączenia z Zookeeperem, nie będzie mógł tego zrobić i od tego momentu odmówi przyjęcia dalszych wpisów.

komunikaty acks=wszystko nie otrzymają potwierdzenia, ponieważ ISR najpierw włącza wszystkie repliki, a wiadomości do nich nie docierają. Kiedy pierwotny lider spróbuje usunąć ich z ISR, nie będzie mógł tego zrobić i w ogóle przestanie akceptować jakiekolwiek wiadomości.

Klienci szybko zauważają zmianę lidera i rozpoczynają wysyłanie rekordów na nowy serwer. Po przywróceniu sieci pierwotny lider widzi, że nie jest już liderem, i obcina swój dziennik do wartości sprzętu, którą miał nowy lider w momencie niepowodzenia, aby uniknąć rozbieżności logów. Następnie rozpocznie wysyłanie żądań pobrania do nowego lidera. Wszystkie rekordy pierwotnego lidera, które nie zostaną zreplikowane do nowego lidera, zostaną utracone. Oznacza to, że wiadomości, które nie zostały potwierdzone przez pierwotnego lidera w ciągu tych kilku sekund, gdy pracowało dwóch liderów, zostaną utracone.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 29. Scenariusz 4. Lider na brokerze 1 staje się naśladowcą po przywróceniu sieci

Scenariusz 5: Obserwujący jest całkowicie oddzielony od innych węzłów Kafki i Zookeepera

Obserwator jest całkowicie odizolowany od innych węzłów Kafki i Zookeepera. Po prostu usuwa się z ISR do czasu przywrócenia sieci, a następnie dogania pozostałych.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 30. Scenariusz 5: Izolowany obserwujący zostaje usunięty z ISR

Scenariusz 6: Lider jest całkowicie oddzielony od pozostałych węzłów Kafki i Zookeepera

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 31. Scenariusz 6. Lider i dwóch naśladowców

Lider jest całkowicie odizolowany od swoich zwolenników, kontrolera i Zookeepera. Przez krótki okres będzie nadal przyjmować wpisy od potwierdzenie = 1.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 32. Scenariusz 6: Izolowanie lidera od innych węzłów Kafki i Zookeepera

Nieotrzymanie żądań po wygaśnięciu replika.opóźnienia.max.ms, będzie próbował zmniejszyć ISR do siebie, ale nie będzie w stanie tego zrobić, ponieważ nie ma komunikacji z Zookeeperem, wtedy przestanie akceptować zapisy.

W międzyczasie Zookeeper oznaczy izolowanego brokera jako martwego, a kontroler wybierze nowego lidera.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 33. Scenariusz 6. Dwóch liderów

Pierwotny lider może akceptować wpisy przez kilka sekund, ale potem przestaje akceptować jakiekolwiek wiadomości. Klienci są aktualizowani co 60 sekund o najnowsze metadane. Zostaną poinformowani o zmianie lidera i zaczną wysyłać wpisy do nowego lidera.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 34. Scenariusz 6: Producenci przechodzą na nowego lidera

Wszystkie potwierdzone wpisy dokonane przez pierwotnego lidera od czasu utraty łączności zostaną utracone. Po przywróceniu sieci pierwotny lider odkryje za pośrednictwem Zookeepera, że ​​nie jest już liderem. Następnie w momencie wyboru skróci swój dziennik do sprzętu nowego lidera i zacznie wysyłać żądania jako obserwator.

RabbitMQ vs Kafka: odporność na błędy i wysoka dostępność
Ryż. 35. Scenariusz 6: Pierwotny lider staje się naśladowcą po przywróceniu łączności sieciowej

W tej sytuacji separacja logiczna może nastąpić na krótki okres, ale tylko wtedy, gdy potwierdzenie = 1 и repliki min.insync także 1. Logiczna separacja kończy się automatycznie albo po przywróceniu sieci, kiedy pierwotny lider zorientuje się, że nie jest już liderem, albo kiedy wszyscy klienci zorientują się, że lider się zmienił i zaczną pisać do nowego lidera – w zależności od tego, co nastąpi wcześniej. W każdym razie niektóre wiadomości zostaną utracone, ale tylko z potwierdzenie = 1.

Istnieje inny wariant tego scenariusza, w którym tuż przed podziałem sieci zwolennicy pozostali w tyle, a lider skompresował ISR tylko do siebie. Następnie zostaje odizolowany z powodu utraty łączności. Wybierany jest nowy przywódca, ale nawet pierwotny przywódca nadal przyjmuje zgłoszenia acks=wszystko, bo poza nim w ISR nie ma nikogo innego. Zapisy te zostaną utracone po przywróceniu sieci. Jedynym sposobem na uniknięcie tej opcji jest min.insync.repliki = 2.

Scenariusz 7: Węzeł kontrolera Kafka nie widzi innego węzła Kafka

Ogólnie rzecz biorąc, po utracie połączenia z węzłem Kafki kontroler nie będzie mógł przesłać do niego żadnych informacji o zmianie lidera. W najgorszym przypadku doprowadzi to do krótkoterminowego logicznego rozdzielenia, jak w scenariuszu 6. W większości przypadków broker po prostu nie stanie się kandydatem na przywódcę, jeśli ten zawiedzie.

Scenariusz 8: Kontroler Kafki nie widzi Zookeepera

Zookeeper nie otrzyma sygnału ping od upadłego kontrolera i wybierze nowy węzeł Kafki jako kontroler. Pierwotny kontroler może nadal prezentować się jako taki, ale nie otrzymuje powiadomień od Zookeepera, więc nie będzie miał żadnych zadań do wykonania. Gdy sieć zostanie przywrócona, zda sobie sprawę, że nie jest już kontrolerem, ale stał się zwykłym węzłem Kafki.

Wnioski ze scenariuszy

Widzimy, że utrata łączności obserwatora nie powoduje utraty wiadomości, ale po prostu tymczasowo zmniejsza redundancję do czasu przywrócenia sieci. Może to oczywiście prowadzić do utraty danych w przypadku utraty jednego lub większej liczby węzłów.

Jeśli lider zostanie oddzielony od Zookeepera z powodu utraty łączności, może to spowodować utratę wiadomości potwierdzenie = 1. Brak komunikacji z Zookeeperem powoduje krótki logiczny rozłam między dwoma przywódcami. Problem ten rozwiązuje parametr acks=wszystko.

Parametr repliki min.insync na dwie lub więcej replik zapewnia dodatkową pewność, że takie krótkoterminowe scenariusze nie spowodują utraty wiadomości, jak w scenariuszu 6.

Podsumowanie utraconych wiadomości

Wymieńmy wszystkie sposoby utraty danych w Kafce:

  • Jakakolwiek awaria lidera, jeśli wiadomości zostały potwierdzone przy użyciu potwierdzenie = 1
  • Każde nieczyste przejście przywództwa, to znaczy na naśladowcę spoza ISR, nawet z acks=wszystko
  • Izolowanie lidera od Zookeepera, jeśli wiadomości zostały potwierdzone przy użyciu potwierdzenie = 1
  • Całkowita izolacja lidera, który skurczył już do siebie grupę ISR. Nawet wszystkie wiadomości zostaną utracone acks=wszystko. Jest to prawdą tylko wtedy, gdy min.insync.replicas=1.
  • Jednoczesne awarie wszystkich węzłów partycji. Ponieważ wiadomości są potwierdzane z pamięci, niektóre mogą nie zostać jeszcze zapisane na dysku. Po ponownym uruchomieniu serwerów może brakować niektórych komunikatów.

Nieczystych zmian przywództwa można uniknąć poprzez ich zakazanie lub zapewnienie co najmniej dwóch zwolnień. Najtrwalsza konfiguracja to kombinacja acks=wszystko и repliki min.insync powyżej 1.

Bezpośrednie porównanie niezawodności RabbitMQ i Kafki

Aby zapewnić niezawodność i wysoką dostępność, obie platformy implementują system replikacji pierwotnej i wtórnej. RabbitMQ ma jednak piętę achillesową. Podczas ponownego łączenia po awarii węzły odrzucają swoje dane, a synchronizacja jest blokowana. To podwójne zaskoczenie stawia pod znakiem zapytania trwałość dużych kolejek w RabbitMQ. Będziesz musiał zaakceptować zmniejszoną redundancję lub długie czasy blokowania. Zmniejszenie nadmiarowości zwiększa ryzyko masowej utraty danych. Jeśli jednak kolejki są małe, to w celu zapewnienia redundancji krótkie okresy niedostępności (kilkusekundowe) można rozwiązać, powtarzając próby połączenia.

Kafka nie ma tego problemu. Odrzuca dane tylko z punktu rozbieżności między liderem a naśladowcą. Wszystkie udostępnione dane są zapisywane. Ponadto replikacja nie blokuje systemu. Lider nadal akceptuje posty, podczas gdy nowy obserwujący nadrabia zaległości, więc dla devopsów dołączenie lub ponowne dołączenie do klastra staje się trywialnym zadaniem. Oczywiście podczas replikacji nadal występują problemy, takie jak przepustowość sieci. Jeśli dodasz wielu obserwujących jednocześnie, możesz napotkać ograniczenie przepustowości.

RabbitMQ jest lepszy od Kafki pod względem niezawodności, gdy wiele serwerów w klastrze ulega awarii w tym samym czasie. Jak już powiedzieliśmy, RabbitMQ wysyła potwierdzenie do wydawcy dopiero po zapisaniu wiadomości na dysk przez mastera i wszystkie serwery lustrzane. Ale to dodaje dodatkowe opóźnienie z dwóch powodów:

  • fsync co kilkaset milisekund
  • Awarię serwera lustrzanego można zauważyć dopiero po upływie okresu życia pakietów sprawdzających dostępność każdego węzła (tick sieci). Jeśli lustro zwalnia lub opada, powoduje to dodatkowe opóźnienie.

Kafka zakłada, że ​​jeśli wiadomość jest przechowywana w wielu węzłach, może potwierdzić wiadomości, gdy tylko trafią do pamięci. Z tego powodu istnieje ryzyko utraty wiadomości dowolnego typu (nawet acks=wszystko, min.insync.replicas=2) w przypadku jednoczesnej awarii.

Ogólnie rzecz biorąc, Kafka charakteryzuje się lepszą wydajnością oprogramowania i jest od podstaw zaprojektowana z myślą o klastrach. Jeśli jest to konieczne ze względu na niezawodność, liczbę obserwujących można zwiększyć do 11. Współczynnik replikacji 5 i minimalna liczba synchronizowanych replik min.insync.replicas=3 sprawi, że utrata wiadomości będzie zjawiskiem bardzo rzadkim. Jeśli Twoja infrastruktura obsługuje ten współczynnik replikacji i poziom redundancji, możesz wybrać tę opcję.

Klastrowanie RabbitMQ jest dobre w przypadku małych kolejek. Ale nawet małe kolejki mogą szybko rosnąć, gdy panuje duży ruch. Gdy kolejki staną się duże, będziesz musiał dokonać trudnego wyboru między dostępnością a niezawodnością. Klastrowanie RabbitMQ najlepiej nadaje się do nietypowych sytuacji, w których korzyści płynące z elastyczności RabbitMQ przewyższają wszelkie wady jego klastrowania.

Antidotum na podatność RabbitMQ na duże kolejki jest podzielenie ich na wiele mniejszych kolejek. Jeśli nie potrzebujesz pełnego uporządkowania całej kolejki, a jedynie odpowiednie wiadomości (np. wiadomości od konkretnego klienta) lub w ogóle niczego nie zamawiasz, to ta opcja jest do przyjęcia: spójrz na mój projekt Rebalanser podzielić kolejkę (projekt jest jeszcze na wczesnym etapie).

Na koniec nie zapomnij o szeregu błędów w mechanizmach klastrowania i replikacji zarówno RabbitMQ, jak i Kafki. Z biegiem czasu systemy stały się bardziej dojrzałe i stabilne, ale żadna wiadomość nigdy nie będzie w 100% zabezpieczona przed utratą! Ponadto w centrach danych zdarzają się wypadki na dużą skalę!

Jeśli coś przeoczyłem, popełniłem błąd lub nie zgadzasz się z którymś punktem, śmiało napisz komentarz lub skontaktuj się ze mną.

Często spotykam się z pytaniami: „Co wybrać, Kafkę czy RabbitMQ?”, „Która platforma jest lepsza?”. Prawda jest taka, że ​​to naprawdę zależy od Twojej sytuacji, aktualnego doświadczenia itp. Waham się z wyrażeniem swojej opinii, ponieważ zalecanie jednej platformy dla wszystkich przypadków użycia i możliwych ograniczeń byłoby zbyt dużym uproszczeniem. Napisałem tę serię artykułów, abyś mógł wyrobić sobie własną opinię.

Chcę powiedzieć, że oba systemy są liderami w tej dziedzinie. Mogę być trochę stronniczy, ponieważ z mojego doświadczenia z projektami zazwyczaj cenię takie rzeczy, jak gwarantowana kolejność komunikatów i niezawodność.

Widzę inne technologie, którym brakuje tej niezawodności i gwarantowanej kolejności, potem patrzę na RabbitMQ i Kafkę i zdaję sobie sprawę z niesamowitej wartości obu tych systemów.

Źródło: www.habr.com

Dodaj komentarz