Jak określić master w mysql master-slave

17

Konfiguruję replikację MySQL Master-slave i próbuję wymyślić, jak poradzić sobie z sytuacją przełączania awaryjnego, w której promuję slave do master (w przypadku awarii master).

Mój serwer aplikacji musi przekierowywać wszystkie zapisy do bieżącego wzorca, ale nie mogę używać HA na poziomie serwera między wzorcem a urządzeniem podrzędnym (bicie serca, utrzymywanie aktywności), ponieważ dwa serwery db znajdują się w całkowicie różnych podsieciach w różnych lokalizacjach fizycznych.

Myślę, że jest to coś, z czym muszę sobie poradzić na poziomie aplikacji. Mogę przesłać zapytanie do dwóch serwerów i zapytać, który jest serwerem głównym, a następnie wykonać wszystkie zapytania do tego.

Czy w MySQL jest zapytanie, czy bieżący serwer jest serwerem głównym w replice master-slave?

Ethan Hayon
źródło
Jakiej wersji MySQL używasz?
RolandoMySQLDBA
To jest wynik mysqlServer version: 5.5.23 MySQL Community Server (GPL)
Ethan Hayon

Odpowiedzi:

13

@RolandoMySQLDBA dokładnie odpowiedział na pytanie ... ale zwrócił również uwagę, że jego rozwiązanie było „szybkie i brudne”.

I to jest bardzo prawdziwe stwierdzenie. :)

To, co mnie tu dotyczy, nie dotyczy tej odpowiedzi, ale raczej to, że pierwotne pytanie wydaje się przyjmować błędne założenie:

Mogę przesłać zapytanie do dwóch serwerów i zapytać, który jest serwerem głównym, a następnie wykonać wszystkie zapytania do tego.

Problem polega na tym, że w replikacji MySQL master nigdy nie jest tak naprawdę świadomy, że jest masterem.

Pojęcie „awans do opanowania” nie jest tak naprawdę pojęciem w asynchronicznej replikacji MySQL. „Promowanie” serwera MySQL do roli głównej jest czymś, co dzieje się „na zewnątrz” serwerów „MySQL”, a nie „czymś, co dzieje się” na „serwerach MySQL”.

„Awans do opanowania” nie jest wykonywany przez jakiekolwiek udostępnianie serwerów, ponieważ technicznie rzecz biorąc, każdy serwer MySQL, który ma włączone rejestrowanie binarne, jest master, nawet jeśli nigdy nie ma slave. SHOW MASTER STATUSdziała dokładnie w ten sam sposób i zwraca dokładnie ten sam wynik, slave lub nie, a master z 2 slave nie jest mniej więcej mistrzem niż master z 1 slave lub 0 slave. Podobnie mistrz, którego niewolnicy są w trybie offline, jest nadal tak samo mistrzem, ponieważ kiedy niewolnicy wrócą do sieci, zaczną replikować tam, gdzie przerwali.

W pewnym sensie jedyną „świadomością” ze strony dowolnego serwera nie jest to, czy jest to master, ale raczej, czy jest to slave (czy „nie”).

Tak pyta rozwiązanie Rolando: „jesteś niewolnikiem?” Jeśli odpowiedź brzmi „nie”, wówczas zakłada się, że musi to być mistrz… co również wskazał jako błędne założenie, jeśli STOP SLAVE;zostało wydane. Ale zatrzymany niewolnik wciąż jest niewolnikiem, więc „nie jest niewolnikiem” (w żadnym momencie) nie oznacza „być panem”.

Podobny test można wykonać na domniemanym mistrzu:

SELECT COUNT(1) FROM information_schema.processlist
 WHERE user = 'the_username_used_by_the_slave';

lub

SELECT COUNT(1) FROM information_schema.processlist
 WHERE command = 'binlog dump';

Jeśli wartość wynosi zero, to wątek IO urządzenia podrzędnego nie jest podłączony. Ten test ma podobną wadę, ponieważ jeśli slave zostanie odłączony administracyjnie, odizolowany lub nie powiedzie się, to nie zostanie podłączony. Więc to tak naprawdę niczego nie rozwiązuje.

Co gorsza (dla jednego z tych scenariuszy) „table” information_schema.processlist to wirtualna tabela, która pojawia się za każdym razem, gdy jest wybierana, a to wymaga czasu i zasobów. Im bardziej zajęty jest Twój serwer, tym więcej kosztuje, ponieważ aktywność każdego wątku musi zostać wczytana.

Bardziej lekkim rozwiązaniem byłoby:

SELECT @@global.read_only;

Na urządzeniu podrzędnym można / należy ustawić zmienną globalną read_only, aby użytkownicy bez SUPERuprawnień nie mogli przypadkowo do niej zapisać (a aplikacja nie powinna SUPER). Jeśli ręcznie „awansujesz” niewolnika do roli głównej, możesz SET GLOBAL read_only = OFFwłączyć zapisy. (Replikacja może zawsze zapisywać do urządzenia podrzędnego, bez względu na to, jak to jest ustawione).

