O przechodzeniu z Redis do klastra Redis

O przechodzeniu z Redis do klastra Redis

Jeśli chodzi o produkt, który rozwija się od ponad dekady, wcale nie jest zaskakujące znalezienie w nim przestarzałych technologii. Ale co jeśli w ciągu sześciu miesięcy będziesz musiał utrzymać obciążenie 10 razy większe, a koszt upadków wzrośnie setki razy? W tym przypadku potrzebny jest fajny inżynier Highload. Ale pod nieobecność pokojówki powierzyli mi rozwiązanie problemu. W pierwszej części artykułu opowiem Wam jak przeszliśmy z Redis do Redis-cluster, a w drugiej części podpowiem jak zacząć korzystać z klastra i na co zwrócić uwagę korzystając z niego.

Wybór technologii

Jest aż tak źle? oddziel Redisa (samodzielny redis) w konfiguracji 1 master i N slave? Dlaczego nazywam to przestarzałą technologią?

Nie, Redis nie jest taki zły... Są jednak pewne niedociągnięcia, których nie można zignorować.

  • Po pierwsze, Redis nie obsługuje mechanizmów odzyskiwania po awarii głównej. Aby rozwiązać ten problem zastosowaliśmy konfigurację z automatycznym przeniesieniem VIP-ów na nowego mastera, zmieniając rolę jednego z slave'ów i przełączając resztę. Mechanizm ten zadziałał, jednak nie można go nazwać rozwiązaniem niezawodnym. Po pierwsze, pojawiały się fałszywe alarmy, po drugie, był on jednorazowy, a po uruchomieniu konieczne było ręczne działanie w celu naciągnięcia sprężyny.

  • Po drugie, posiadanie tylko jednego wzorca doprowadziło do problemu shardingu. Musieliśmy stworzyć kilka niezależnych klastrów „1 master i N slave”, następnie ręcznie rozdzielić bazy danych pomiędzy te maszyny i mieć nadzieję, że jutro jedna z baz nie spuchnie tak bardzo, że trzeba będzie ją przenieść do osobnej instancji.

Jakie są opcje?

  • Najdroższym i najbogatszym rozwiązaniem jest Redis-Enterprise. Jest to rozwiązanie pudełkowe z pełnym wsparciem technicznym. Mimo, że z technicznego punktu widzenia wygląda idealnie, to jednak nie przypadł nam do gustu ze względów ideologicznych.
  • Klaster Redis. Od razu po wyjęciu z pudełka dostępna jest obsługa głównego przełączania awaryjnego i fragmentowania. Interfejs prawie nie różni się od zwykłej wersji. Wygląda obiecująco, o pułapkach porozmawiamy później.
  • Tarantool, Memcache, Aerospike i inne. Wszystkie te narzędzia robią prawie to samo. Ale każdy ma swoje wady. Postanowiliśmy nie wkładać wszystkich jajek do jednego koszyka. Do innych zadań używamy Memcache i Tarantool i patrząc w przyszłość powiem, że w naszej praktyce było z nimi więcej problemów.

Specyfika użytkowania

Przyjrzyjmy się, jakie problemy rozwiązaliśmy historycznie za pomocą Redis i z jakich funkcjonalności korzystaliśmy:

  • Buforuj przed żądaniami do zdalnych usług, takich jak 2GIS | Golang

    GET SET MGET MSET „WYBIERZ DB”

  • Pamięć podręczna przed MYSQL | PHP

    GET SET MGET MSET SKAN „KLUCZ PO WZORCU” „WYBIERZ DB”

  • Główny magazyn usługi pracy z sesjami i współrzędnymi kierowców | Golang

    GET SET MGET MSET "WYBIERZ DB" "DODAJ KLUCZ GEO" "UZYSKAJ KLUCZ GEO" SKAN

Jak widać, nie ma wyższej matematyki. W czym zatem tkwi trudność? Przyjrzyjmy się każdej metodzie osobno.

metoda
Opis
Cechy klastra Redis
decyzja

PRZYGOTOWAĆ SIĘ
Klawisz zapisu/odczytu

MGET MSET
Zapis/odczyt wielu kluczy
Klucze będą znajdować się w różnych węzłach. Gotowe biblioteki mogą wykonywać wielooperacje tylko w obrębie jednego węzła
Zamień MGET na potok N operacji GET

