@RolandoMySQLDBA ha risposto alla domanda in modo accurato ... ma ha anche sottolineato che la sua soluzione era "veloce e sporca".
E questa è un'affermazione molto vera. :)
La cosa che mi interessa qui non è con quella risposta, ma piuttosto è che la domanda originale sembra fare un'ipotesi errata:
Posso interrogare i due server e chiedere quale è un master, quindi eseguire tutte le query su quello.
Il problema è che nella replica di MySQL il master non è mai veramente consapevole di essere il master.
Il concetto di "promozione da padroneggiare" non è in realtà un concetto nella replica asincrona di MySQL. "Promuovere" un server MySQL per il ruolo principale è qualcosa che accade "esterno ai" server MySQL, al contrario di qualcosa che accade "interno" ai server MySQL.
La "promozione da master" non viene eseguita da alcun tipo di provisioning del server, poiché, tecnicamente parlando, ogni server MySQL con la registrazione binaria abilitata è un master, anche se non ha mai uno slave. SHOW MASTER STATUS
funziona esattamente allo stesso modo e restituisce esattamente lo stesso risultato, slave o no, e un master con 2 slave non è più o meno un master di un master con 1 slave o 0 slave. Allo stesso modo, un maestro i cui schiavi sono tutti offline è ancora altrettanto un maestro, perché quando gli schiavi tornano online, riprenderanno replicando da dove avevano interrotto.
In un certo senso, l'unica "consapevolezza" da parte di entrambi i server non è se si tratta di un master, ma piuttosto se si tratta di uno slave (o "non").
Ecco cosa chiede la soluzione di Rolando: "sei uno schiavo?" Se la risposta è no, allora il presupposto è che questo deve essere il padrone ... che ha anche indicato come presupposto imperfetto se STOP SLAVE;
viene rilasciato. Ma uno schiavo fermo è ancora uno schiavo, quindi "non uno schiavo" (in qualsiasi momento nel tempo) non equivale a "essere un maestro".
Un test simile potrebbe essere eseguito sul presunto master:
SELECT COUNT(1) FROM information_schema.processlist
WHERE user = 'the_username_used_by_the_slave';
o
SELECT COUNT(1) FROM information_schema.processlist
WHERE command = 'binlog dump';
Se il valore è zero, il thread IO dello slave non è collegato. Questo test ha un difetto simile, nel senso che se lo slave viene disconnesso amministrativamente, isolato o fallito, non verrà collegato. Quindi neanche questo risolve nulla.
Peggio ancora (per uno di questi scenari) la "tabella" information_schema.processlist è una tabella virtuale che si materializza ogni volta che viene selezionata, e ciò richiede tempo e risorse in termini di costi. Più occupato è il tuo server, più costa, perché l'attività di ogni thread deve essere scrupolosa.
Una soluzione più leggera sarebbe:
SELECT @@global.read_only;
Su uno slave, è possibile / impostare la variabile globale in read_only
modo che gli utenti senza il SUPER
privilegio non possano scriverlo involontariamente (e l'applicazione non dovrebbe avere SUPER
). Se "promuovi" manualmente lo slave nel ruolo principale, devi SET GLOBAL read_only = OFF
abilitare le scritture. (La replica può sempre scrivere allo slave, indipendentemente da come è impostata).
Ma questo, penso, manca ancora un punto importante:
Proporrei che l'applicazione non dovrebbe prendere questa decisione in modo euristico in una configurazione master / slave, e certamente non in base alla connessione. L'applicazione deve utilizzare un'opzione di configurazione effettiva oppure l'applicazione deve rimanere inconsapevole e la destinazione della connessione al database deve essere gestita da qualcos'altro.
O, come minimo, l'applicazione non dovrebbe mai cambiare fino a quando il master fallisce, e quindi non dovrebbe mai tornare indietro da solo.
Ecco perché dico che: una volta presa la "decisione" - da chiunque o qualunque cosa - di rendere un altro server il master, l'applicazione non può essere autorizzata per nessun motivo a tornare al master originale, anche dopo che torna in linea , senza intervento.
Diciamo che hai colpito un bug e c'è un crash forzato dal software; mysqld_safe
si riavvia doverosamente mysqld
e il ripristino da crash di InnoDB funziona in modo impeccabile. Ma ci vogliono alcuni minuti.
Nel frattempo, il master è inattivo, quindi l'applicazione è passata allo slave. Sono state create transazioni, ordini effettuati, fondi trasferiti, commenti pubblicati, blog modificati, qualunque cosa faccia il tuo sistema.
Ora, il master originale torna online.
Se l'applicazione ritorna al master originale, ci si trova in un mondo assoluto di sofferenza, perché la prossima cosa che probabilmente accadrà è che la replica si interrompe a causa di un'incoerenza, poiché l'applicazione ha modificato i dati sullo slave nel mezzo tempo. Ora hai due server di database con dati incoerenti che dovrai riconciliare manualmente. Se ci sono dollari o punti o crediti coinvolti, ora hai saldi non corrispondenti.
Quindi è fondamentale che l'applicazione non possa tornare al master originale senza il tuo intervento.
Aspetta, hai appena trovato il problema con questo scenario come l'ho descritto? Il master non è riuscito ma l'applicazione non utilizzerà lo slave, poiché pensa che lo slave sia ancora lo slave e non il master ... la information_schema.processlist
query sullo slave restituirà comunque un valore diverso da zero anche se il server master è spento .
Quindi non ha molto senso scoprire qualcosa nell'applicazione, dal momento che dovrai fare manualmente STOP SLAVE
quel test per essere utile.
Forse un approccio migliore se si desidera che l'applicazione sia in grado di cambiare sarebbe configurare i server con replica circolare.
La replica circolare presenta problemi intrinseci propri, ma fintanto che l'applicazione scrive sempre e solo su un server alla volta, la maggior parte di questi problemi diventa non-problemi. In altre parole, entrambe le macchine sono sempre e contemporaneamente sia master che slave, in senso di replica, ma la tua applicazione, tramite qualche meccanismo, punta sempre a una sola macchina alla volta come "master" su cui può e deve scrivere .
Non è possibile distribuire strumenti HA sui server MySQL a causa della loro separazione, ma è possibile implementarlo con HAProxy in esecuzione sui server delle applicazioni. L'applicazione si collega a "MySQL" su localhost, che non è affatto MySQL, ma in realtà è HAProxy ... e inoltra la connessione TCP alla macchina MySQL appropriata.
HAProxy può testare le connessioni ai server MySQL e offrire traffico solo a una macchina MySQL che accetta connessioni e consente l'autenticazione.
La combinazione di HAProxy in esecuzione sul server delle applicazioni (la sua richiesta di risorse non sarà sostanziale rispetto a tutto ciò che il server delle applicazioni deve fare - è praticamente solo unire i socket e ignorare il loro payload) ... e la replica circolare di MySQL sarebbe l'approccio che probabilmente prenderei in questo caso, basato su ciò che è noto dalla domanda.
Oppure, per una configurazione strettamente manuale, scegli qualcosa di molto più semplice di "scoperta", come una voce nel /etc/hosts
file del server delle app con un nome host che l'applicazione utilizza per connettersi a MySQL, che potresti aggiornare manualmente, supponendo la promozione di slave master è destinato ad essere un processo manuale.
Oppure, qualcosa di più complesso, usando Percona XtraDB Cluster. Per questo, però, vorresti aggiungere un terzo server, perché con 3 nodi in PXC, se 2 server possono vedersi ma isolati da 1 server (se tutti e tre sono ancora in esecuzione) i 2 server continuano a funzionare felicemente ma il server 1 si rannicchia in una pallina e si rifiuta di fare qualsiasi cosa poiché si rende conto che deve essere quello dispari. Questo funziona perché i 2 si rendono conto che costituiscono ancora la maggioranza dei nodi che erano online prima della divisione della rete e il 1 si rende conto che non lo è. Con PXC, non importa davvero a quale server si connette la tua applicazione.
Dico tutto questo per dire "non fare in modo che l'applicazione esegua il polling dei server per vedere quale sia il master" perché ti morderà prima o poi e sgranoccherà le tue prestazioni fino al giorno in cui morde.