RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach

Tolerancja błędów i wysoka dostępność to duże tematy, dlatego RabbitMQ i Kafce poświęcimy osobne artykuły. Ten artykuł dotyczy RabbitMQ, a następny dotyczy Kafki w porównaniu z RabbitMQ. To długi artykuł, więc usiądź wygodnie.

Przyjrzyjmy się strategiom odporności na awarie, spójności i wysokiej dostępności (HA) oraz kompromisom wynikającym z każdej strategii. RabbitMQ może działać na klastrze węzłów – i wtedy jest klasyfikowany jako system rozproszony. W przypadku systemów rozproszonych często mówimy o spójności i dostępności.

Pojęcia te opisują zachowanie systemu w przypadku awarii. Awaria połączenia sieciowego, awaria serwera, awaria dysku twardego, tymczasowa niedostępność serwera z powodu usuwania elementów bezużytecznych, utraty pakietów lub spowolnienia połączenia sieciowego. Wszystko to może prowadzić do utraty danych lub konfliktów. Okazuje się, że praktycznie niemożliwe jest zbudowanie systemu, który byłby zarówno w pełni spójny (bez utraty danych, bez rozbieżności danych), jak i dostępny (akceptujący odczyt i zapis) dla wszystkich scenariuszy awarii.

Zobaczymy, że spójność i dostępność znajdują się na przeciwległych krańcach spektrum i trzeba wybrać sposób optymalizacji. Dobra wiadomość jest taka, że ​​dzięki RabbitMQ taki wybór jest możliwy. Masz tego rodzaju „nerdowskie” dźwignie, które pozwalają przesunąć równowagę w stronę większej spójności lub większej dostępności.

Szczególną uwagę zwrócimy na to, które konfiguracje prowadzą do utraty danych w wyniku potwierdzonych zapisów. Istnieje łańcuch odpowiedzialności pomiędzy wydawcami, brokerami i konsumentami. Gdy wiadomość zostanie przesłana do brokera, jego zadaniem jest nie zgubić wiadomości. Gdy broker potwierdzi wydawcy otrzymanie wiadomości, nie spodziewamy się, że zostanie ona utracona. Ale zobaczymy, że może się to faktycznie zdarzyć w zależności od konfiguracji brokera i wydawcy.

Elementy podstawowe odporności pojedynczego węzła

Odporne kolejkowanie/routowanie

W RabbitMQ istnieją dwa rodzaje kolejek: trwałe i nietrwałe. Wszystkie kolejki zapisywane są w bazie Mnesia. Trwałe kolejki są ponownie ogłaszane przy uruchamianiu węzła, dzięki czemu przetrwają ponowne uruchomienie, awarię systemu lub awarię serwera (o ile dane zostaną utrwalone). Oznacza to, że jeśli zadeklarujesz, że routing (wymiana) i kolejka są odporne, infrastruktura kolejkowania/routingu wróci do trybu online.

Lotne kolejki i routing są usuwane po ponownym uruchomieniu węzła.

Stałe komunikaty

To, że kolejka jest trwała, nie oznacza, że ​​wszystkie jej komunikaty przetrwają restart węzła. Tylko wiadomości ustawione przez wydawcę jako zrównoważony (uporczywy). Trwałe wiadomości powodują dodatkowe obciążenie brokera, ale jeśli utrata wiadomości jest niedopuszczalna, nie ma innej opcji.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 1. Matryca zrównoważonego rozwoju

Klastrowanie z dublowaniem kolejki

Aby przetrwać stratę brokera, potrzebujemy redundancji. Możemy połączyć wiele węzłów RabbitMQ w klaster, a następnie dodać dodatkową redundancję poprzez replikację kolejek pomiędzy wieloma węzłami. Dzięki temu w przypadku awarii jednego węzła nie stracimy danych i pozostaniemy dostępni.

Dublowanie kolejki:

  • jedna główna kolejka (master), która odbiera wszystkie polecenia zapisu i odczytu
  • jeden lub więcej serwerów lustrzanych odbierających wszystkie komunikaty i metadane z kolejki głównej. Lustra te nie służą do skalowania, ale wyłącznie do redundancji.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 2. Dublowanie kolejki