WYBIERZ bazę danych
Wybierz bazę, z którą będziemy pracować
Nie obsługuje wielu baz danych
Umieść wszystko w jednej bazie danych. Dodaj przedrostki do kluczy

SCAN
Przejrzyj wszystkie klucze w bazie danych
Ponieważ mamy jedną bazę danych, przeglądanie wszystkich kluczy w klastrze jest zbyt kosztowne
Zachowaj niezmiennik w obrębie jednego klawisza i wykonaj HSCAN na tym klawiszu. Lub całkowicie odmówić

GEO
Operacje z geokluczem
Klucz geograficzny nie jest fragmentowany

KLUCZ WEDŁUG WZORU
Wyszukiwanie klucza według wzoru
Ponieważ mamy jedną bazę danych, przeszukamy wszystkie klucze w klastrze. Za drogie
Odrzuć lub zachowaj niezmiennik, jak w przypadku SCAN

Redis kontra klaster Redis

Co tracimy, a co zyskujemy przechodząc na klaster?

  • Wady: tracimy funkcjonalność kilku baz danych.
    • Jeśli chcemy przechowywać logicznie niepowiązane dane w jednym klastrze, będziemy musieli stworzyć kule w postaci przedrostków.
    • Tracimy wszystkie operacje „bazowe”, takie jak SCAN, DBSIZE, CLEAR DB itp.
    • Wielooperacje stały się znacznie trudniejsze do wdrożenia, ponieważ mogą wymagać dostępu do kilku węzłów.
  • Zalety:
    • Tolerancja błędów w formie głównego przełączania awaryjnego.
    • Sharding po stronie Redis.
    • Przesyłaj dane pomiędzy węzłami atomowo i bez przestojów.
    • Dodawaj i redystrybuuj moce produkcyjne i ładunki bez przestojów.

Doszedłem do wniosku, że jeśli nie trzeba zapewniać wysokiego poziomu odporności na błędy, to przechodzenie do klastra nie jest tego warte, ponieważ może to być nietrywialne zadanie. Ale jeśli początkowo wybierzesz między wersją oddzielną a wersją klastrową, powinieneś wybrać klaster, ponieważ nie jest gorszy, a dodatkowo uwolni Cię od niektórych bólów głowy

Przygotowanie do przeprowadzki

Zacznijmy od wymagań dotyczących przeprowadzki:

  • Powinno być płynnie. Całkowite zatrzymanie usługi na 5 minut nam nie odpowiada.
  • Powinno to przebiegać tak bezpiecznie i stopniowo, jak to tylko możliwe. Chcę mieć jakąś kontrolę nad sytuacją. Nie chcemy rzucić wszystkiego na raz i modlić się o przycisk wycofania.
  • Minimalna utrata danych podczas przenoszenia. Rozumiemy, że przeniesienie atomowe będzie bardzo trudne, dlatego pozwalamy na pewną desynchronizację między danymi w zwykłym i klastrowym Redis.

Utrzymanie klastra

Tuż przed przeprowadzką powinniśmy zastanowić się, czy możemy wesprzeć klaster:

  • Wykresy. Używamy Prometheusa i Grafany do tworzenia wykresów obciążenia procesora, wykorzystania pamięci, liczby klientów, liczby operacji GET, SET, AUTH itp.
  • Ekspertyza. Wyobraź sobie, że jutro będziesz miał pod swoją odpowiedzialnością ogromny klaster. Jeśli się zepsuje, nikt oprócz Ciebie nie będzie w stanie tego naprawić. Jeśli zacznie zwalniać, wszyscy będą biec w twoją stronę. Jeśli będziesz potrzebował dodać zasoby lub rozłożyć obciążenie, wróć do Ciebie. Aby nie siwieć w wieku 25 lat, zaleca się uwzględnienie tych przypadków i wcześniejsze sprawdzenie, jak technologia zachowa się pod pewnymi działaniami. Porozmawiajmy o tym szerzej w części „Ekspertyza”.
  • Monitoring i alerty. Kiedy klaster się rozpada, chcesz dowiedzieć się o tym jako pierwszy. Tutaj ograniczyliśmy się do powiadomienia, że ​​wszystkie węzły zwracają tę samą informację o stanie klastra (tak, bywa różnie). Inne problemy można szybciej zauważyć dzięki alertom z usług klienta Redis.