Ale myślę, że nadal brakuje ważnej kwestii:

Proponuję, aby aplikacja nie podejmowała tej decyzji heurystycznie w konfiguracji master / slave, a na pewno nie na zasadzie połączenia przez połączenie. Aplikacja powinna użyć albo twardej opcji konfiguracji, albo aplikacja powinna pozostać nieświadoma i mieć miejsce docelowe połączenia z bazą danych obsługiwane przez coś innego.

Lub przynajmniej aplikacja nigdy nie powinna się przełączać, dopóki master nie ulegnie awarii, a następnie nigdy nie powinna sama się przełączać.

Oto, dlaczego mówię: po podjęciu „decyzji” przez kogokolwiek lub cokolwiek innego, aby uczynić z innego serwera wzorzec, aplikacja nie może zostać z jakiegokolwiek powodu przełączona z powrotem na pierwotny wzorzec, nawet po powrocie online , bez interwencji.

Powiedzmy, że trafiłeś w błąd i nastąpiła awaria oprogramowania; mysqld_safesumiennie uruchamia się ponownie mysqld, a odzyskiwanie po awarii programu InnoDB działa bezbłędnie. Ale to zajmuje kilka minut.

W międzyczasie master nie działa, więc twoja aplikacja przełączyła się na slave. Transakcje zostały utworzone, złożone zamówienia, przekazane środki, opublikowane komentarze, edytowane blogi, bez względu na to, co robi Twój system.

Teraz oryginalny mistrz powraca online.

Jeśli twoja aplikacja powróci do pierwotnego wzorca, znajdujesz się w absolutnym świecie krzywdy, ponieważ następną rzeczą, która może się zdarzyć, jest zatrzymanie replikacji z powodu niespójności, ponieważ aplikacja zmieniła dane na urządzeniu podrzędnym czas. Masz teraz dwa serwery bazy danych z niespójnymi danymi, które trzeba będzie ręcznie uzgodnić. Jeśli w grę wchodzą dolary, punkty lub kredyty, masz niedopasowane salda.

Dlatego bardzo ważne jest, aby aplikacja nie mogła wrócić do pierwotnego wzorca bez interwencji użytkownika.

Zaraz, czy właśnie znalazłeś problem z tym scenariuszem, tak jak to opisałem? Master zawiódł, ale twoja aplikacja nie będzie korzystała z slave, ponieważ uważa, że ​​slave jest nadal slave, a nie master ... information_schema.processlistzapytanie na slave nadal zwróci wartość niezerową, nawet jeśli serwer master zostanie wyłączony .

Aplikacja nie ma więc sensu niczego odkrywać, ponieważ trzeba będzie ręcznie, STOP SLAVEaby ten test był przydatny.

Być może lepszym rozwiązaniem, jeśli chcesz, aby aplikacja mogła się przełączyć, byłoby skonfigurowanie serwerów z cykliczną replikacją.

Replikacja cykliczna ma swoje własne problemy, ale dopóki twoja aplikacja zawsze pisze tylko na jednym serwerze naraz, większość z tych problemów staje się bezproblemowa. Innymi słowy, obie maszyny są zawsze i jednocześnie zarówno master, jak i slave, w sensie replikacji, ale twoja aplikacja, poprzez jakiś mechanizm, zawsze wskazuje tylko jedną maszynę na raz jako „master”, do którego może i powinna pisać .

Nie możesz wdrożyć narzędzi HA na serwerach MySQL ze względu na ich separację, ale możesz zaimplementować je z HAProxy działającym na serwerach aplikacji. Aplikacja łączy się z „MySQL” na localhost, który wcale nie jest MySQL, ale tak naprawdę jest HAProxy ... i przekazuje połączenie TCP do odpowiedniej maszyny MySQL.

HAProxy może testować połączenia z serwerami MySQL i oferować ruch tylko do maszyny MySQL, która przyjmuje połączenia i umożliwia uwierzytelnianie.

Połączenie HAProxy działającego na serwerze aplikacji (jego zapotrzebowanie na zasoby nie będzie znaczne w porównaniu do wszystkiego, co musi zrobić serwer aplikacji - to po prostu wiązanie gniazd i ignorowanie ich ładunku) ... i cykliczna replikacja MySQL byłoby podejściem, które prawdopodobnie przyjąłbym w tym przypadku, w oparciu o to, co wiadomo z pytania.

Lub, dla ściśle ręcznej konfiguracji, skorzystaj z czegoś znacznie prostszego niż „wykrywanie”, takiego jak wpis w /etc/hostspliku serwera aplikacji z nazwą hosta, którego aplikacja używa do łączenia się z MySQL, którą możesz ręcznie zaktualizować - zakładając promocję slave na master ma być procesem ręcznym.

