P: Jeden serwer usługowy, jedna baza danych, działanie: zapytanie o aktualne saldo użytkownika, potrącenie 3% bieżącego salda jako opłata za obsługę
Synchronizacja zamek DB Lock
P: Dwa serwery usługowe, jedna baza danych, działanie: zapytanie o aktualne saldo użytkownika, potrącenie 3% bieżącego salda jako opłata za obsługę Zamki rozproszone
Jakiego rodzaju rozproszonego zamka potrzebujemy? Może zapewnić, że w rozproszonym klastrze aplikacji ta sama metoda może być wykonywana tylko przez jeden wątek na jednej maszynie jednocześnie.
Jeśli ten zamek jest zamkiem reentrantowym (unikaj deadlocków)
Ten zamek najlepiej jest blokujący (rozważ, czy chcesz go zastosować zgodnie z potrzebami firmy).
Ten zamek najlepiej jest uczciwy (rozważ, czy chcesz go wybrać w zależności od potrzeb biznesowych)
Dostępne są wysoce dostępne funkcje blokady akwizycji i uwalniania
Wydajność blokad akwizycji i zwolnienia jest lepsza
1. Rozproszone blokady oparte na bazach danych
Rozproszone blokady oparte na implementacjach opartych na tabelach
Gdy chcemy zablokować metodę, wykonaj następujące SQL: wstaw do methodLock(method_name,desc) wartości ('method_name','desc')
Ponieważ wprowadziliśmy ograniczenie unikalności na method_name, jeśli do bazy danych zostanie przesłanych wiele żądań jednocześnie, baza danych zapewni, że tylko jedna operacja może się powiedzieć, wtedy możemy założyć, że wątek, który skutecznie uzyskał blokadę metody, może wykonać treść treści metody.
Gdy metoda zostanie wykonana, jeśli chcesz zwolnić blokadę, musisz wykonać następujące SQL: delete from methodLock, gdzie method_name ='method_name'
Ta prosta implementacja powyżej ma następujące problemy:
- Ten blok zależy od dostępności bazy danych, która jest pojedynczym punktem i powoduje, że system biznesowy stanie się niedostępny po zawieszeniu bazy danych.
- Ta blokada nie ma czasu wygaśnięcia, a po niepowodzeniu operacji odblokowania rekord blokady pozostaje w bazie danych i inne wątki nie będą już mogły go uzyskać.
- Ten blok może być nieblokujący tylko dlatego, że operacja wstawiania danych bezpośrednio zgłasza błąd po niepowodzeniu wstawienia. Wątki, które nie nabywają blokad, nie wejdą do kolejki i będą musiały ponownie uruchomić operację pozyskiwania blokady, aby ponownie ją uzyskać.
- Zamek jest niepowracający i ten sam gwint nie może go ponownie uzyskać, dopóki nie zostanie zwolniony. Ponieważ dane w danych już istnieją.
- Ta zamka jest niesprawiedliwa, a wszystkie wątki czekające na nią rywalizują o zamk dzięki szczęściu.
Oczywiście powyższe problemy możemy rozwiązać także na inne sposoby.
- Czy baza danych to jeden punkt? Zbuduj dwie bazy danych, a dane będą synchronizowane w obu kierunkach. Po rozłączeniu szybko przełącz się do biblioteki zapasowej.
- Brak czasu ważności? Po prostu wykonaj zaplanowane zadanie, aby regularnie czyścić dane z limitu czasu w bazie danych.
- Nieblokujące? Rób pętlę długą, aż insert się powiedzie, a potem wracaj do sukcesu.
- Osoba niereancjonująca? Dodaj pole do tabeli bazy danych, aby zapisać informacje o hostze i wątku maszyny, która obecnie otrzymuje blokadę, a następnym razem, gdy ją dostaniesz, najpierw zapytaj bazę danych, jeśli informacje o hostze i wątku bieżącej maszyny znajdziesz w bazie, możesz bezpośrednio przypisać blokadę do niej.
- Niesprawiedliwe? Stwórz kolejną tabelę pośrednią, aby zapisać wszystkie wątki oczekujące na blokadę i sortować je według czasu utworzenia, a tylko pierwszy utworzony wątek może przejąć blokadę
Rozproszone zamki oparte na wyłącznych zamkach
Oprócz dodawania i usuwania rekordów w tabeli danych, rozproszone blokady mogą być również implementowane za pomocą blokad dołączonych do danych.
Korzystamy też z tabeli bazy danych, którą właśnie stworzyliśmy. Rozproszone blokady mogą być realizowane poprzez wyłączne blokady w bazach danych. Silnik InnoDB oparty na MySQL może wykorzystywać następujące metody do implementacji operacji blokady:
Jeśli dodasz do aktualizacji po zapytaniu, baza danych doda wyłączną blokadę do tabeli bazy danych podczas procesu zapytania. Gdy do rekordu dodana jest wyłączna blokada, inne wątki nie mogą już dodać wyłącznej blokady do rekordu na tej linii.
Możemy przypuszczać, że wątek, który uzyska wyłączny zamek, może uzyskać zamek rozproszony, a gdy blokada zostanie uzyskana, można wykonać logikę biznesową metody, a następnie odblokować ją za pomocą następujących metod:
public void unlock(){ connection.commit(); }
via connection.commit(); operacja zwalniająca zamek.
Ta metoda może skutecznie rozwiązać wspomniane wcześniej problemy dotyczące niemożności zwolnienia i zablokowania zamka.
Blokowanie zamków? Instrukcja for update wraca natychmiast po pomyślnym wykonaniu i pozostaje zablokowana do momentu zakończenia sukcesu.
Usługa nie działa po zablokowaniu, nie można go zwolnić? W ten sposób baza danych sama zwalnia blokadę po awarii usługi.
Jednak nadal nie rozwiązuje bezpośrednio problemu pojedynczego punktu bazy danych, reentrancji i uczciwego blokowania.
Podsumowując sposób wykorzystania bazy danych do implementacji rozproszonych blokad, które opierają się na tabeli w bazie danych, jedno polega na określeniu istnienia blokady na podstawie istnienia rekordów w tabeli, a drugim na implementację rozproszonych blokad poprzez wyłączny zamek bazy danych.
Zalety rozproszonego blokowania w bazach danych
Bezpośrednio, z pomocą bazy danych, jest to łatwe do zrozumienia.
Wady implementacji rozproszonych blokad w bazach danych
Pojawią się różne problemy, a całe rozwiązanie stanie się coraz bardziej złożone w procesie ich rozwiązywania.
Obsługa bazy danych wymaga pewnych narzutów i należy uwzględnić kwestie wydajnościowe.
2. Rozproszone blokady oparte na pamięci podręcznej
W porównaniu z rozproszonym rozwiązaniem do blokowania opartym na bazie danych, implementacja oparta na pamięci podręcznej będzie działać lepiej pod względem wydajności.
Obecnie istnieje wiele dojrzałych produktów cachingowych, w tym Redis, memcached itd. Tutaj bierzemy Redis jako przykład, aby przeanalizować schemat wykorzystania pamięci podręcznej do implementacji rozproszonych blokad.
W Internecie jest wiele powiązanych artykułów na temat implementacji rozproszonych blokad opartych na Redis, a główną metodą implementacji jest użycie metody Jedis.setNX.
Istnieje także kilka problemów z powyższą implementacją:
1. Problem pojedynczego punktu.
2. Ta blokada nie ma czasu ważności, po niepowodzeniu operacji odblokowania rekord blokady będzie cały czas w redis i inne wątki nie będą mogły już uzyskać blokady.
3. Ten zamek może być tylko nieblokujący i wróci bezpośrednio, niezależnie od sukcesu lub porażki.
4. Ten zamek jest niereentrantny, po zdobyciu zamka przez nić nie może go ponownie zdobyć przed jego zwolnieniem, ponieważ klucz użyty już istnieje w redis. operacje setNX nie mogą być już wykonywane.
5. Ten blok jest niesprawiedliwy, wszystkie oczekujące wątki rozpoczynają operacje setNX jednocześnie, a szczęśliwe wątki mogą zdobyć blokadę.
Oczywiście istnieją też sposoby, by to rozwiązać.
- Obecnie główne usługi buforowania wspierają wdrażanie klastrów, aby rozwiązywać problemy pojedynczego punktu poprzez klastry.
- Brak czasu ważności? Metoda setExpire w redis obsługuje nadchodzący czas wygaśnięcia, a dane są automatycznie usuwane po upływie tego czasu.
- Nieblokujące? podczas wielokrotnych egzekucji.
- Czy nie da się ponownie wejść? Po uzyskaniu blokady przez wątek zapisz aktualne informacje o hostze i wątku, a przed następnym razem sprawdź, czy jesteś właścicielem aktualnej blokady.
- Niesprawiedliwe? Umieść wszystkie oczekujące wątki w kolejce zanim wątek zdobędzie blokadę, a następnie nabyj blokadę na zasadzie pierwszy wszedł, pierwszy wyszedł.
Polityka synchronizacji klastra redis zajmuje trochę czasu i możliwe, że wątek A zostanie zablokowany po pomyślnym ustawieniu NX, ale ta wartość nie została zaktualizowana na serwerze, na którym wątek B wykonuje setNX, co spowoduje problemy z współbieżnością.
Salvatore Sanfilippo, autor redis, zaproponował algorytm Redlock, który implementuje rozproszone zarządzanie blokadami (DLM), które jest bezpieczniejsze i bardziej niezawodne niż pojedynczy węzeł.
Algorytm Redlock zakłada, że istnieje N węzłów redis niezależnych od siebie, zazwyczaj ustawionych na N=5, i te N węzłów działa na różnych maszynach, aby zachować niezależność fizyczną.
Kroki algorytmu są następujące:
1. Klient otrzymuje aktualny czas w milisekundach. 2. Klient próbuje uzyskać blokadę N węzłów (każdy z nich otrzymuje blokadę w taki sam sposób jak wspomnianą wcześniej blokadę pamięci podręcznej), a N węzłów otrzymuje blokadę z tym samym kluczem i wartością. Klient musi ustawić limit czasu dostępu do interfejsu, a czas wyłączenia interfejsu musi być znacznie krótszy niż czas blokady, na przykład czas automatycznego zwolnienia blokady to 10 sekund, a limit czasu interfejsu jest ustawiony na około 5-50 ms. Pozwala to jak najszybciej wygasać czas przy dostępie do węzła redis po jego awarii i ogranicza normalne użycie blokady. 3. Klient oblicza, ile czasu zajmuje uzyskanie blokady, odejmując czas uzyskany w kroku 1 od aktualnego czasu, tylko gdy klient uzyska więcej niż 3 węzły blokady, a czas na uzyskanie blokady jest krótszy niż czas wygaśnięcia blokady, klient uzyskuje blokadę rozproszoną. 4. Czas klienta na zdobycie zamka to czas wyznaczonego czasu blokady pomniejszony o czas potrzebny na uzyskanie zamka obliczany w kroku 3. 5. Jeśli klient nie uzyska blokady, usunie wszystkie blokady po kolei. Korzystając z algorytmu Redlock, można zagwarantować, że rozproszona usługa blokady nadal działa przy zawieszaniu się do 2 węzłów, co znacznie poprawia dostępność w porównaniu do poprzedniego zamknięcia bazy danych i zamknięcia pamięci podręcznej.
Jednak ekspert ds. dystrybucji napisał artykuł "How to do distributed locking", kwestionując poprawność Redlocka.
Ekspert wspomniał, że przy rozważaniu rozproszonych blokad należy wziąć pod uwagę dwa aspekty: wydajność i poprawność.
Jeśli używasz wysokowydajnego rozproszonego zamka i poprawność nie jest wymagana, to wystarczy użycie zamka pamięci podręcznej.
Jeśli używasz bardzo niezawodnego zamka rozproszonego, musisz wziąć pod uwagę ścisłe kwestie niezawodności. Redlock natomiast nie spełnia poprawności. Dlaczego nie? Eksperci wymieniają kilka aspektów.
Obecnie wiele języków programowania korzysta z maszyn wirtualnych z funkcjami GC, w Full GC program przestaje przetwarzać GC, czasem Full GC trwa długo, a nawet program ma kilka minut opóźnień; artykuł podaje przykład HBase, HBase czasem GC przez kilka minut, co powoduje wygaśnięcie czasu dzierżawy. Na przykład na poniższym rysunku klient 1 otrzymuje blokadę i jest bliski przetworzenia współdzielonego zasobu, a gdy zbliża się do przetworzenia współdzielonego zasobu, pełna GC następuje aż do wygaśnięcia blokady. W ten sposób klient 2 ponownie zdobywa blokadę i zaczyna pracę nad współdzielonym zasobem. Gdy klient 2 przetwarza, klient 1 kończy pełną GC i zaczyna przetwarzać wspólne zasoby, tak aby obaj klienci przetwarzali wspólne zasoby.
Eksperci podali rozwiązanie, jak pokazano na poniższym rysunku, wygląda to na MVCC, przynieś token do zamka, token to koncepcja wersji, za każdym razem, gdy blokada operacyjna zostaje zakończona, token zostanie dodany 1, przynieś token podczas przetwarzania współdzielonych zasobów, tylko określona wersja tokena może obsłużyć współdzielony zasób.
Następnie ekspert dodał, że algorytm opiera się na czasie lokalnym, a Redis polega na metodzie getTimeOfDay, aby uzyskać czas zamiast na zegarze monotonicznym podczas obsługi wygaśnięcia klucza, co również prowadzi do niedokładności czasu. Na przykład w scenariuszu dwa klienty 1 i 2 mają 5 węzłów redis (A, B, C, D i E).
1. Klient 1 skutecznie zdobywa zamek od A, B i C oraz uzyskuje timeout sieci zamków od D i E. 2. Zegar węzła C jest niedokładny, co powoduje wyłączenie blokady. 3. klient 2 pomyślnie zdobywa blokadę od C, D i E oraz uzyskuje wyłączenie blokady sieciowej od A i B. 4. W ten sposób zarówno klient 1, jak i klient 2 uzyskują blokadę. Podsumowując dwa punkty, które eksperci mówią o niedostępności Redlocka:
1. GC i inne scenariusze mogą wystąpić w dowolnym momencie, powodując uzyskanie blokady przez klienta, a czas na przekroczenie przetwarzania powoduje, że inny klient ją uzyska. Eksperci podali także rozwiązanie do używania tokenów samoprzyrastających. 2. Algorytm opiera się na czasie lokalnym, a zegar będzie niedokładny, co skutkuje tym, że dwóch klientów będzie miało blokady jednocześnie. Dlatego eksperci doszli do wniosku, że Redlock może normalnie działać tylko w ograniczonym zakresie opóźnień sieciowych, ograniczonych przerw w programie oraz ograniczonym zakresie błędów zegara, ale granice tych trzech scenariuszy nie mogą być potwierdzone, dlatego eksperci nie zalecają stosowania Redlocka. W przypadku sytuacji wymagających wysokiej poprawności eksperci polecają Zookeeper, o którym później będzie mowa o użyciu Zookeepera jako rozproszonego zamka.
Odpowiedź autora Redis
Autor Redis odpowiedział, pisząc blog po przeczytaniu artykułu eksperta. Autor uprzejmie podziękował ekspertowi, a następnie wyraził swoje niezadowolenie z jego poglądem.
Dyskusję autora REDIS na temat wykorzystania tokenów do rozwiązania problemu blokady czasowej można podsumować w następujących pięciu punktach:
Punkt 1, stosowanie rozproszonych blokad polega zazwyczaj na tym, że nie masz innego sposobu kontrolowania współdzielonych zasobów, eksperci używają tokenów do zapewnienia przetwarzania współdzielonych zasobów, wtedy nie ma potrzeby stosowania rozproszonych blokad. Punkt 2: W przypadku generowania tokenów, aby zapewnić niezawodność tokenów uzyskanych przez różnych klientów, usługa generująca tokeny nadal wymaga rozproszonych blokad, aby zapewnić niezawodność usługi. Punkt 3, ponieważ eksperci mówią o tokenach samoprzyrastających, autor redis uważa, że jest to całkowicie zbędne, każdy klient może wygenerować unikalny UUID jako token i ustawić współdzielony zasób w stanie, który może obsługiwać tylko klient z uuid, tak aby inni klienci nie mogli przetwarzać współdzielonego zasobu, dopóki klient, który uzyska blokadę, nie zwolni blokady. Jak pokazano na powyższym rysunku, jeśli klient tokenu 34 wyśle GC podczas procesu zapisu i spowoduje wygaśnięcie blokady, inny klient może przejąć blokadę tokena 35 i zacząć zapisywać ponownie, co skutkuje konfliktem blokad. Dlatego kolejność tokenów nie może być łączona z zasobami współdzielonymi. Punkt 5: autor redis uważa, że w większości scenariuszy rozproszone blokady są używane do obsługi problemów aktualizacji w scenariuszach nietransakcyjnych. Autor powinien mieć na myśli, że są sytuacje, w których trudno jest łączyć tokeny do obsługi współdzielonych zasobów, więc trzeba polegać na blokadach do blokowania zasobów i ich przetwarzania. Kolejny problem z zegarem, o którym mówią eksperci, autorzy Redis również podają wyjaśnienie. Jeśli czas potrzebny na zdobycie zamka jest zbyt długi i przekracza domyślny czas przejścia zamka, klient nie może go wtedy zdobyć i nie zaproponuje żadnych przykładów przez ekspertów.
Osobiste uczucia
Pierwszym problemem, który podsumowuję, jest to, że po uzyskaniu przez klienta rozproszonej blokady, blokada może zostać zwolniona po upływie czasu podczas przetwarzania przez klienta. Wcześniej, mówiąc o timeoutzie wyznaczonym przez blokadę bazy danych wynoszącą 2 minuty, jeśli zadanie zajmuje blokadę zlecenia dłużej niż 2 minuty, to drugie centrum handlowe może uzyskać tę blokadę zlecenia, dzięki czemu oba centra mogą przetwarzać to samo zlecenie jednocześnie. W normalnych warunkach zadanie jest przetwarzane w kilka sekund, ale czasami czas wyznaczony przy dołączeniu do żądania RPC jest zbyt długi, a w zadaniu występuje wiele takich żądań, wtedy prawdopodobnie zostanie przekroczony czas automatycznego odblokowania. Jeśli piszemy w Javie, może być pełny GC pośrodku, więc po odblokowaniu blokady po upływie blokady klient nie może go zauważyć, co jest bardzo poważną sprawą. Nie sądzę, żeby to był problem samej blokady, dopóki każda wspomniana rozproszona blokada ma cechy zwolnienia timeoutu, taki problem się pojawi. Jeśli używasz funkcji blokady timeout, klient musi ustawić timeout blokady i podjąć odpowiednie działania, zamiast kontynuować przetwarzanie współdzielonego zasobu. Algorytm Redlocka zwraca czas blokady, który klient może zająć po uzyskaniu blokady, a klient musi przetworzyć ten czas, aby zatrzymać zadanie po upływie tego czasu.
Drugim problemem jest to, że eksperci rozproszeni nie rozumieją Redlocka. Kluczową cechą Redlocka jest to, że czas potrzebny na uzyskanie zamka to całkowity czas, jaki zamk domyślnie przyjmuje do timeoutu pomniejszony o czas potrzebny na jej uzyskanie, więc czas potrzebny na przetworzenie przez klienta jest względny, niezależnie od czasu lokalnego.
Z tego punktu widzenia poprawność Redlocka jest całkowicie gwarantowana. Dokładna analiza Redlocka, w porównaniu do redis węzła, główną cechą Redlocka jest wyższa niezawodność, co jest istotną cechą w niektórych scenariuszach. Ale uważam, że Redlock wydał za dużo pieniędzy, żeby osiągnąć niezawodność.
- Po pierwsze, aby Redlock był bardziej niezawodny, należy wdrożyć 5 węzłów.
- Następnie musisz zażądać 5 węzłów, aby uzyskać blokadę, a metodą Future możesz najpierw zażądać do 5 węzłów jednocześnie, a potem uzyskać wynik odpowiedzi, co może skrócić czas odpowiedzi, ale nadal zajmuje więcej czasu niż blokada na pojedynczy węzeł Redis.
- Ponieważ trzeba uzyskać więcej niż 3 z 5 węzłów, może wystąpić konflikt blokad, czyli wszyscy zdobyli 1-2 blokady, a w rezultacie nikt nie może go zdobyć – w tym problemie autor Redis czerpie istotę algorytmu raft, poprzez kolizję w losowym czasie, czas konfliktu można znacznie skrócić, ale nie da się tego skutecznie uniknąć, zwłaszcza gdy blokada zostanie zdobyta po raz pierwszy, więc koszt czasu jej zdobycia rośnie.
- Jeśli 2 z 5 węzłów są nieaktywne, dostępność blokady znacznie się zmniejszy, po pierwsze, trzeba poczekać na wynik tych dwóch zablokowanych węzłów, zanim wrócisz, a są tylko 3 węzły, a klient musi zdobyć blokady wszystkich 3 węzłów, aby mieć blokadę, co również jest trudniejsze.
- Jeśli istnieje partycja sieciowa, może się zdarzyć, że klient nigdy nie będzie w stanie uzyskać blokady.
Po analizie wielu powodów uważam, że najważniejszym punktem problemu Redlocka jest to, że Redlock wymaga od klientów zapewnienia spójności zapisów, a 5 węzłów backendowych jest całkowicie niezależnych i wszyscy klienci muszą obsługiwać te 5 węzłów. Jeśli lider znajduje się wśród 5 węzłów, klient może synchronizować dane lidera, pod warunkiem uzyskania blokady od lidera, aby nie pojawiły się problemy takie jak partycjonowanie, limity czasu i konflikty. Dlatego, aby zapewnić poprawność rozproszonych blokad, uważam, że użycie rozproszonej usługi koordynacyjnej o silnej spójności może lepiej rozwiązać ten problem.
Znów pojawia się pytanie, jak długo powinienem ustawić czas ważności? Ustawienie czasu unieważnienia jest zbyt krótkie, a blokada jest automatycznie zwalniana przed wykonaniem metody, wtedy pojawiają się problemy z współbieżnością. Jeśli zajmie to zbyt dużo czasu, inne wątki, które dostaną blokadę, mogą musieli długo czekać.
Ten problem występuje również przy użyciu baz danych do implementacji rozproszonych blokad.
Obecne powszechne podejście do tego problemu polega na ustawieniu krótkiego czasu limitu dla każdej uzyskanej blokady i uruchamianiu wątku odświeżającego czas blokady za każdym razem, gdy zbliża się do tego limitu. Zakończ ten wątek w tym samym momencie, gdy zwalniasz zamek. Na przykład redisson, oficjalny komponent rozproszonego zamka redis, korzysta z tego rozwiązania.
Zalety wykorzystania buforowania do implementacji rozproszonych blokad Dobra wydajność.
Wady wykorzystania buforowania do implementacji rozproszonych blokad Wdrożenie jest zbyt odpowiedzialne, jest zbyt wiele czynników do rozważenia.
Rozproszone blokady oparte na implementacji Zookeepera
Rozproszone blokady oparte na tymczasowo uporządkowanych węzłach Zookeepera.
Ogólna idea jest taka, że gdy każdy klient blokuje metodę, w katalogu określonego węzła odpowiadającego metodzie na zookeeperze generowany jest unikalny, natychmiastowy uporządkowany węzeł. Sposób na określenie, czy zdobyć zamek, jest prosty – wystarczy wybrać ten z najmniejszym numerem seryjnym w uporządkowanym węźle. Po zwolnieniu blokady wystarczy usunąć węzeł natychmiastowy. Jednocześnie pozwala uniknąć problemu zacięć spowodowanych przestojami w serwisie, których nie można rozwiązać.
Zobaczmy, czy Zookeeper rozwiąże wspomniane wcześniej problemy.
- Zamek się nie otwiera? Korzystanie z Zookeepera może skutecznie rozwiązać problem nieodblokowywania blokad, ponieważ podczas tworzenia zamka klient tworzy tymczasowy węzeł w ZK, a gdy klient uzyska blokadę i nagle ją zawiesi (połączenie sesji zostaje przerwane), tymczasowy węzeł zostanie automatycznie usunięty. Inni klienci mogą ponownie zdobyć zamek.
- Zamki nieblokujące? Po zmianie węzła Zookeeper powiadomi klienta, a klient może sprawdzić, czy utworzony przez niego węzeł jest najmniejszą liczbą porządkową spośród wszystkich węzłów.
- Nie można wejść ponownie? Gdy klient tworzy węzeł, bezpośrednio zapisuje informacje o hostze i wątkach aktualnego klienta do węzła, a następnym razem, gdy chcesz uzyskać blokadę, możesz porównać je z danymi w obecnie najmniejszym węźle. Jeśli informacje są takie same jak twoje, możesz bezpośrednio uzyskać blokadę, a jeśli jest inna, utworzyć tymczasowy węzeł sekwencyjny, aby uczestniczyć w kolejce.
Pytanie pojawia się ponownie, wiemy, że Zookeeper musi być wdrażany w klastrach, czy będą problemy z synchronizacją danych jak w klastrzach Redis?
Zookeeper to rozproszony komponent, który gwarantuje słabą spójność, czyli ostateczną spójność.
Zookeeper stosuje protokół synchronizacji danych zwany Quorum Based Protocol. Jeśli w klastrze Zookeeper znajduje się N serwerów Zookeeper (N jest zwykle nieparzyste, 3 spełniają niezawodność danych i mają wysoką wydajność odczytu i zapisu, a 5 najlepiej równoważy niezawodność danych z wydajnością odczytu i zapisu), to najpierw synchronizuje się operację zapisu użytkownika z serwerami N/2 + 1, a następnie zwraca się użytkownikowi, co zachęca użytkownika do pomyślnego zapisu. Protokół synchronizacji danych oparty na Quorum Based Protocol określa spójność siły, jaką Zookeeper może obsłużyć.
W środowisku rozproszonym przechowywanie danych o wysokiej spójności praktycznie nie istnieje i wymaga, aby wszystkie węzły były aktualizowane synchronicznie podczas aktualizacji danych jednego węzła. Ta strategia synchronizacji występuje w bazie danych replikacji synchronicznej master-slave. Jednak ta strategia synchronizacji ma zbyt duży wpływ na wydajność zapisu i rzadko spotyka się ją w praktyce. Ponieważ Zookeeper zapisuje N/2+1 węzłów synchronicznie, a N/2 węzłów nie są aktualizowane synchronicznie, Zookeeper nie jest bardzo spójny.
Operacja aktualizacji danych użytkownika nie gwarantuje, że kolejne odczyty odczytają zaktualizowaną wartość, ale ostatecznie wykazują spójność. Poświęcenie spójności nie oznacza całkowitego ignorowania spójności danych, bo inaczej dane są chaotyczne, więc bez względu na to, jak wysoka jest dostępność systemu czy jak dobry jest rozkład, nie mają one żadnej wartości. Poświęcenie spójności to po prostu to, że silna spójność w relacyjnych bazach danych nie jest już wymagana, ale pod warunkiem, że system jest w stanie osiągnąć ostateczną spójność.
Pytanie jednopunktowe? Użycie Zookeepera pozwala skutecznie rozwiązać problem pojedynczego punktu, ZK jest wdrażany w klastrach, a jeśli ponad połowa maszyn w klastrze przetrwa, usługa może być udostępniana światu zewnętrznemu.
Problemy ze sprawiedliwością? Użycie Zookeepera może rozwiązać problem uczciwych zamków, tymczasowe węzły utworzone przez klienta w ZK są uporządkowane, a za każdym razem, gdy blokada zostaje zwolniona, ZK może powiadomić najmniejszy węzeł o uzyskaniu blokady, zapewniając uczciwość.
Pytanie pojawia się ponownie, wiemy, że Zookeeper musi być wdrażany w klastrach, czy będą problemy z synchronizacją danych jak w klastrzach Redis?
Zookeeper to rozproszony komponent, który gwarantuje słabą spójność, czyli ostateczną spójność.
Zookeeper stosuje protokół synchronizacji danych zwany Quorum Based Protocol. Jeśli w klastrze Zookeeper znajduje się N serwerów Zookeeper (N jest zwykle nieparzyste, 3 spełniają niezawodność danych i mają wysoką wydajność odczytu i zapisu, a 5 najlepiej równoważy niezawodność danych z wydajnością odczytu i zapisu), to najpierw synchronizuje się operację zapisu użytkownika z serwerami N/2 + 1, a następnie zwraca się użytkownikowi, co zachęca użytkownika do pomyślnego zapisu. Protokół synchronizacji danych oparty na Quorum Based Protocol określa spójność siły, jaką Zookeeper może obsłużyć.
W środowisku rozproszonym przechowywanie danych o wysokiej spójności praktycznie nie istnieje i wymaga, aby wszystkie węzły były aktualizowane synchronicznie podczas aktualizacji danych jednego węzła. Ta strategia synchronizacji występuje w bazie danych replikacji synchronicznej master-slave. Jednak ta strategia synchronizacji ma zbyt duży wpływ na wydajność zapisu i rzadko spotyka się ją w praktyce. Ponieważ Zookeeper zapisuje N/2+1 węzłów synchronicznie, a N/2 węzłów nie są aktualizowane synchronicznie, Zookeeper nie jest bardzo spójny.
Operacja aktualizacji danych użytkownika nie gwarantuje, że kolejne odczyty odczytają zaktualizowaną wartość, ale ostatecznie wykazują spójność. Poświęcenie spójności nie oznacza całkowitego ignorowania spójności danych, bo inaczej dane są chaotyczne, więc bez względu na to, jak wysoka jest dostępność systemu czy jak dobry jest rozkład, nie mają one żadnej wartości. Poświęcenie spójności to po prostu to, że silna spójność w relacyjnych bazach danych nie jest już wymagana, ale pod warunkiem, że system jest w stanie osiągnąć ostateczną spójność.
To, czy Zookeeper spełnia spójność przyczynową, zależy od tego, jak klient jest zaprogramowany.
Praktyki, które nie spełniają spójności przyczynowej
- Proces A zapisuje fragment danych do /z Zookeepera i zwraca pomyślnie
- Proces A informuje proces B, że A zmodyfikował dane z /z
- B odczytuje dane z /z Zookeepera
- Ponieważ serwer Opiekuna Zookeepera połączony z B mógł nie zostać zaktualizowany o zapisane dane A, B nie będzie mógł odczytać zapisanych danych A
Praktyki spełniające spójność przyczynową
- Proces B nasłuchuje zmian danych w /z w Zookeeperze
- Proces A zapisuje fragment danych do /z Zookeepera, a zanim zostanie pomyślnie powrócony, Zookeeper musi zadzwonić do słuchacza zarejestrowanego na /z, a lider powiadomi B o zmianie danych
- Po odpowiedzi na reakcję na zdarzenie procesu B, przyjmuje on zmienione dane, więc B na pewno uzyska zmienioną wartość
- Spójność przyczynowa odnosi się tutaj do spójności przyczynowej między liderem a B, czyli liderem informuje dane o zmianie
Drugi mechanizm odsłuchu zdarzeń to także metoda, którą należy użyć do właściwego programowania Zookeepera, więc Zookeeper powinien spełniać tę przyczynową spójność
Dlatego implementując rozproszone blokady oparte na Zookeeperze, powinniśmy stosować praktykę spełniania spójności przyczynowej, czyli wątki czekające na blokadę słuchają zmian w blokadzie Zookeepera, a gdy blokada zostanie zwolniona, Zookeeper powiadomi oczekujący wątek, który spełnia warunki fair lock.
Możesz bezpośrednio korzystać z klienta biblioteki zewnętrznej Zookeeper, który enkapsuluje usługę blokady reentrant.
Rozproszone blokady zaimplementowane za pomocą ZK wydają się dokładnie odpowiadać temu, czego oczekiwaliśmy od rozproszonego zamka na początku tego artykułu. Jednak tak nie jest, a rozproszony zamek zaimplementowany przez Zookeeper ma w rzeczywistości wadę, czyli wydajność może nie być tak wysoka jak w usłudze buforowania. Ponieważ za każdym razem, gdy tworzymy i zwalniamy blokadę, natychmiastowe węzły muszą być dynamicznie tworzone i niszczone, aby zrealizować funkcję blokady. Tworzenie i usuwanie węzłów w ZK może być wykonywane wyłącznie przez serwer lidera, a następnie dane są udostępniane wszystkim maszynom towarzyszącym.
Zalety wykorzystania Zookeepera do implementacji rozproszonych zamków Skutecznie rozwiązuj problemy z pojedynczym punktem, problemy nie-powrotne, nieblokujące oraz nieuwalnianie blokady. Wdrożenie jest stosunkowo proste.
Wady wykorzystania Zookeepera do implementacji rozproszonych blokad Wydajność nie jest tak dobra jak w przypadku używania pamięci podręcznej do implementacji rozproszonych blokad. Wymagana jest znajomość zasad ZK.
Porównanie trzech opcji
Z perspektywy łatwości zrozumienia (od niskiego do wysokiego) Baza danych > pamięci podręcznej > Zookeeper
Z perspektywy złożoności implementacji (od niskiej do najwyższej) Zookeeper > cache > bazy danych
Z perspektywy wydajności (od wysokiego do niskiego) Cache > Zookeeper >= baza danych
Z perspektywy niezawodności (od wysokiego do niskiego) Zookeeper > cache > bazy danych
|