Przesunąć

Jak będziemy się poruszać:

  • Przede wszystkim należy przygotować bibliotekę do pracy z klastrem. Za podstawę wersji Go uznaliśmy go-redis i zmieniliśmy ją trochę, aby nam odpowiadała. Wdrożyliśmy Multi-metody poprzez potoki, a także nieznacznie poprawiliśmy zasady powtarzających się żądań. Wersja PHP miała więcej problemów, ale ostatecznie zdecydowaliśmy się na php-redis. Niedawno wprowadzili wsparcie dla klastrów i naszym zdaniem wygląda to dobrze.
  • Następnie musisz wdrożyć sam klaster. Odbywa się to dosłownie za pomocą dwóch poleceń opartych na pliku konfiguracyjnym. Omówimy to ustawienie bardziej szczegółowo poniżej.
  • Do stopniowego przenoszenia używamy trybu suchego. Ponieważ mamy dwie wersje biblioteki z tym samym interfejsem (jedna dla wersji zwykłej, druga dla klastra), nic nie kosztuje stworzenie wrappera, który będzie działał z osobną wersją i równolegle duplikował wszystkie żądania do klastra, porównaj odpowiedzi i zapisz rozbieżności w logach (w naszym przypadku w NewRelic). Dlatego nawet jeśli wersja klastra ulegnie awarii podczas wdrażania, nie będzie to miało wpływu na naszą produkcję.
  • Po rozłożeniu klastra w trybie suchym możemy spokojnie przyjrzeć się wykresowi rozbieżności odpowiedzi. Jeśli poziom błędów powoli, ale systematycznie zbliża się do jakiejś małej stałej, wszystko jest w porządku. Dlaczego nadal występują rozbieżności? Ponieważ zapis w osobnej wersji następuje nieco wcześniej niż w klastrze, a ze względu na mikrolag, dane mogą się różnić. Pozostaje tylko przyjrzeć się dziennikom rozbieżności i jeśli wszystkie zostaną wyjaśnione brakiem atomowości zapisu, możemy przejść dalej.
  • Teraz możesz przełączyć tryb suszenia w przeciwnym kierunku. Będziemy pisać i czytać z klastra oraz powielać go w osobnej wersji. Po co? Przez najbliższy tydzień chciałbym obserwować pracę klastra. Jeśli nagle okaże się, że przy szczytowym obciążeniu są problemy, albo czegoś nie wzięliśmy pod uwagę, zawsze mamy awaryjny powrót do starego kodu i aktualnych danych dzięki trybowi suchemu.
  • Pozostaje tylko wyłączyć tryb suchy i zdemontować osobną wersję.

Specjalizacja

Na początek krótko o konstrukcji klastra.

Po pierwsze, Redis to sklep typu klucz-wartość. Jako klucze używane są dowolne ciągi znaków. Jako wartości można używać liczb, ciągów znaków i całych struktur. Tych ostatnich jest bardzo wiele, ale dla zrozumienia ogólnej struktury nie jest to dla nas ważne.
Kolejnym poziomem abstrakcji po kluczach są sloty (SLOTS). Każdy klucz należy do jednego z 16 383 miejsc. W każdym gnieździe może znajdować się dowolna liczba kluczy. Zatem wszystkie klucze są podzielone na 16 383 rozłączne zbiory.
O przechodzeniu z Redis do klastra Redis

Następnie w klastrze musi znajdować się N węzłów głównych. Każdy węzeł można traktować jako osobną instancję Redis, która wie wszystko o innych węzłach w klastrze. Każdy węzeł główny zawiera pewną liczbę gniazd. Każde gniazdo należy tylko do jednego węzła głównego. Wszystkie sloty muszą być rozdzielone pomiędzy węzłami. Jeśli niektóre sloty nie zostaną przydzielone, przechowywane w nich klucze będą niedostępne. Rozsądne jest uruchamianie każdego węzła głównego na osobnej maszynie logicznej lub fizycznej. Warto również pamiętać, że każdy węzeł działa tylko na jednym rdzeniu, a jeśli chcesz uruchomić wiele instancji Redis na tej samej maszynie logicznej, upewnij się, że działają one na różnych rdzeniach (nie próbowaliśmy tego, ale teoretycznie powinno działać) . Zasadniczo węzły główne zapewniają regularne dzielenie na fragmenty, a większa liczba węzłów głównych umożliwia skalowanie żądań zapisu i odczytu.

