Cómo determinar master en mysql master-slave

17

Estoy configurando la replicación maestro-esclavo MySQL y estoy tratando de descubrir cómo manejar la situación de conmutación por error en la que promuevo el esclavo a maestro (en caso de que el maestro se caiga).

Mi servidor de aplicaciones necesita dirigir todas las escrituras al maestro actual, pero no puedo usar el nivel de servidor HA entre el maestro y el esclavo (latido, keepalived) ya que los dos servidores db están en subredes completamente diferentes en diferentes ubicaciones físicas.

Creo que esto es algo que necesito manejar a nivel de aplicación. Puedo consultar los dos servidores y preguntar cuál es un maestro, luego realizar todas las consultas a ese.

¿Hay una consulta en MySQL para ver si el servidor actual es un maestro en una réplica maestro-esclavo?

Ethan Hayon
fuente
¿Qué versión de MySQL estás usando?
RolandoMySQLDBA
Esta es la salida de mysqlServer version: 5.5.23 MySQL Community Server (GPL)
Ethan Hayon

Respuestas:

13

@RolandoMySQLDBA ha respondido la pregunta con precisión ... pero también señaló que su solución fue "rápida y sucia".

Y esa es una afirmación muy verdadera. :)

Lo que me preocupa aquí no es con esa respuesta, sino que la pregunta original parece hacer una suposición incorrecta:

Puedo consultar los dos servidores y preguntar cuál es un maestro, luego realizar todas las consultas a ese.

El problema es que en la replicación MySQL, el maestro nunca es realmente consciente de que es el maestro.

El concepto de "promoción a maestro" no es realmente un concepto en la replicación asincrónica de MySQL. "Promover" un servidor MySQL a la función de maestro es algo que sucede "externo a" los servidores MySQL, en lugar de algo que sucede "interno" a los servidores MySQL.

La "promoción al maestro" no se realiza mediante ningún tipo de aprovisionamiento del servidor, porque, técnicamente hablando, cada servidor MySQL que tiene habilitado el registro binario es un maestro, incluso si nunca tiene un esclavo. SHOW MASTER STATUSfunciona exactamente de la misma manera y devuelve exactamente el mismo resultado, esclavos o no, y un maestro con 2 esclavos no es más o menos maestro que un maestro con 1 esclavo o 0 esclavos. Del mismo modo, un maestro cuyos esclavos están todos fuera de línea sigue siendo igual de maestro, porque cuando los esclavos vuelvan a conectarse, continuarán replicando donde lo dejaron.

En cierto sentido, la única "conciencia" por parte de cualquiera de los servidores no es si es un maestro, sino más bien si es un esclavo (o "no").

Eso es lo que pregunta la solución de Rolando: "¿eres un esclavo?" Si la respuesta es no, entonces la suposición es que este debe ser el maestro ... que también señaló como una suposición defectuosa si STOP SLAVE;se emite. Pero un esclavo detenido sigue siendo un esclavo, por lo que "no es un esclavo" (en ningún momento) no equivale a "ser un maestro".

Se podría hacer una prueba similar en el supuesto maestro:

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';

Si el valor es cero, entonces el hilo IO del esclavo no está conectado. Esta prueba tiene un defecto similar, ya que si el esclavo se desconecta administrativamente, se aísla o falla, no se conectará. Así que esto tampoco resuelve nada realmente.

Peor aún (para cualquiera de estos escenarios), la "tabla" de information_schema.processlist es una tabla virtual que se materializa cada vez que se selecciona, y esto toma tiempo y cuesta recursos. Cuanto más ocupado esté su servidor, más cuesta, porque la actividad de cada subproceso debe ser analizada.

Una solución más ligera sería:

SELECT @@global.read_only;

En un esclavo, podría / debería establecer la variable global read_onlypara que los usuarios sin el SUPERprivilegio no puedan escribirle involuntariamente (y su aplicación no debería tenerla SUPER). Si "promueve" manualmente al esclavo a la función de maestro, puede SET GLOBAL read_only = OFFhabilitar las escrituras. (La replicación siempre puede escribir en el esclavo, sin importar cómo se configure).