Dublowanie jest ustawiane przez odpowiednią politykę. Można w nim wybrać współczynnik replikacji, a nawet węzły, na których ma znajdować się kolejka. Przykłady:

  • ha-mode: all
  • ha-mode: exactly, ha-params: 2 (jeden mistrz i jedno lustro)
  • ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2

Potwierdzenie wydawcy

Aby zapewnić spójne nagrywanie, wymagane jest potwierdzenie wydawcy. Bez nich istnieje ryzyko utraty wiadomości. Po zapisaniu wiadomości na dysk do wydawcy wysyłane jest potwierdzenie. RabbitMQ zapisuje wiadomości na dysk nie po otrzymaniu, ale okresowo, w ciągu kilkuset milisekund. Kiedy kolejka jest dublowana, potwierdzenie jest wysyłane dopiero wtedy, gdy wszystkie serwery lustrzane również zapisały swoje kopie wiadomości na dysku. Oznacza to, że korzystanie z potwierdzeń zwiększa opóźnienia, ale jeśli bezpieczeństwo danych jest ważne, są one konieczne.

Kolejka awaryjna

Kiedy broker kończy pracę lub ulega awarii, wszyscy liderzy kolejki (master) w tym węźle ulegają awarii wraz z nim. Następnie klaster wybiera najstarsze lustro każdego wzorca i promuje je jako nowego wzorca.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 3. Wiele kolejek lustrzanych i ich zasady

Broker 3 przestaje działać. Należy pamiętać, że lustro kolejki C na Brokerze 2 jest promowane do poziomu master. Należy również pamiętać, że dla kolejki C na Brokerze 1 utworzono nowe lustro. RabbitMQ zawsze stara się utrzymać współczynnik replikacji określony w Twoich zasadach.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 4. Awaria brokera 3 powoduje awarię kolejki C

Następny Broker 1 upada! Został nam tylko jeden broker. Lustro kolejki B zostaje awansowane na master.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Rys.. 5

Zwróciliśmy Brokera 1. Niezależnie od tego, jak dobrze dane przetrwają utratę i odzyskanie brokera, wszystkie komunikaty z kolejki lustrzanej zostaną odrzucone po ponownym uruchomieniu. Warto o tym pamiętać, ponieważ będą konsekwencje. Wkrótce przyjrzymy się tym konsekwencjom. Zatem Broker 1 jest teraz ponownie członkiem klastra, a klaster próbuje zastosować się do zasad i dlatego tworzy kopie lustrzane w Brokerze 1.

W tym przypadku utrata Brokera 1 była całkowita, podobnie jak dane, więc nieodzwierciedlona Kolejka B została całkowicie utracona.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 6. Broker 1 wraca do serwisu

Broker 3 powrócił do trybu online, więc kolejki A i B odzyskują utworzone na nim serwery lustrzane, aby spełnić swoje zasady HA. Ale teraz wszystkie główne kolejki znajdują się w jednym węźle! Nie jest to idealne rozwiązanie, lepsza jest równomierna dystrybucja między węzłami. Niestety, nie ma tu zbyt wielu możliwości przywrócenia równowagi mistrzom. Wrócimy do tego problemu później, ponieważ najpierw musimy przyjrzeć się synchronizacji kolejek.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 7. Broker 3 wraca do serwisu. Wszystkie główne kolejki w jednym węźle!

Teraz powinieneś mieć pojęcie o tym, w jaki sposób lustra zapewniają redundancję i odporność na błędy. Zapewnia to dostępność w przypadku awarii pojedynczego węzła i zabezpiecza przed utratą danych. Ale to jeszcze nie koniec, bo w rzeczywistości jest to dużo bardziej skomplikowane.

Synchronizacja

Podczas tworzenia nowego serwera lustrzanego wszystkie nowe wiadomości będą zawsze replikowane do tego serwera lustrzanego i wszystkich innych. Jeśli chodzi o istniejące dane w kolejce wzorcowej, możemy je zreplikować na nowe lustro, które stanie się pełną kopią wzorca. Możemy również zrezygnować z replikowania istniejących wiadomości i pozwolić, aby główna kolejka i nowy serwer lustrzany zbiegły się w czasie, tak aby nowe wiadomości docierały na koniec, a istniejące wiadomości opuszczały początek głównej kolejki.