Po rozdzieleniu wszystkich kluczy pomiędzy gniazdami i rozproszeniu gniazd pomiędzy węzłami głównymi, do każdego węzła głównego można dodać dowolną liczbę węzłów podrzędnych. W każdym takim połączeniu master-slave będzie działać normalna replikacja. Urządzenia podrzędne są potrzebne do skalowania żądań odczytu i przełączania awaryjnego w przypadku awarii urządzenia głównego.
O przechodzeniu z Redis do klastra Redis

Porozmawiajmy teraz o operacjach, które lepiej byłoby móc wykonać.

Dostęp do systemu uzyskamy poprzez Redis-CLI. Ponieważ Redis nie ma jednego punktu wejścia, możesz wykonać następujące operacje na dowolnym z węzłów. W każdym punkcie osobno zwracam uwagę na możliwość wykonania operacji pod obciążeniem.

  • Pierwszą i najważniejszą rzeczą, jakiej potrzebujemy, jest obsługa węzłów klastra. Zwraca stan klastra, pokazuje listę węzłów, ich role, rozkład slotów itp. Więcej informacji można uzyskać, korzystając z informacji o klastrze i gniazd klastra.
  • Byłoby miło móc dodawać i usuwać węzły. W tym celu istnieją operacje spotykania klastra i zapominania klastra. Należy pamiętać, że funkcję zapominania klastra należy zastosować do KAŻDEGO węzła, zarówno głównego, jak i replik. A klaster Meet należy wywołać tylko w jednym węźle. Ta różnica może być niepokojąca, dlatego najlepiej poznać ją przed uruchomieniem klastra. Dodanie węzła odbywa się bezpiecznie w bitwie i nie wpływa w żaden sposób na działanie klastra (co jest logiczne). Jeśli zamierzasz usunąć węzeł z klastra, powinieneś upewnić się, że nie pozostały na nim żadne sloty (w przeciwnym razie ryzykujesz utratę dostępu do wszystkich kluczy w tym węźle). Nie usuwaj także mastera, który ma slave'y, w przeciwnym razie zostanie przeprowadzone niepotrzebne głosowanie na nowego mastera. Jeśli węzły nie mają już gniazd, jest to mały problem, ale po co nam dodatkowe opcje, skoro możemy najpierw usunąć urządzenia podrzędne.
  • Jeśli chcesz na siłę zamienić pozycje master i slave, wystarczy polecenie przełączania awaryjnego klastra. Wzywając go w bitwie, musisz zrozumieć, że mistrz nie będzie dostępny podczas operacji. Zwykle przełączenie następuje w czasie krótszym niż sekunda, ale nie jest atomowe. Można się spodziewać, że w tym czasie niektóre żądania kierowane do urządzenia głównego zawiodą.
  • Przed usunięciem węzła z klastra nie powinno być na nim żadnych wolnych miejsc. Lepiej jest je ponownie rozdystrybuować za pomocą polecenia klastra reshard. Sloty zostaną przeniesione z jednego mistrza na drugiego. Cała operacja może zająć kilka minut, jest to uzależnione od ilości przesyłanych danych, jednak proces przesyłania jest bezpieczny i nie wpływa w żaden sposób na działanie klastra. Dzięki temu wszystkie dane można przesyłać z jednego węzła do drugiego bezpośrednio pod obciążeniem i bez obawy o ich dostępność. Istnieją jednak również subtelności. Po pierwsze, transfer danych wiąże się z pewnym obciążeniem węzłów odbiorcy i nadawcy. Jeśli węzeł odbiorczy jest już mocno obciążony na procesorze, nie należy go ładować wraz z odebraniem nowych danych. Po drugie, gdy tylko na urządzeniu wysyłającym nie zostanie ani jedno miejsce, wszystkie jego urządzenia podrzędne natychmiast trafią do urządzenia głównego, do którego te miejsca zostały przeniesione. Problem w tym, że wszyscy ci podrzędni będą chcieli zsynchronizować dane na raz. Będziesz miał szczęście, jeśli będzie to synchronizacja częściowa, a nie pełna. Weź to pod uwagę i połącz operacje przesyłania slotów i wyłączania/przenoszenia urządzeń podrzędnych. Lub miej nadzieję, że masz wystarczający margines bezpieczeństwa.
  • Co zrobić, jeśli podczas transferu okaże się, że zgubiłeś gdzieś swoje sloty? Mam nadzieję, że ten problem Cię nie dotyczy, ale jeśli tak się stanie, konieczna będzie operacja naprawy klastra. Przynajmniej rozrzuci szczeliny po węzłach w losowej kolejności. Polecam sprawdzić jego działanie usuwając najpierw z klastra węzeł z rozproszonymi slotami. Ponieważ dane w nieprzydzielonych slotach są już niedostępne, jest już za późno na martwienie się problemami z dostępnością tych slotów. Z kolei operacja nie będzie miała wpływu na rozproszone gniazda.
  • Kolejną przydatną operacją jest monitorowanie. Pozwala zobaczyć w czasie rzeczywistym całą listę żądań kierowanych do węzła. Co więcej, możesz go grepować i dowiedzieć się, czy jest niezbędny ruch.