Pero esto todavía, creo, pierde un punto importante:

Yo propondría que la aplicación no tome esta decisión heurísticamente en una configuración maestro / esclavo, y ciertamente no en una conexión por conexión. La aplicación debe usar una opción de configuración rígida, o la aplicación debe permanecer inconsciente y tener el destino de conexión de la base de datos manejado por otra cosa.

O, como mínimo, la aplicación nunca debe cambiar hasta que el maestro falle, y luego nunca debe volver a cambiar por sí sola.

He aquí por qué digo eso: una vez que la "decisión" se toma, por quien sea o lo que sea, de convertir a otro servidor en el maestro, no se puede permitir que la aplicación cambie por ningún motivo al maestro original, incluso después de que vuelva a estar en línea , sin intervención.

Digamos que chocas con un error y hay un bloqueo forzado por el software; mysqld_safese reinicia debidamente mysqld, y la recuperación de fallos de InnoDB se realiza sin problemas. Pero eso lleva unos minutos.

Mientras tanto, el maestro está inactivo, por lo que su aplicación se ha cambiado al esclavo. Se han creado transacciones, se han realizado pedidos, se han transferido fondos, se han publicado comentarios, se han editado blogs, haga lo que haga su sistema.

Ahora, el maestro original vuelve a estar en línea.

Si su aplicación vuelve al maestro original, se encuentra en un mundo de dolor absoluto, porque lo siguiente que probablemente sucederá es que la replicación se detiene debido a una inconsistencia, porque su aplicación ha cambiado los datos en el esclavo en la media hora. Ahora tiene dos servidores de bases de datos con datos inconsistentes que tendrá que conciliar manualmente. Si hay dólares o puntos o créditos involucrados, ahora tiene saldos no coincidentes.

Por lo tanto, es fundamental que no se permita que la aplicación vuelva al maestro original sin su intervención.

Espera, ¿acabas de encontrar el problema con este escenario como lo describí? El maestro ha fallado, pero su aplicación no usará el esclavo, porque cree que el esclavo sigue siendo el esclavo y no el maestro ... la information_schema.processlistconsulta sobre el esclavo aún devolverá un valor distinto de cero, incluso si el servidor maestro está apagado .

Por lo tanto, no tiene mucho sentido que la aplicación descubra algo, ya que tendrá que hacerlo manualmente STOP SLAVEpara que esa prueba sea útil.

Quizás un mejor enfoque si desea que la aplicación pueda cambiar sería configurar los servidores con replicación circular.

La replicación circular tiene sus propios problemas inherentes, pero siempre que su aplicación siempre escriba en un servidor a la vez, la mayoría de esos problemas se convierten en problemas. En otras palabras, ambas máquinas son siempre y simultáneamente maestro y esclavo, en un sentido de replicación, pero su aplicación, a través de algún mecanismo, siempre apunta a una máquina a la vez como el "maestro" en el que puede y debe escribir .

No puede implementar herramientas HA en los servidores MySQL debido a su separación, pero puede implementarlo con HAProxy ejecutándose en los servidores de aplicaciones. La aplicación se conecta a "MySQL" en localhost, que no es MySQL en absoluto, pero en realidad es HAProxy ... y reenvía la conexión TCP a la máquina MySQL adecuada.

HAProxy puede probar las conexiones a los servidores MySQL y solo ofrece tráfico a una máquina MySQL que acepta conexiones y permite la autenticación.

La combinación de HAProxy que se ejecuta en el servidor de aplicaciones (su demanda de recursos no será sustancial en comparación con todo lo demás que el servidor de aplicaciones tiene que hacer; es más que solo unir sockets e ignorar su carga útil) ... y la replicación circular de MySQL sería el enfoque que probablemente tomaría en este caso, basado en lo que se sabe de la pregunta.