Ta synchronizacja jest wykonywana automatycznie lub ręcznie i jest zarządzana przy użyciu zasad kolejek. Spójrzmy na przykład.

Mamy dwie lustrzane kolejki. Kolejka A jest synchronizowana automatycznie, a kolejka B jest synchronizowana ręcznie. Obie kolejki zawierają dziesięć komunikatów.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 8. Dwie kolejki z różnymi trybami synchronizacji

Teraz tracimy Brokera 3.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 9. Broker 3 upadł

Broker 3 wraca do serwisu. Klaster tworzy kopię lustrzaną dla każdej kolejki w nowym węźle i automatycznie synchronizuje nową kolejkę A z kolejką główną. Jednakże lustro nowej kolejki B pozostaje puste. W ten sposób mamy pełną redundancję w kolejce A i tylko jedno lustro dla istniejących komunikatów kolejki B.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 10. Nowe lustro kolejki A odbiera wszystkie istniejące komunikaty, ale nowe lustro kolejki B nie.

W obu kolejkach pojawia się dziesięć kolejnych wiadomości. Następnie Broker 2 ulega awarii, a Kolejka A powraca do najstarszego serwera lustrzanego, który znajduje się w Brokerze 1. W przypadku awarii nie następuje utrata danych. W kolejce B znajduje się dwadzieścia wiadomości w stacji głównej i tylko dziesięć w kopii lustrzanej, ponieważ w tej kolejce nigdy nie było repliki oryginalnych dziesięciu wiadomości.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 11. Kolejka A wraca do Brokera 1 bez utraty wiadomości

W obu kolejkach pojawia się dziesięć kolejnych wiadomości. Teraz ulega awarii Broker 1. Kolejka A łatwo przełącza się na serwer lustrzany bez utraty wiadomości. Jednakże kolejka B ma problemy. W tym momencie możemy zoptymalizować dostępność lub spójność.

Jeśli chcemy zoptymalizować dostępność, to polityka ha-promote-w przypadku niepowodzenia należy zainstalować w zawsze. Jest to wartość domyślna, zatem nie można w ogóle określać polityki. W tym przypadku zasadniczo dopuszczamy awarie niezsynchronizowanych serwerów lustrzanych. Spowoduje to utratę wiadomości, ale kolejka pozostanie możliwa do odczytu i zapisu.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 12. Kolejka A jest przywracana do Brokera 3 bez utraty wiadomości. Kolejka B wraca do Brokera 3 z utraconymi dziesięcioma komunikatami

Możemy również zainstalować ha-promote-on-failure w znaczenie when-synced. W takim przypadku zamiast wracać do lustra, kolejka będzie czekać, aż Broker 1 ze swoimi danymi powróci do trybu online. Po powrocie kolejka główna wraca do Brokera 1 bez utraty danych. Dostępność została poświęcona na rzecz bezpieczeństwa danych. Jest to jednak tryb ryzykowny, który może nawet doprowadzić do całkowitej utraty danych, czemu przyjrzymy się wkrótce.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 13. Kolejka B pozostaje niedostępna po utracie Brokera 1

Możesz zapytać: „Czy lepiej nigdy nie używać automatycznej synchronizacji?” Odpowiedź jest taka, że ​​synchronizacja jest operacją blokującą. Podczas synchronizacji kolejka główna nie może wykonywać żadnych operacji odczytu ani zapisu!

Spójrzmy na przykład. Teraz mamy bardzo długie kolejki. Jak one mogą urosnąć do takich rozmiarów? Z kilku powodów:

  • Kolejki nie są aktywnie wykorzystywane
  • Są to kolejki o dużej prędkości, a obecnie konsumenci są powolni
  • Są kolejki dużych prędkości, wystąpiła usterka, a konsumenci nadrabiają zaległości

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 14. Dwie duże kolejki z różnymi trybami synchronizacji

Teraz Broker 3 upada.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 15. Broker 3 upada, pozostawiając w każdej kolejce jednego mistrza i lustro

Broker 3 wraca do trybu online i tworzone są nowe serwery lustrzane. Kolejka główna A rozpoczyna replikację istniejących wiadomości do nowego serwera lustrzanego i w tym czasie kolejka jest niedostępna. Replikacja danych zajmuje dwie godziny, co skutkuje dwiema godzinami przestoju w tej kolejce!

