¿Alguna mejor manera de salir del registro de MySQL InnoDB "en el futuro"?

16

Tengo este error de InnoDB en MySQL 5.0. Mysqld se detuvo limpiamente, pero logré perder ib_logfile0 e ib_logfile1 después. Ahora, después de un inicio limpio, InnoDB ha realizado su "recuperación de bloqueo". Revisé el negocio innodb_force_recovery = 4, reparé una tabla MyISAM colgada y ahora la replicación está lista, aparte de esto. Grandes números comunicados:

111116 15:49:36  InnoDB: Error: page 393457 log sequence number 111 561,760,232
InnoDB: is in the future! Current system log sequence number 70 3,946,969,851.
InnoDB: Your database may be corrupt or you may have copied the InnoDB
InnoDB: tablespace but not the InnoDB log files. See
InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html
InnoDB: for more information.

Esto está en un servidor esclavo. El error anterior arroja por cientos. Encontré esta respuesta: "insertar y eliminar> 64 GB de datos, para que el número de secuencia de registro se infle lo suficientemente grande".

http://forums.mysql.com/read.php?22,50163,50163#msg-50163

Ese número mágico de 64 GB proviene de 4 GB * 16, donde el "número mayor" del registro innodb de ese tipo necesitaba aumentar de 0 a 15. El mío va de 70 a 111 = 164 GB. Esto llevará 5 días. Seguiré trabajando para acelerar mi script y ejecutarlo en paralelo para acelerar esto. Mientras tanto, espero que alguien más tenga una mejor respuesta. Esto es tonto.

IcarusNM
fuente
Una respuesta prometedora: "Si se trata de un servidor esclavo, la mejor solución sería apartar la base de datos e instalar una nueva instantánea del maestro". Desafortunadamente, hay 20,000 tablas en 25 bases de datos, una mezcla de MyISAM e InnoDB, en producción 24x7. Llevaría demasiado tiempo cerrar todo eso y realizar una nueva replicación completa antes de iniciar la replicación nuevamente.
IcarusNM
44
Ahora tengo esta máquina de 8 núcleos de rodillas en una carrera sin sentido para crear y eliminar 164 gigas de datos. La única alternativa que escucho es bombardear todo con este esclavo y comenzar de cero. Todo para cambiar efectivamente un número en dos archivos. Seguramente hay algún ingeniero de InnoDB por ahí con un consejo profesional. ¿Alguien alguna vez abrió ib_logfile0 en Emacs, encontró el número mágico en hexadecimal y lo cambió?
IcarusNM
Aquí hay un gran artículo sobre algunas formas de hacerlo. Percona es definitivamente la autoridad en MySQL. percona.com/blog/2013/09/11/…
jbrahy

Respuestas:

10

Esta era una situación bastante rara. Espero no volver a terminar allí nunca más, con un "número de secuencia de registro InnoDB en el futuro". error. Debido a mis detalles particulares, la reconstrucción / restauración de los datos de mi servidor fue el último recurso. Algunos trucos para ayudar fueron buenas ideas, pero al final, decidí seguir mejorando mi script de Perl para jugar este juego tonto y batir tantos conciertos / hora como pude. Qué diablos, es una buena prueba de estrés del sistema.

Recuerde: el objetivo es aumentar un único contador ("número de secuencia de registro") que se almacena en algún lugar de los encabezados de ib_logfile0 e ib_logfile1 . Esto es para fingir InnoDB para que ignore una distorsión temporal aparente y continúe con la vida. Pero nadie sabe cómo editar ese número. O si lo saben, nadie está hablando.

Aquí está mi producto final. YMMV, pero usar la función REPEAT de mysql para generar los datos internamente es altamente eficiente.

 #!/usr/bin/perl
 use DBI;
 $table = shift || die;
 $dbh = DBI->connect("DBI:mysql:junk:host=localhost", "user", "pass"); #Edit "junk" (DB name), user, and pass to suit.
 $dbh->do("DROP TABLE IF EXISTS $table");
 $dbh->do("CREATE TABLE $table (str TEXT) ENGINE=INNODB");
 $sth = $dbh->prepare("INSERT INTO $table (str) VALUES (REPEAT(?,1000000))");
 foreach (1..50) {
    $sth->execute('0123456789');   # 10 MB
 }
 $dbh->do("DELETE FROM $table");