O, para una configuración estrictamente manual, vaya con algo mucho más simple que "descubrimiento", como una entrada en el /etc/hostsarchivo del servidor de aplicaciones con un nombre de host que la aplicación utiliza para conectarse a MySQL, que puede actualizar manualmente, suponiendo la promoción de esclavo a master está destinado a ser un proceso manual.

O, algo más complejo, utilizando Percona XtraDB Cluster. Sin embargo, para esto, desearía agregar un tercer servidor, porque con 3 nodos en PXC, si 2 servidores pueden verse pero se aíslan de 1 servidor (si los tres todavía se están ejecutando) los 2 servidores siguen funcionando felizmente, pero el servidor 1 se acurruca en una pequeña bola y se niega a hacer nada, ya que se da cuenta de que debe ser el extraño. Esto funciona porque los 2 se dan cuenta de que todavía constituyen la mayoría de los nodos que estaban en línea antes de la división de la red y el 1 se da cuenta de que no lo es. Con PXC, realmente no importa a qué servidor se conecta su aplicación.

Digo que todo esto es para decir "no haga que la aplicación sondee los servidores para ver cuál es el maestro" porque tarde o temprano lo morderá y afectará su rendimiento hasta el día en que muerde.

Michael - sqlbot
fuente
En primer lugar, gracias por la respuesta bien escrita. Creo que has propuesto una buena solución. He pensado en usar la replicación circular en el pasado, pero he leído cosas malas con respecto a su confiabilidad. Sin embargo, muchos de estos problemas pueden prevenirse modificando auto_increment_increment, auto_increment_offset, etc. El uso local de HAProxy en los servidores de aplicaciones (solo como failover) funcionaría bien para nosotros, ya que no tendríamos que modificar nuestra aplicación, por lo tanto, abstrayendo la failover lógica lejos de la capa de aplicación. Buscaré configurar HAProxy, ¡gracias!
Ethan Hayon
1
Encantado de ayudar. Un voto positivo sería apreciado si aún no lo ha hecho. La replicación circular es tan confiable como el maestro / esclavo (es la misma tecnología, solo va en ambas direcciones) siempre y cuando comprenda cómo funciona y lo use de manera sensata. Mientras los servidores estén sincronizados correctamente y la aplicación solo escriba en un servidor a la vez, nunca he tenido un problema con él. Las auto_increment_*variables siguen siendo buenas para usar en este escenario, "por si acaso". Además, recuerde usar binlog_format= rowo mixed- no statement(incluso si no está haciendo circular).
Michael - sqlbot
Cambié la respuesta aceptada simplemente porque esta explicación detallada me ayudó a rediseñar el sistema para que sea más robusto. La respuesta de @ RolandoMySQLDBA sigue siendo correcta y resuelve el problema que describí inicialmente. ¡Gracias!
Ethan Hayon
10

Si está utilizando solo Maestro / Esclavo, aquí hay algo rápido y sucio:

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

¿Qué te dice esto?

  • Si SlaveThreadCount= 0, tienes el maestro
  • Si SlaveThreadCount> 0, tienes el esclavo

PRUEBA : esto funciona mientras no se ejecuteSTOP SLAVE;

Otra cosa para intentar es esta: si deshabilita el registro binario en el esclavo y ejecuta SHOW MASTER STATUS;, el maestro le da el registro binario actual. El esclavo no te da nada.

RolandoMySQLDBA
fuente
Impresionante, esto es exactamente lo que necesito. ¿Crees que esta es una solución desordenada al problema? El único problema que puedo imaginar es que ambos servidores se promueven a maestro, pero eso nunca debería suceder.
Ethan Hayon
Si esta respuesta es lo que necesita, marque la respuesta aceptada haciendo clic en la marca de verificación en mi respuesta.
RolandoMySQLDBA
No puedo marcarlo como aceptado por otros 5 minutos :)
Ethan Hayon
No hay problema. ¡Me alegré de poder ayudar!
RolandoMySQLDBA
0

ejecute esta declaración desde mysql prompt
mysql> muestre el estado del esclavo;

En esclavo muestra muchos parámetros y sus valores / estado, mientras que en maestro muestra Conjunto vacío

akrai48
fuente