
Réplica de múltiples escritores ha sido un desafío en el ecosistema MySQL durante años antes de la introducción de soluciones verdaderamente dedicadas: primero la replicación Galera (y, por lo tanto, Percona XtradDB Cluster (PXC)) (alrededor de 2011) y luego la replicación grupal (primera AG en 2016).
Ahora, con las dos tecnologías de secuencias de comandos múltiples disponibles, ¿seguimos necesitando la replicación asíncrona tradicional, instalada en una topología de activo a activo? Aparentemente sí, todavía hay casos de uso válidos. Y es posible que lo necesite no solo cuando, por alguna razón, Galera / PXC o GR no sean adecuados, sino también cuando realmente lo use. Por supuesto, el caso más típico es tener un segundo clúster en una ubicación geográfica diferente, como Disaster Rrecuperación. Si también se pregunta por qué lo necesita, solo lea cómo un centro de datos completo podría desaparecer en las noticias hace unas semanas. sobre el incidente de OVH.
Por lo tanto, un sitio DR debe replicarse en línea desde el clúster principal y poder recuperar la carga de trabajo muy rápidamente si es necesario. Pero también se espera que pueda cambiar sin esfuerzo, por lo que muy a menudo se instalan canales de replicación asíncronos en ambas direcciones.
Puede encontrar un muy buen artículo sobre esto aquí: Cómo no hacer que MySQL tenga alta disponibilidad: distribución de nodos geográficos con replicación basada en galería.
Ahora, después de ver repetidos problemas con configuraciones activo-activo cayendo una y otra vez durante años, pensé que todavía había muy pocas advertencias aquí sobre los riesgos, así que decidí agregar una piedra más a la pila.
Antes de continuar, permítanme mencionar este gran seminario web realizado el año pasado por mi colega Sveta. Definitivamente debería investigarlo si está interesado en el tema: ¿Qué tan segura es la configuración Asynchronous Master-Master en MySQL?
Regístrate en Percona Live ONLINE
Un evento virtual sobre bases de datos Open Source
Prueba de falla
Entonces, permítanme demostrar un caso de prueba simple, que puede ser interesante para algunos.
Primero, usamos el grande. dbdeployer herramienta para lanzar dos instancias de MySQL con replicación activo-activo en un solo comando:
$ dbdeployer deployment replication –topology = all-masters –nodes = 2 –concurrent 8.0.23 directorio all-masters instalado en $ HOME / sandboxes / all_masters_msb_8_0_23 ejecute ‘dbdeployer multiple use’ para obtener instrucciones básicas’ $ HOME / sandboxes / all_masters_0_m2 / initialize_ms_nodes # servidor: 1 # servidor: 2
PS dbdeployer implementar replicación –topología=todos–maestros –nodos=2 –competidores 8.0.23 todos–maestros directorio instalado en PSCASA/cajas de arena/todos_maestros_msb_8_0_23 correr «uso múltiple de dbdeployer» en orden bases instrucciones‘ PSCASA/cajas de arena/todos_maestros_msb_8_0_23/initialize_ms_nodes #servidor 1 #servidor: 2 |
Ahora, cree una tabla muy simple con una fila de datos de muestra:
nodo1 (prueba)> crear tabla t1 (id int clave principal auto_incremento, int); Consulta OK, 0 fila cortada (0.04 seg) nodo1 (prueba)> insertar en t1 establecer a = 500; Consulta OK, 1 fila cortada (0.01 seg)
nodo 1 (prueba) > crear mesa t1 (identificación En t Clave primaria auto_incremento, a En t); Pregunta está bien, 0 póngase en fila afectado (0.04 segundo) nodo 1 (prueba) > insertar en t1 colocar a=500; Pregunta está bien, 1 póngase en fila afectado (0.01 segundo) |
Entonces, en este punto, los dos nodos tienen los mismos datos:
nodo1 (prueba)> seleccione * de prueba.t1; + —- + —— + | identificación | un | + —- + —— + | 1 | 500 | + —- + —— + 1 fila en conjunto (0.00 seg) nodo2 (prueba)> seleccionar * de prueba.t1; + —- + —— + | identificación | un | + —- + —— + | 1 | 500 | + —- + —— + 1 fila en conjunto (0.00 seg)
nodo 1 (prueba) > Seleccione * sí prova.t1; + —- + —— + | identificación | a | + —- + —— + | 1 | 500 | + —- + —— + 1 póngase en fila en colocar (0.00 segundo) nodo 2 (prueba) > Seleccione * sí prova.t1; + —- + —— + | identificación | a | + —- + —— + | 1 | 500 | + —- + —— + 1 póngase en fila en colocar (0.00 segundo) |
En el siguiente paso, simulamos un ligero retraso en la replicación introduciendo un retraso de un segundo, para que podamos reproducir el problema a voluntad:
nodo1 (prueba)> detener réplica sql_thread; CAMBIAR FUENTE DE REPLICACIÓN A SOURCE_DELAY = 1 POR CANAL «nodo2»; iniciar la replicación de sql_thread; Consulta OK, 0 filas cortadas (0.01 seg) Consulta OK, 0 filas cortadas (0.00 seg) Consulta OK, 0 filas cortadas (0.00 seg) nodo2 (prueba)> detener réplica sql_thread; CAMBIAR FUENTE DE REPLICACIÓN A SOURCE_DELAY = 1 POR CANAL «nodo1»; iniciar la replicación de sql_thread; Consulta OK, 0 filas divididas (0,01 s) Consulta OK, 0 filas divididas (0,00 s) Consulta OK, 0 filas divididas (0,00 s)
nodo 1 (prueba) > firma réplica hilo_sql; CAMBIO REPLICACIÓN FUENTE A FUENTE_DELAY=1 EN ORDEN CANAL «nodo2»; comienza réplica hilo_sql; Pregunta está bien, 0 póngase en fila afectado (0.01 segundo) Pregunta está bien, 0 póngase en fila afectado (0.00 segundo) Pregunta está bien, 0 póngase en fila afectado (0.00 segundo) nodo 2 (prueba) > firma réplica hilo_sql; CAMBIO REPLICACIÓN FUENTE A FUENTE_DELAY=1 EN ORDEN CANAL «nodo 1»; comienza réplica hilo_sql; Pregunta está bien, 0 póngase en fila afectado (0.01 segundo) Pregunta está bien, 0 póngase en fila afectado (0.00 segundo) Pregunta está bien, 0 póngase en fila afectado (0.00 segundo) |
Bien, cuando enviamos una actualización, muy cerca en el tiempo, a ambos nodos, donde la misma fila recibe un valor diferente:
$ all_masters_msb_8_0_23 / use_all -e «update test.t1 set a = @@ server_id where id = 1» # servidor: 1 # servidor: 2
PS todos_maestros_msb_8_0_23/use_all –mi «actualizar conjunto test.t1 [email protected]@server_id donde id = 1 «
#servidor 1 #servidor: 2 |
Como resultado, ¡los dos nodos tienen valores de columna diferentes!
nodo1 (prueba)> seleccione * de prueba.t1; + —- + —— + | identificación | un | + —- + —— + | 1 | 200 | + —- + —— + 1 fila en conjunto (0.00 seg) nodo2 (prueba)> seleccionar * de prueba.t1; + —- + —— + | identificación | un | + —- + —— + | 1 | 100 | + —- + —— + 1 fila en conjunto (0.00 seg)
nodo 1 (prueba) > Seleccione * sí prova.t1; + —- + —— + | identificación | a | + —- + —— + | 1 | 200 | + —- + —— + 1 póngase en fila en colocar (0.00 segundo) nodo 2 (prueba) > Seleccione * sí prova.t1; + —- + —— + | identificación | a | + —- + —— + | 1 | 100 | + —- + —— + 1 póngase en fila en colocar (0.00 segundo) |
¿Está rota la replicación?
¿Crees que la replicación ahora está rota y que algunos errores te alertarán sobre la situación? ¡Para nada!
nodo1 (prueba)> mostrar estado de replicación G ***************************** 1. fila ******** ** ***************** … Replica_IO_Running: Sí Replica_SQL_Running: Sí … Seconds_Behind_Source: 0 Source_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 LastS … Ejecutado 00023824-1111-1111-1111-111111111111: 1-3, 00023825-2222-2222-2222-222222222222: 1 … nodo2 (prueba)> mostrar estado de replicación G ****** ****** *************** 1. fila ************************ * … Replica_IO_Running: Sí Replica_sql_Running: Sí… second_Behind_source: 0 Source_Slw_cert: 00011111111: 1-32382511222382511222228-2222- 222222222222: 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 dieciséis 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
nodo 1 (prueba) > espectáculos réplica estadoG *************************** 1. póngase en fila *************************** … Replication_IO_Running: sí SQL_Ejecución de replicación: sí … Seconds_Behind_Source: 0 Source_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Último_IO_Error: Last_SQL_Errno: 0 Último_SQL_Error: … Conjunto_Gtid_ejecutado: 00023824–1111–1111–1111–111111111111: 1–3, 00023825–2222–2222–2222–222222222222: 1 … nodo 2 (prueba) > espectáculos réplica estadoG *************************** 1. póngase en fila *************************** … Replication_IO_Running: sí SQL_Ejecución de replicación: sí … Seconds_Behind_Source: 0 Source_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Último_IO_Error: Last_SQL_Errno: 0 Último_SQL_Error: … Conjunto_Gtid_ejecutado: 00023824–1111–1111–1111–111111111111: 1–3, 00023825–2222–2222–2222–222222222222: 1 |
¿O espera que la activación de la función GTID evite que ocurran inconsistencias? Bueno, nos vemos Executed_Gtid_Set en ambos nodos: es lo mismo, pero los nodos tienen datos diferentes.
¿Qué pasa después? Bueno, depende, tal vez la replicación falle algún día con un error si la misma fila se modifica nuevamente, ¡pero también es posible que la inconsistencia se extienda aún más sin que te des cuenta!
¿Lección aprendida?
Espero que este simple ejemplo haya enfatizado la necesidad de un cuidado extra cuando se trata de topologías de replicación primaria múltiple. Pero el remedio suele ser bastante simple:
1 – Asegúrese de permitir que solo un nodo escriba a la vez (super_read_only está aquí para ayudar).
2 – Verifique la consistencia de los datos regularmente con las herramientas apropiadas (antes de replicar MySQL con pt-table-checksum y pt-table-sync).
Percona Distribution for MySQL es la solución MySQL de código abierto más completa, estable, escalable y segura disponible, que proporciona entornos de base de datos de nivel empresarial para sus aplicaciones comerciales más críticas… ¡y es de uso gratuito!
Descarga Percona Distribution para MySQL hoy