
Este artículo trata sobre cómo salvarse de un accidente pt-online-schema-change
aprovechar pt-archiver
y ejecuta consultas para garantizar que los datos se migren con precisión. Le mostraré cómo continuar con el proceso de copia de datos y cómo apagarlo de manera segura. pt-online-schema-change
a través de operaciones manuales como RENAME TABLE
y DROP TRIGGER
mandamientos El proceso normal para recuperarse de un accidente pt-online-schema-change
es colocar los disparadores en su tablero original y colocar el nuevo tablero creado por el script. Entonces vete pt-online-schema-change
. En este caso, esto no fue posible.
Recientemente, un cliente necesitaba agregar una columna de clave principal a una tabla muy ocupada (con aproximadamente 200 millones de filas). La tabla tenía una sola clave en una columna (llamada our_id
debajo). El cliente estaba preocupado por el retraso del esclavo y quería asegurarse de que hubiera poco o nada. Esto, como el hecho de que no puede agregar una clave principal como DDL en línea en MySQL y Percona Server 5.6, significaba que la respuesta obvia era usarla. pt-online-schema-change
.
Debido a la sensibilidad de su entorno, solo podían permitir una ventana corta para los bloqueos de metadatos iniciales y tendrían que hacer manualmente el intercambio desplegable que pt-online-schema-change
generalmente se hace automáticamente. Aquí es donde no-drop-triggers
y no-swap-tables
ingresar. En teoría, los disparadores se ejecutarán indefinidamente para mantener sincronizadas las tablas nuevas y antiguas una vez. pt-online-schema-change
está completo. Creamos el siguiente comando:
pt-online-schema-change –execute –alter-foreign-keys-method = auto –max-load Threads-running = 30 –critical-load Threads_running = 55 –check-slave-lag mysql-slave1, mysql-slave2, mysql-slave3 –max − lag = 10 –chunk-time = 0.5 –set-vars = lock_timeout = 1 –tries = «create_triggers: 10: 2, drop_triggers: 10: 2» –no -drop-new-table –no-drop-triggers –no-swap-tables –chunk-index «our_id» –alter «ADD newcol BIGINT (20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST» D = sitio web, t = tabla grande –nocheck-plan
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 dieciséis 17 |
punto–en línea–esquema–cambio –completo –alter-foreign-keys-method = auto –max-load Subprocesos en ejecución = 30 –critical-load Threads_running = 55 –check-slave-lag mysql-slave1, mysql-slave2, mysql-slave3 –máx – retraso = 10 –trozo-tiempo = 0.5 –set-vars = lock_timeout = 1 –intenta = «create_triggers: 10: 2, drop_triggers: 10: 2» –no-drop-new-table –no-drop-triggers –sin-tablas-de-intercambio –chunk-index «nuestro_id» –alter «AÑADIR newcol BIGINT (20) SIN FIRMAR NO NULO AUTO_INCREMENT CLAVE PRINCIPAL PRIMERO» D=sitio web,t=Mesa grande –nocheck-plan |
Puede ver algunas de las especificaciones de las otras banderas y por qué las usamos en el Manual del kit de herramientas de Percona.
Una vez que ejecutamos el comando, el cliente se preocupó, ya que sus herramientas de monitoreo no mostraban ningún trabajo realizado (que es diseño, pt-online-schema-change
no quieres dañar tu entorno de carrera). El cliente corrió strace -p
para asegurarse de que funcionó. Esta no fue una gran elección ya que fracasó pt-online-schema-change
.
En este punto, sabemos que la aplicación (y la administración) no nos permite realizar nuevos bloqueos de metadatos para crear disparadores en la tabla, ya que hemos pasado por nuestra ventana de bloqueo de metadatos.
Entonces, ¿cómo nos recuperamos?
Primero, comencemos con una pizarra limpia. Emitimos los siguientes comandos para crear una nueva tabla, donde __largetable_new
es la tabla creada por pt-online-schema-change
:
CREAR TABLA mynewlargetable LIKE __largetable_new; CAMBIAR EL NOMBRE DE LA TABLA __largetable_new A __largetable_vecchio, mynewlargetable A __largetable_new; DROP TABLE __largetable_old;
CREAR MESA minuevamesagrande ME GUSTA __tablero_grande_nuevo; REBAUTIZAR MESA __tablero_grande_nuevo A __tabla_grande_antigua, minuevamesagrande A __tablero_grande_nuevo; GAS MESA __tabla_grande_antigua; |
Ahora los disparadores en la mesa original, largetable
actualice la nueva tabla vacía que tiene nuestro nuevo esquema.
Ahora afrontemos el problema de traducir los datos que ya están allí. largetable
a __largetable_new
. Aquí es donde pt-archiver
ingresar. Creamos el siguiente comando:
pt-archiver –execute –max-lag = 10 –source D = sitio web, t = tabla grande, i = our_id –dest D = sitio web, t = __largetable_new –where «1 = 1» –no -check -charset –no-delete –no-check-columns –txn-size = 500 –limit = 500 –ignore –statistics
punto–archivador –completo –max-retraso = 10 –fuente D = sitio web, t = lanzamiento, i = nuestro_id –dest D = sitio web, t = __ largetable_new –donde «1 = 1» –no-check-juego de caracteres –no-eliminar –sin-verificar-columnas –txn-tamaño = 500 –limitado = 500 –ignorar –estadísticas |
lo usamos pt-archiver
para copiar lentamente los registros de forma no destructiva a la nueva tabla en función de our_id
y WHERE 1=1
(todos los registros). En este punto, revisamos periódicamente el directorio de datos de MySQL en el transcurso de un día con ls -l
para comparar las dimensiones de la mesa.
Una vez que los archivos de la tabla tenían casi el mismo tamaño, realizamos conteos en las tablas. Notamos algo interesante: la nueva tabla tenía miles de registros más que la tabla original.
Esto nos preocupó. Nos preguntábamos si nuestro “pirata” estaba equivocado. En este punto, hemos hecho algunas preguntas de verificación:
seleccione min (nuestro_id) de __largetable_new; seleccione max (nuestro_id) de __largetable_new; seleccione min (nuestro_id) de la tabla grande; seleccione max (our_id) de largetable;
Seleccione min(en nuestro_id) sí __tablero_grande_nuevo; Seleccione máximo(en nuestro_id) sí __tablero_grande_nuevo; Seleccione min(en nuestro_id) sí Mesa grande; Seleccione máximo(en nuestro_id) sí Mesa grande; |
Nos enteramos de que había registros más antiguos que no existían en la mesa en vivo. Esto significa que pt-archiver
y el activador DELETE pueden haberse perdido entre sí (es decir, pt-archiver
ya estaba en una transacción pero no había escrito registros en la nueva tabla hasta que ya se había disparado el activador DELETE).
Comprobamos con más preguntas:
SELECCIONA CUENTA
DESDE largetable l DONDE NO EXISTE (SELECCIONE our_id FROM __largetable_new n DONDE n.our_id = l.our_id); SELECCIONECONTAR(* ) SÍ Mesa grande yo INDUNI NO EXISTE( SELECCIONE en nuestro_id SÍ __tablero_grande_nuevo norte INDUNInorte.en nuestro_id=yo.en nuestro_id) |
;
No devuelven nada.
SELECCIONA CUENTA FROM __largetable_new n DONDE NO EXISTE (SELECCIONE our_id FROM largetable l DONDE n.our_id = l.our_id);SELECCIONECONTAR( * ) SÍ __tablero_grande_nuevo norte INDUNI NOEXISTE ( SELECCIONE en nuestro_id SÍ Mesa grande yoINDUNInorte.en nuestro_id=yo.en nuestro_id |
)
; DELETE
Nuestro resultado mostró 4000 registros adicionales en la nueva tabla. Esto muestra que terminamos con registros adicionales que se eliminaron de la tabla original. Realizamos otras consultas en sus datos para verificar también.
Esto no fue un gran problema para nuestra aplicación y podría tratarse fácilmente con uno simple. pt-online-schema-change
consulta basada en el índice único (es decir, si no existe en la tabla original, elimínelo de la nueva).
Ahora para completar el
comportamiento. Todo lo que tenemos que hacer es cambiarle el nombre atómicamente o soltarlo. Esto debe hacerse lo antes posible para evitar caer en un estado degradado, donde todas las entradas en la tabla anterior se duplican en la nueva. CAMBIAR EL NOMBRE DE TABLE largetable TO __largetable_old, __largetable_new TO largetable; REBAUTIZAR MESA Mesa grande A __tabla_grande_antigua , __tablero_grande_nuevoA |
Mesa grande
;
Entonces deje los factores desencadenantes por seguridad: DROP TRIGGER pt_osc_website_largetable_ins; DROP TRIGGER pt_osc_website_largetable_upd; DROP TRIGGER pt_osc_website_largetable_del; GASDESENCADENAR pt_osc_website_largetable_ins ; GASDESENCADENAR pt_osc_website_largetable_upd ; GASDESENCADENAR |
pt_osc_website_largetable_del
;
En este punto, es más seguro esperar a que la tabla anterior se elimine del grupo de búfer antes de irse, solo para asegurarse de que no haya impacto en el servidor (quizás una semana para estar seguro). Puede consultar el esquema de información para obtener una lectura más precisa de esto: SELECCIONA CUENTAFROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE WHERE TABLE_NAME = ‘`website`.`__largetable_old`’; + ———- + | contar| + ———- + | 279175 | + ———- + 1 fila en conjunto (8.94 seg)SELECCIONE CONTAR (*) SÍ INFORMACIÓN_ESQUEMA . INNODB_BUFFER_PÁGINAINDUNI NOMBRE DE LA TABLA= «sitio web`.`__largetable_old`’ ;+———- +| contar (* ) |+ ———- + | 279175 | + ———- + 1póngase en fila encolocar |
(
8.94
segundo ) Una vez que esto llega a 0, puede emitir:DROP TABLE __largetable_old; |
GASSUTABELLA__mesa_grande_vecchia;