Mi receta sugerida:

  1. Crear una base de datos 'basura'
  2. Guarde el script perl anterior como junk.pl .
  3. Ejecute junk.pl data1 y junk.pl data2 y junk.pl data3 , etc., todo a la vez, para tantos núcleos de CPU como tenga su servidor de base de datos, para comenzar. Abrir varias conchas y envolver cada corrida en un bucle Bash: while true; do date; junk.pl dataX; done.

Observe cómo crece su LSN, tal vez en otro ciclo:

 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 3871092821
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 4209892586
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 125 85212387

El gran número es un INT de 32 bits sin signo que se ajustará a 4 GB, aumentando el número más pequeño cada vez. En este caso anterior, simplemente pasó de 124 a 125. Su objetivo está oculto en el mysqld.log que lo envió a Google para esta solución ridícula en primer lugar. Una vez que cruce esa línea de meta, ¡eso es todo! Soplar los cuernos! ¡Suelta el confeti!

Barra lateral: Esto descubrió un error interesante en mysqld 5.0 w / REPEAT: si va a 20 MB, voltea algún contador interno y se acumula a ~ 96 KB. Sin advertencia o error en ningún lado. No iba a perder el tiempo rastreando eso. 10 MB funciona muy bien. Si llega a otro límite, puede quejarse. Tengo varios buffers innodb aumentados de forma predeterminada. Sazone al gusto. Como siempre, mire mysqld.log en una ventana.

IcarusNM
fuente
Mira esto percona.com/blog/2013/09/11/…
Jonas Stensved
Gracias jonas; eso es interesante. Creo que puedo seguir con mi método anterior. Muestra el uso de gdb contra el mysqld en ejecución que probablemente nunca arriesgaría. Pero buena información allí también.
IcarusNM
Por alguna extraña razón, usando MariaDB, no obtengo los números de secuencia de registro 'número pequeño [espacio] número grande', sino solo un 'número grande', así que lamentablemente este método no funcionó para mí. Bueno, por supuesto, el registro se actualiza, ¡no sé cuándo parar!
Gwyneth Llewelyn
5

Tienes tres (3) opciones:

OPCIÓN 01: Realizar rsync de maestro a esclavo (tiempo de inactividad en el maestro)

  • Paso 01: corre reset master; en el maestro (registros binarios de Zaps)
  • Paso 02: service mysql stopen el maestro
  • Paso 03: service mysql stopen el esclavo
  • Paso 04: rsync / var / lib / mysql del maestro al esclavo
  • Paso 05: service mysql starten el maestro
  • Paso 06: Use el primer registro binario en el maestro como el registro para iniciar la replicación. Utilice el tamaño de archivo de ese registro como posición para iniciar la replicación desde
  • Paso 07: service mysql stop --skip-slave-start en el esclavo
  • Paso 08: Ejecute el comando CHANGE MASTER TO para configurar la replicación desde el registro y la posición determinada desde el Paso 06
  • Paso 09: ejecuta start slave;el esclavo y deja que la replicación se ponga al día

OPCIÓN 02: Realizar rsync de maestro a esclavo (tiempo de inactividad mínimo en el maestro)

  • Paso 01: ejecutarreset master; en el maestro (registros binarios de Zaps)
  • Paso 02: service mysql stopen el esclavo
  • Paso 03: rsync / var / lib / mysql del maestro al esclavo
  • Paso 04: repita el paso 03 hasta que dos rsyncs consecutivos tomen la misma cantidad de tiempo
  • Paso 05: service mysql stopen el maestro
  • Paso 06: rsync / var / lib / mysql del maestro al esclavo
  • Paso 07: service mysql starten el maestro
  • Paso 08: Use el primer registro binario en el maestro como el registro para iniciar la replicación. Utilice el tamaño de archivo de ese registro como posición para iniciar la replicación desde
  • Paso 09: service mysql stop --skip-slave-starten el esclavo
  • Paso 10: Ejecute el comando CHANGE MASTER TO para configurar la replicación desde el registro y la posición determinada desde el Paso 08
  • Paso 11: ejecutar start slave;en el esclavo y dejar que la replicación se ponga al día