Warto również wspomnieć o procedurze master Failover. Krótko mówiąc, istnieje i moim zdaniem sprawdza się świetnie. Nie myśl jednak, że jeśli odłączysz przewód zasilający na maszynie z węzłem głównym, Redis natychmiast się przełączy, a klienci nie zauważą straty. W mojej praktyce przełączenie następuje w ciągu kilku sekund. W tym czasie część danych będzie niedostępna: wykryta zostanie niedostępność mastera, węzły głosują na nowego, nastąpi zamiana urządzeń slave, synchronizacja danych. Najlepszym sposobem, aby przekonać się na własnej skórze, że program działa, jest przeprowadzenie lokalnych ćwiczeń. Podnieś klaster na swoim laptopie, daj mu minimalne obciążenie, zasymuluj awarię (na przykład blokując porty) i oceń prędkość przełączania. Moim zdaniem dopiero po dniu lub dwóch graniu w ten sposób można być pewnym działania technologii. Cóż, albo miej nadzieję, że oprogramowanie, z którego korzysta połowa Internetu, prawdopodobnie działa.

Konfiguracja

Często konfiguracja jest pierwszą rzeczą, której potrzebujesz, aby rozpocząć pracę z narzędziem, a kiedy wszystko działa, nie chcesz nawet dotykać konfiguracji. Zmuszenie się do powrotu do ustawień i dokładnego przejrzenia ich wymaga pewnego wysiłku. W mojej pamięci mieliśmy co najmniej dwie poważne awarie wynikające z nieuwagi przy konfiguracji. Zwróć szczególną uwagę na następujące punkty:

  • timeout 0
    Czas po którym nieaktywne połączenia zostaną zamknięte (w sekundach). 0 - nie zamykaj
    Nie każda nasza biblioteka była w stanie poprawnie zamknąć połączenia. Wyłączając to ustawienie, ryzykujemy przekroczenie limitu liczby klientów. Z drugiej strony, jeśli taki problem wystąpi, to automatyczne zakończenie utraconych połączeń zamaskuje go, a my możemy tego nie zauważyć. Ponadto nie należy włączać tego ustawienia podczas korzystania z połączeń trwałych.
  • Zapisz xy i tylko dołącz tak
    Zapisywanie migawki RDB.
    Poniżej omówimy szczegółowo kwestie RDB/AOF.
  • stop-writes-on-bgsave-error nie i slave-serve-stale-data tak
    Jeśli ta opcja jest włączona, jeśli migawka RDB ulegnie uszkodzeniu, urządzenie główne przestanie akceptować żądania zmian. Jeśli połączenie z masterem zostanie utracone, slave może nadal odpowiadać na żądania (tak). Lub przestanie odpowiadać (nie)
    Nie jesteśmy zadowoleni z sytuacji, w której Redis zamienia się w dynię.
  • okres repl-ping-slave 5
    Po tym czasie zaczniemy się martwić, że master się zepsuł i czas przeprowadzić procedurę przełączania awaryjnego.
    Będziesz musiał ręcznie znaleźć równowagę między fałszywymi alarmami a uruchomieniem przełączania awaryjnego. W naszej praktyce jest to 5 sekund.
  • repl-backlog-size 1024mb i epl-backlog-ttl 0
    Dokładnie tyle danych możemy przechowywać w buforze na wypadek nieudanej repliki. Jeśli bufor się wyczerpie, będziesz musiał całkowicie zsynchronizować.
    Praktyka podpowiada, że ​​lepiej ustawić wyższą wartość. Istnieje wiele powodów, dla których replika może zacząć się opóźniać. Jeśli opóźnia się, najprawdopodobniej twój mistrz już stara się sobie z tym poradzić, a pełna synchronizacja będzie ostatnią kroplą.
  • maksymalna liczba klientów 10000
    Maksymalna liczba klientów jednorazowych.
    Z naszego doświadczenia wynika, że ​​lepiej ustawić wyższą wartość. Redis radzi sobie dobrze z połączeniami 10 tys. Upewnij się tylko, że w systemie jest wystarczająca liczba gniazd.
  • maxmemory-policy volatile-ttl
    Reguła, według której klucze są usuwane po osiągnięciu limitu dostępnej pamięci.
    Ważna jest tu nie sama reguła, ale zrozumienie, jak to się stanie. Redis można pochwalić za zdolność do normalnej pracy po osiągnięciu limitu pamięci.