Lub coś bardziej złożonego, przy użyciu klastra Percona XtraDB. W tym celu chciałbyś jednak dodać trzeci serwer, ponieważ z 3 węzłami w PXC, jeśli 2 serwery mogą się widzieć, ale izolują się od 1 serwera (jeśli wszystkie trzy nadal działają), 2 serwery nadal działają radośnie, ale 1 serwer zwinięty w kłębek i odmawia zrobienia czegokolwiek, ponieważ zdaje sobie sprawę, że musi to być dziwny. Działa to, ponieważ 2 zdają sobie sprawę, że nadal stanowią większość węzłów, które były online przed podziałem sieci, a 1 zdaje sobie sprawę, że tak nie jest. Dzięki PXC tak naprawdę nie ma znaczenia, z którym serwerem łączy się Twoja aplikacja.

Mówię, że wszystko to znaczy „nie każ aplikacji sondować serwerów, aby zobaczyć, który z nich jest mistrzem”, ponieważ prędzej czy później cię ugryzie i skubie twoją wydajność aż do dnia, w którym gryzie.

Michael - sqlbot
źródło
Przede wszystkim dziękuję za dobrze napisaną odpowiedź. Myślę, że zaproponowałeś dobre rozwiązanie. W przeszłości myślałem o używaniu replikacji cyklicznej, ale czytałem złe rzeczy dotyczące jej niezawodności. Jednak wielu z tych problemów można zapobiec, modyfikując auto_increment_increment, auto_increment_offset itp. Używanie HAProxy lokalnie na serwerach aplikacji (tylko jako przełączenie awaryjne) działałoby dla nas dobrze, ponieważ nie musielibyśmy modyfikować naszej aplikacji, a tym samym abstrakować przełączanie awaryjne logika z dala od warstwy aplikacji. Przyjrzę się konfiguracji HAProxy, dzięki!
Ethan Hayon,
1
Miło, że mogłem pomóc. Wcześniejsze głosowanie byłoby mile widziane, jeśli jeszcze tego nie zrobiłeś. Replikacja cykliczna jest tak samo niezawodna jak master / slave (jest to ta sama technologia, tylko obie strony), o ile rozumiesz, jak to działa i używasz jej w rozsądny sposób. Tak długo, jak serwery są odpowiednio zsynchronizowane, a aplikacja pisze tylko na jednym serwerze naraz, nigdy nie miałem z tym problemu. Te auto_increment_*zmienne są jeszcze dobrze używać w tym scenariuszu, „na wszelki wypadek”. Pamiętaj też, aby użyć binlog_format= rowlub mixed- nie statement(nawet jeśli nie robisz okólnika).
Michael - sqlbot
Zmieniłem zaakceptowaną odpowiedź wyłącznie dlatego, że to szczegółowe wyjaśnienie pomogło mi przebudować system, aby był bardziej niezawodny. @ Odpowiedź RolandoMySQLDBA jest nadal poprawna i rozwiązuje problem, który początkowo opisałem. Dzięki!
Ethan Hayon,
10

Jeśli używasz tylko Master / Slave, oto coś szybkiego i brudnego:

SELECT COUNT(1) SlaveThreadCount
FROM information_schema.processlist
WHERE user='system user';

Co ci to mówi?

  • Jeśli SlaveThreadCount= 0, masz Mistrza
  • Jeśli SlaveThreadCount> 0, masz Slave

CAVEAT : Działa tak długo, jak długo nie uruchamiaszSTOP SLAVE;

Inną rzeczą do wypróbowania jest to: Jeśli wyłączysz rejestrowanie binarne w Slave i uruchomisz SHOW MASTER STATUS;, Master da ci bieżący log binarny. Niewolnik nic ci nie daje.

RolandoMySQLDBA
źródło
Świetnie, właśnie tego potrzebuję. Czy uważasz, że jest to niechlujne rozwiązanie problemu? Jedyny problem, jaki mogę sobie wyobrazić, to awans obu serwerów do opanowania, ale tak naprawdę nie powinno tak się stać.
Ethan Hayon
Jeśli potrzebujesz tej odpowiedzi, zaznacz odpowiedź zaakceptowaną, klikając znacznik wyboru na mojej odpowiedzi.
RolandoMySQLDBA
Nie mogę oznaczyć tego jako zaakceptowane przez kolejne 5 minut :)
Ethan Hayon
Nie ma problemu. Cieszyłem się, że mogłem pomóc !!!
RolandoMySQLDBA
0

wykonaj tę instrukcję z monitu
mysql mysql> pokaż status slave;

Na slave pokazuje wiele parametrów i ich wartości / status, a na master pokazuje pusty zestaw

akrai48
źródło