OPCIÓN 03: Usar XtraBackup

Esta herramienta de software no solo realizará una copia no intrusiva de un maestro en ejecución, sino que también creará los ib_logfiles correspondientes para usted. Tendría que configurar la replicación

He publicado anteriormente en StackExchange sobre este tema

He hecho estas cosas muchas veces para la empresa de alojamiento web de mi empleador. Un cliente tenía 3,7 TB para mover y tardó aproximadamente 16 horas. 64GB es muy pequeño en comparación.

RolandoMySQLDBA
fuente
En la OPCIÓN 02, Paso 05, dice que inicie el maestro. ¿Cuándo fue detenido? Rsync en un maestro en vivo es valiente. Estoy impresionado. Y por suerte estoy usando innodb_file_per_table. Pero eventualmente debe morder la bala y detener el maestro el tiempo suficiente para que se ejecute un rsync final antes de comenzar la replicación. Es una posibilidad a la que puedo recurrir, pero este es un DBMS muy activo. Y miraré XtraBackup para ver mi información.
IcarusNM
@IcarusNM: Ah, error tipográfico. Lo corregí Gracias !!!
RolandoMySQLDBA
La OPCIÓN 02 probablemente todavía podría usar algo de trabajo. Por ejemplo, debes hacer el paso 2 antes del paso 1. Probablemente quieras un RESTABLECER ESCLAVO en alguna parte. Error tipográfico en el paso 4. Y usted dice "primer registro binario" en el paso 5, pero realmente quiere decir "solo" o "último" registro binario. Y debe usar mysqlbinlog para determinar las posiciones de registro, no el tamaño del archivo. Y todo esto aún no funcionará a menos que detengas al maestro en algún momento. Basar una posición / hora de registro en cuándo finalizó un rsync es, en el mejor de los casos, arriesgado.
IcarusNM
He estado haciendo la OPCIÓN 2 durante los últimos 4 años con clientes de Hosting DB que tienen datos en la gama TeraByte. Funciona cada vez contra un servidor en ejecución. El único error real que podrías cometer es en el esclavo. Ese error estaría en si la replicación se configuró correctamente o no. Además, RESET SLAVEes útil, especialmente si ha acumulado muchos GB de registros de retransmisión. Después del proceso rsync y el restablecimiento de la replicación, recuerde que el comando CAMBIAR MAESTRO A también borrará los registros de retransmisión para usted también.
RolandoMySQLDBA
mmm ... extraño. configuré mi esclavo usando xtrabackup (como siempre) y todavía recibí estos errores de registro (percona mysql 5.5.x) ... parece que algo salió mal en este esclavo y tengo que hacerlo nuevamente.
Harald
2

Descubrí que quizás haya una forma más genial de resolver este problema trabajando en tablas particionadas. Necesitaba eliminar particiones de algunos años atrás, y tuve que agregar algunas para 2014. Casi todas las particiones informan este error, así que también las antiguas. Choque muy desagradable.

Entonces, mientras DROPPING old y use REORGANIZE de la partición MAXVALUE (la última), creará nuevos archivos que están bien, por lo que recibo cada vez menos advertencias. Mientras tanto, ayuda a incrementar el contador de secuencia de registro, por lo que no necesito insertar datos falsos. Tengo esto sucediendo en un servidor maestro por cierto ...

Así que esto:

ALTER TABLE Events DROP PARTITION p1530 , p1535 , p1540 , p1545 , 
p1550, p1555 , p1560 , p1565 , p1570 , p1575 , p1580 , p1585 , p1590 , 
p1595 , p1600 , p1605 , p1610 , p1615 , p1620 , p1625 , p1630 , p1635 , 
p1640 , p1645 , p1650 , p1655 , p1660 , p1665 , p1670 , p1675 , p1680 , 
p1685 , p1690 , p1695 , p1700 , p1705 , p1710 , p1715 , p1720 , p1725 , 
p1730 , p1735 , p1740 , p1745 , p1750 , p1755 , p1760 , p1765 , p1770 , 
p1775 , p1780 , p1785 , p1790 , p1795 , p1800 , p1805 , p1810 , p1815 , 
p1820 , p1825 , p1830 , p1835 , p1840;