Kolejka B pozostaje jednak dostępna przez cały okres. Poświęciła pewną redundancję na rzecz dostępności.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 16. Kolejka pozostaje niedostępna podczas synchronizacji

Po dwóch godzinach kolejka A również staje się dostępna i może ponownie rozpocząć akceptowanie odczytu i zapisu.

Aktualizacje

To blokujące zachowanie podczas synchronizacji utrudnia aktualizację klastrów z bardzo dużymi kolejkami. W pewnym momencie węzeł główny musi zostać zrestartowany, co oznacza albo przełączenie na serwer lustrzany, albo wyłączenie kolejki na czas aktualizacji serwera. Jeśli zdecydujemy się na przejście, utracimy wiadomości, jeśli serwery lustrzane nie zostaną zsynchronizowane. Domyślnie podczas awarii brokera nie jest wykonywane przełączanie awaryjne do niezsynchronizowanego serwera lustrzanego. Oznacza to, że gdy tylko broker powróci, nie tracimy żadnych wiadomości, jedyną szkodą była zwykła kolejka. Zasady zachowania w przypadku rozłączenia brokera są określone przez politykę ha-promote-on-shutdown. Możesz ustawić jedną z dwóch wartości:

  • always= przejście do niezsynchronizowanych serwerów lustrzanych jest włączone
  • when-synced= przejście tylko do zsynchronizowanego serwera lustrzanego, w przeciwnym razie kolejka stanie się nieczytelna i niemożliwa do zapisu. Kolejka wraca do usługi zaraz po powrocie brokera

Tak czy inaczej, przy dużych kolejkach trzeba wybierać pomiędzy utratą danych a ich niedostępnością.

Kiedy dostępność poprawia bezpieczeństwo danych

Przed podjęciem decyzji należy wziąć pod uwagę jeszcze jedną komplikację. Chociaż automatyczna synchronizacja jest lepsza pod względem nadmiarowości, jaki ma ona wpływ na bezpieczeństwo danych? Oczywiście, przy lepszej redundancji, RabbitMQ jest mniej narażony na utratę istniejących wiadomości, ale co z nowymi wiadomościami od wydawców?

Tutaj należy wziąć pod uwagę następujące kwestie:

  • 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 wydawca może jedynie odrzucić wiadomość, to tak naprawdę poprawa dostępności poprawia również bezpieczeństwo danych.

Należy zatem szukać równowagi, a rozwiązanie zależy od konkretnej sytuacji.

Problemy z ha-promote-on-failure=when-synced

Pomysł ha-promote-w przypadku niepowodzenia= po synchronizacji polega na tym, że zapobiegamy przejściu na niezsynchronizowany serwer lustrzany, a tym samym unikamy utraty danych. Kolejka pozostaje nieczytelna lub zapisywalna. Zamiast tego staramy się odzyskać uszkodzonego brokera z nienaruszonymi danymi, aby mógł wznowić działanie jako master bez utraty danych.

Ale (i to jest duże ale) jeśli broker utracił swoje dane, to mamy duży problem: kolejka przepadła! Wszystkie dane zniknęły! Nawet jeśli masz lustra, które w większości doganiają główną kolejkę, te lustra również są odrzucane.

Aby ponownie dodać węzeł o tej samej nazwie, mówimy klastrowi, aby zapomniał o utraconym węźle (za pomocą polecenia królikmqctl zapomnij_cluster_node) i uruchom nowego brokera o tej samej nazwie hosta. Podczas gdy klaster pamięta utracony węzeł, pamięta starą kolejkę i niezsynchronizowane serwery lustrzane. Kiedy klaster ma zapomnieć o osieroconym węźle, ta kolejka również zostaje zapomniana. Teraz musimy to ponownie ogłosić. Straciliśmy wszystkie dane, chociaż mieliśmy lustrzane kopie z częściowym zestawem danych. Lepiej byłoby przejść na niezsynchronizowane lustro!

Dlatego ręczna synchronizacja (i brak synchronizacji) w połączeniu z ha-promote-on-failure=when-syncedmoim zdaniem dość ryzykowne. Lekarze twierdzą, że istnieje taka opcja ze względu na bezpieczeństwo danych, ale jest to nóż obosieczny.