Problemy z RDB i AOF

Chociaż sam Redis przechowuje wszystkie informacje w pamięci RAM, istnieje również mechanizm zapisywania danych na dysku. Dokładniej, trzy mechanizmy:

  • Migawka RDB - pełna migawka wszystkich danych. Ustaw przy użyciu konfiguracji SAVE XY i brzmi: „Zapisz pełną migawkę wszystkich danych co X sekund, jeśli zmieniło się co najmniej Y klawiszy”.
  • Plik tylko do dołączania - lista operacji w kolejności ich wykonywania. Dodaje nowe operacje przychodzące do pliku co X sekund lub co Y operacji.
  • RDB i AOF są kombinacją dwóch poprzednich.

Wszystkie metody mają swoje zalety i wady, nie będę ich wszystkich wymieniać, zwrócę tylko uwagę na punkty, które moim zdaniem nie są oczywiste.

Po pierwsze, zapisanie migawki RDB wymaga wywołania FORK. Jeśli jest dużo danych, może to spowodować zawieszenie całego Redis na okres od kilku milisekund do sekundy. Dodatkowo system musi przydzielić pamięć na taki snapshot, co powoduje konieczność utrzymywania podwójnego zapasu RAM na maszynie logicznej: jeśli dla Redisa przydzielone zostanie 8 GB, to na maszynie wirtualnej powinno być dostępne 16 GB To.

Po drugie, występują problemy z częściową synchronizacją. W trybie AOF, po ponownym podłączeniu urządzenia podrzędnego, zamiast częściowej synchronizacji można przeprowadzić pełną synchronizację. Dlaczego tak się dzieje, nie mogłem zrozumieć. Ale warto o tym pamiętać.

Te dwa punkty już skłaniają nas do zastanowienia się, czy naprawdę potrzebujemy tych danych na dysku, jeśli wszystko jest już zduplikowane przez urządzenia podrzędne. Dane mogą zostać utracone tylko w przypadku awarii wszystkich urządzeń podrzędnych i jest to problem na poziomie „pożaru w DC”. Jako kompromis możesz zaproponować zapisywanie danych tylko na urządzeniach podrzędnych, ale w tym przypadku musisz się upewnić, że te urządzenia podrzędne nigdy nie staną się urządzeniami nadrzędnymi podczas odzyskiwania po awarii (w tym celu w ich konfiguracji znajduje się ustawienie priorytetu urządzeń podrzędnych). Sami w każdym konkretnym przypadku zastanawiamy się, czy konieczne jest zapisywanie danych na dysku i najczęściej odpowiedź brzmi „nie”.

wniosek

Podsumowując, mam nadzieję, że udało mi się dać ogólne pojęcie o działaniu redis-cluster tym, którzy w ogóle o nim nie słyszeli, a także zwróciłem uwagę na pewne nieoczywiste punkty dla tych, którzy z niego korzystali przez długi czas.
Dziękuję za poświęcony czas i jak zawsze mile widziane komentarze na ten temat.

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

Dodaj komentarz