@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 STATUS
dział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 SUPER
uprawnień 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 = OFF
włą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_safe
sumiennie 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.processlist
zapytanie 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 SLAVE
aby 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/hosts
pliku 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.