Mistrzowskie przywracanie równowagi

Zgodnie z obietnicą wracamy do problemu akumulacji wszystkich masterów w jednym lub kilku węzłach. Może się to zdarzyć nawet w wyniku stopniowej aktualizacji klastra. W klastrze składającym się z trzech węzłów wszystkie kolejki główne będą gromadzone w jednym lub dwóch węzłach.

Rebalancing masterów może być problematyczny z dwóch powodów:

  • Nie ma dobrych narzędzi do przeprowadzenia przywracania równowagi
  • Synchronizacja kolejki

Istnieje trzecia strona zajmująca się przywracaniem równowagi podłącz, który nie jest oficjalnie obsługiwany. Odnośnie wtyczek innych firm w instrukcji RabbitMQ powiedział: „Wtyczka zapewnia dodatkowe narzędzia do konfiguracji i raportowania, ale nie jest obsługiwana ani weryfikowana przez zespół RabbitMQ. Używasz na własne ryzyko.”

Istnieje jeszcze jedna sztuczka polegająca na przenoszeniu głównej kolejki przez zasady HA. W instrukcji jest mowa scenariusz dla tego. Działa to w ten sposób:

  • Usuwa wszystkie kopie lustrzane korzystające z tymczasowej polityki o wyższym priorytecie niż istniejąca polityka HA.
  • Zmienia tymczasową politykę HA tak, aby korzystała z trybu węzła, określając węzeł, do którego powinna zostać przeniesiona kolejka główna.
  • Synchronizuje kolejkę migracji wypychanej.
  • Po zakończeniu migracji usuwa zasadę tymczasową. Początkowa polityka HA zaczyna obowiązywać i tworzona jest wymagana liczba kopii lustrzanych.

Wadą jest to, że to podejście może nie działać, jeśli masz duże kolejki lub surowe wymagania dotyczące nadmiarowości.

Zobaczmy teraz, jak klastry RabbitMQ współpracują z partycjami sieciowymi.

Utrata łączności

Węzły systemu rozproszonego są połączone łączami sieciowymi, a łącza sieciowe mogą i będą rozłączane. Częstotliwość awarii zależy od lokalnej infrastruktury lub niezawodności wybranej chmury. W każdym razie systemy rozproszone muszą sobie z nimi poradzić. Po raz kolejny mamy wybór pomiędzy dostępnością a spójnością i ponownie dobrą wiadomością jest to, że RabbitMQ zapewnia obie opcje (tylko nie w tym samym czasie).

W RabbitMQ mamy dwie główne opcje:

  • Zezwalaj na podział logiczny (rozszczepiony mózg). Zapewnia to dostępność, ale może spowodować utratę danych.
  • Wyłącz separację logiczną. Może spowodować krótkoterminową utratę dostępności w zależności od sposobu, w jaki klienci łączą się z klastrem. Może również prowadzić do całkowitej niedostępności w klastrze z dwoma węzłami.

Ale czym jest logiczna separacja? Dzieje się tak, gdy klaster dzieli się na dwie części z powodu utraty połączeń sieciowych. Z każdej strony lustra awansują na mistrza, tak że ostatecznie w każdej turze jest kilku mistrzów.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 17. Kolejka główna i dwa serwery lustrzane, każdy w osobnym węźle. Następnie następuje awaria sieci i jedno lustro zostaje odłączone. Oddzielony węzeł widzi, że pozostałe dwa odpadły i przekazuje swoje zwierciadła do mistrza. Mamy teraz dwie główne kolejki, zarówno zapisywalne, jak i odczytywalne.

Jeśli wydawcy wyślą dane do obu wzorców, otrzymamy dwie rozbieżne kopie kolejki.

Różne tryby RabbitMQ zapewniają dostępność lub spójność.

Tryb ignorowania (domyślny)

Ten tryb zapewnia dostępność. Po utracie łączności następuje logiczna separacja. Po przywróceniu łączności administrator musi zdecydować, której partycji nadać priorytet. Strona przegrywająca zostanie uruchomiona ponownie, a wszystkie dane zgromadzone po tej stronie zostaną utracone.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 18. Trzej wydawcy są powiązani z trzema brokerami. Wewnętrznie klaster kieruje wszystkie żądania do głównej kolejki w Brokerze 2.