Y esto:

ALTER table Events REORGANIZE PARTITION p3000 INTO (
PARTITION p3500 VALUES LESS THAN (TO_DAYS('2013-01-01')),
PARTITION p3510 VALUES LESS THAN (TO_DAYS('2013-01-04')),
PARTITION p3520 VALUES LESS THAN (TO_DAYS('2013-01-07')),
PARTITION p3530 VALUES LESS THAN (TO_DAYS('2013-01-10'))
...
PARTITION p4740 VALUES LESS THAN (TO_DAYS('2014-01-08')),
PARTITION p9000 VALUES LESS THAN MAXVALUE)

Eso eliminará efectivamente cada partición en el cambio y la recreará con una copia temporal del contenido de lo que estaba allí. Puede hacerlo por tabla si lo desea, mi aplicación permite que eso suceda, por lo que no tiene que preocuparse por las copias de seguridad sincronizadas, etc.

Ahora, para el resto de la tabla, dado que no he tocado todas las particiones en el proceso, algunas quedarán con la advertencia de secuencia de registro, para aquellas que están rotas pero cubiertas por esta acción de reorganización, probablemente ejecutaré esto:

ALTER TABLE Events REBUILD PARTITION p0, p1;

o eso

ALTER TABLE Events OPTIMIZE PARTITION p0, p1;

Entonces, eso me hizo pensar, podría hacer esto con tablas simples de vainilla, agregar particiones temporalmente por hash y luego eliminarlo (o mantenerlas, puedo recomendar particiones).

Sin embargo, estoy usando mariadb, no mysql (entonces XtraDB)

Quizás esto ayude a alguien. Todavía lo estoy ejecutando, hasta ahora todo bien. Cambiar ENGINE también parece hacer el trabajo, así que lo traigo de regreso entre MyIsam y ellos a InnoDB.

Es bastante lógico, si cambia ENGINE, la tabla desaparece de innodb, por lo que ya no será un problema.

ALTER TABLE Events ENGINE=MyISAM;
ALTER TABLE Events ENGINE=InnoDB;

Parece que funciona aquí. Puedo confirmar algunas cosas en tablas particionadas:

  • ALTER TABLE xyz ENGINE = InnoDB es muy lento, para Aria (mariadb) dos veces más rápido, pero en general es una forma lenta de incrementar el contador de secuencia de registro
  • ALTER TABLE xyz REBUILD PARTITION ALL es la forma más rápida de 'arreglar' las tablas y ayudar a incrementar el contador
  • ALTER TABLE xyz ANALYZE PARTITION ALL es lento comparado con el primero y no reescribe las particiones que están bien. RECONSTRUCCIÓN asegura una reescritura en un esquema de tabla temporal.

Usé los últimos en varias mesas. Las advertencias ocurren cuando se trata de abrir los archivos y hay una para cada definición de partición que se abre con problemas de contador. Casi rodé sobre el mostrador hoy para las últimas mesas. Creo que una vez que todo está procesado, uno necesita vaciar los registros binarios.

actualización : puedo concluir algunas cosas ahora que logré resolver este problema.

  • Mi bloqueo fue causado por la reorganización de particiones en una tabla en formato Aria (MariaDB).
  • (para mí) hacer una reconstrucción de las particiones funcionó mejor y más rápido para obtener el contador de secuencia. La alteración del motor es lenta y debe hacerlo dos veces para afectar innodb. alterar a innoDB es bastante lento en comparación con MyIsam o Aria.
  • Actualicé a MariaDB 5.3 y no a 5.5 (era: 5.2) y funciona bien. Creo que hay demasiados problemas con aria, particiones en 5.5 (y errores confirmados) para usar esa combinación.
  • Realmente debería haber una mejor manera de restablecer el contador de secuencia de registro.
Glenn Plas
fuente
Bajo MariaDB, puede alterar rápidamente todas las tablas usando USE INFORMATION_SCHEMA; SELECT CONCAT("ALTER TABLE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` REBUILD PARTITION ALL;") AS MySQLCMD AS MySQLCMD FROM TABLES;(fuente: dba.stackexchange.com/questions/35073/… ) y unirlo a un archivo para que se ejecute como una serie de comandos.
Gwyneth Llewelyn