Teraz tracimy Brokera 3. Widzi, że inni brokerzy odpadli i promuje swoje lustro przed mistrzem. W ten sposób następuje logiczna separacja.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 19. Podział logiczny (rozszczepiony mózg). Akta trafiają do dwóch głównych kolejek, a obie kopie się rozchodzą.

Łączność zostaje przywrócona, ale logiczna separacja pozostaje. Administrator musi ręcznie wybrać stronę przegrywającą. W poniższym przypadku administrator restartuje Brokera 3. Wszystkie wiadomości, których nie udało mu się przesłać, zostają utracone.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 20. Administrator wyłącza Brokera 3.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 21. Administrator uruchamia Brokera 3, który przyłącza się do klastra, tracąc wszystkie pozostawione tam wiadomości.

W czasie utraty łączności i po jej przywróceniu klaster i ta kolejka były dostępne do odczytu i zapisu.

Tryb automatycznego leczenia

Działa podobnie do trybu Ignoruj, z tą różnicą, że sam klaster automatycznie wybiera stronę przegrywającą po podzieleniu i przywróceniu łączności. Strona przegrywająca wraca do klastra pusta, a kolejka traci wszystkie wiadomości, które zostały wysłane tylko do tej strony.

Wstrzymaj tryb mniejszości

Jeśli nie chcemy zezwalać na partycjonowanie logiczne, jedyną opcją jest odrzucenie odczytów i zapisów po mniejszej stronie za partycją klastra. Kiedy broker widzi, że jest po mniejszej stronie, zawiesza pracę, czyli zamyka wszystkie istniejące połączenia i odrzuca nowe. Raz na sekundę sprawdza przywrócenie łączności. Po przywróceniu łączności wznawia działanie i dołącza do klastra.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 22. Trzej wydawcy są powiązani z trzema brokerami. Wewnętrznie klaster kieruje wszystkie żądania do głównej kolejki w Brokerze 2.

Brokerzy 1 i 2 następnie odłączyli się od Brokera 3. Zamiast awansować swoje lustro do poziomu głównego, Broker 3 zawiesza się i staje się niedostępny.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 23. Broker 3 wstrzymuje, rozłącza wszystkich klientów i odrzuca żądania połączenia.

Po przywróceniu łączności następuje powrót do klastra.

Spójrzmy na inny przykład, w którym główna kolejka znajduje się na Brokerze 3.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 24. Kolejka główna na Brokerze 3.

Następnie następuje ta sama utrata łączności. Broker 3 zatrzymuje się, ponieważ jest po mniejszej stronie. Z drugiej strony węzły widzą, że Broker 3 odpadł, więc starsze lustro z Brokerów 1 i 2 zostaje awansowane na master.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 25. Przejście do Brokera 2 w przypadku braku Brokera 3.

Po przywróceniu łączności Broker 3 dołączy do klastra.

RabbitMQ vs Kafka: tolerancja błędów i wysoka dostępność w klastrach
Ryż. 26. Klaster powrócił do normalnej pracy.

Ważne jest, aby zrozumieć, że uzyskujemy spójność, ale możemy również uzyskać dostępność, jeśli Z powodzeniem przeniesiemy klientów do większości sekcji. W większości sytuacji osobiście wybrałbym tryb Pause Minority, ale to naprawdę zależy od indywidualnego przypadku.

Aby zapewnić dostępność, ważne jest, aby klienci pomyślnie łączyli się z hostem. Spójrzmy na nasze opcje.

Zapewnienie łączności klientom

Mamy kilka możliwości kierowania klientów do głównej części klastra lub do pracujących węzłów (po awarii jednego węzła) po utracie łączności. Po pierwsze, pamiętajmy, że konkretna kolejka jest hostowana w konkretnym węźle, ale routing i zasady są replikowane we wszystkich węzłach. Klienci mogą łączyć się z dowolnym węzłem, a routing wewnętrzny pokieruje ich tam, gdzie chcą się udać. Jednak gdy węzeł jest zawieszony, odrzuca połączenia, więc klienci muszą połączyć się z innym węzłem. Jeśli węzeł odpadnie, niewiele będzie mógł zrobić.

Nasze opcje:

  • Dostęp do klastra uzyskuje się za pomocą modułu równoważenia obciążenia, który po prostu przełącza węzły, a klienci ponawiają próby połączenia, aż do skutku. Jeśli węzeł jest wyłączony lub zawieszony, próby połączenia się z tym węzłem nie powiodą się, ale kolejne próby będą kierowane na inne serwery (w sposób okrężny). Jest to odpowiednie w przypadku krótkotrwałej utraty łączności lub awarii serwera, który można szybko przywrócić.
  • Uzyskaj dostęp do klastra za pomocą modułu równoważenia obciążenia i usuń zawieszone/uszkodzone węzły z listy, gdy tylko zostaną wykryte. Jeśli zrobimy to szybko i jeśli klienci będą mogli ponowić próbę połączenia, to osiągniemy stałą dostępność.
  • Daj każdemu klientowi listę wszystkich węzłów, a klient losowo wybierze jeden z nich podczas łączenia. Jeśli podczas próby połączenia otrzyma błąd, przechodzi do następnego węzła na liście, aż do uzyskania połączenia.
  • Usuń ruch z uszkodzonego/zawieszonego węzła za pomocą DNS. Odbywa się to za pomocą małego TTL.

odkrycia

Klastrowanie RabbitMQ ma swoje zalety i wady. Najpoważniejsze wady to to, że:

  • dołączając do klastra, węzły odrzucają swoje dane;
  • zablokowanie synchronizacji powoduje, że kolejka staje się niedostępna.

Wszystkie trudne decyzje wynikają z tych dwóch cech architektonicznych. Jeśli RabbitMQ mógłby zapisać dane po ponownym przyłączeniu klastra, synchronizacja byłaby szybsza. Gdyby miał możliwość synchronizacji nieblokującej, lepiej obsługiwałby duże kolejki. Naprawienie tych dwóch problemów znacznie poprawiłoby wydajność RabbitMQ jako odpornej na błędy i wysoce dostępnej technologii przesyłania wiadomości. Wahałbym się, czy polecić RabbitMQ z klastrowaniem w następujących sytuacjach:

  • Niezawodna sieć.
  • Niepewne przechowywanie.
  • Bardzo długie kolejki.

Jeśli chodzi o ustawienia wysokiej dostępności, należy wziąć pod uwagę następujące kwestie:

  • ha-promote-on-failure=always
  • ha-sync-mode=manual
  • cluster_partition_handling=ignore (or autoheal)
  • trwałe komunikaty
  • upewnij się, że klienci łączą się z aktywnym węzłem, gdy któryś z węzłów ulegnie awarii

Aby zachować spójność (bezpieczeństwo danych), rozważ następujące ustawienia:

  • Wydawca potwierdza i potwierdza ręcznie po stronie konsumenta
  • ha-promote-on-failure=when-synced, jeśli wydawcy będą mogli spróbować ponownie później i jeśli masz bardzo niezawodne miejsce na dane! Inaczej postaw =always.
  • ha-sync-mode=automatic (ale w przypadku dużych nieaktywnych kolejek może być wymagany tryb ręczny; rozważ także, czy niedostępność spowoduje utratę wiadomości)
  • Wstrzymaj tryb mniejszości
  • trwałe komunikaty

Nie omówiliśmy jeszcze wszystkich zagadnień związanych z odpornością na awarie i wysoką dostępnością; na przykład, jak bezpiecznie wykonywać procedury administracyjne (takie jak aktualizacje kroczące). Musimy także porozmawiać o federacji i wtyczce Shovel.

Jeśli pominąłem coś jeszcze, proszę dać mi znać.

Zobacz także moje pisać, gdzie dokonuję spustoszenia w klastrze RabbitMQ przy użyciu Dockera i Blockade, aby przetestować niektóre scenariusze utraty wiadomości opisane w tym artykule.

Poprzednie artykuły z serii:
Nr 1 - habr.com/ru/company/itsumma/blog/416629
Nr 2 - habr.com/ru/company/itsumma/blog/418389
Nr 3 - habr.com/ru/company/itsumma/blog/437446

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

Dodaj komentarz