La replicación no es una copia de seguridad. ¿O no? Así es como utilizamos la replicación diferida para recuperarnos de la eliminación accidental de accesos directos.
La replicación no es un medio para realizar copias de seguridad de bases de datos (gitlab-ce
Con una réplica diferida, recuperamos datos en solo 1,5 horas. Mira cómo pasó.
Recuperación puntual con PostgreSQL
PostgreSQL tiene una función incorporada que restaura el estado de una base de datos a un momento específico. Se llama
Para utilizar esta función para realizar copias de seguridad en frío, periódicamente realizamos una copia de seguridad básica de la base de datos y la almacenamos en un archivo (los archivos de GitLab se encuentran en
¿Qué es la replicación diferida?
La replicación diferida es la aplicación de cambios de WAL con retraso. Es decir, la transacción ocurrió en una hora. X
, pero aparecerá en la réplica con un retraso. d
h X + d
.
PostgreSQL tiene 2 formas de configurar una réplica de base de datos física: recuperación de respaldo y replicación de transmisión.
Cómo configurar la recuperación retrasada de un archivo
recovery.conf
. Un ejemplo:
standby_mode = 'on'
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /opt/wal-e/bin/wal-e wal-fetch -p 4 "%f" "%p"'
recovery_min_apply_delay = '8h'
recovery_target_timeline = 'latest'
Con estos parámetros configuramos una réplica diferida con recuperación de respaldo. aqui se usa restore_command
) del archivo, y los cambios se aplicarán después de ocho horas (recovery_min_apply_delay
). La réplica observará los cambios en la línea de tiempo en el archivo, por ejemplo, debido a una conmutación por error del clúster (recovery_target_timeline
).
С recovery_min_apply_delay
Puede configurar la replicación de transmisión con un retraso, pero aquí hay un par de problemas relacionados con las ranuras de replicación, la retroalimentación en espera activa, etc. El archivo WAL le permite evitarlos.
Parámetro recovery_min_apply_delay
apareció sólo en PostgreSQL 9.3. En versiones anteriores, para la replicación diferida es necesario configurar la combinación pg_xlog_replay_pause(), pg_xlog_replay_resume()
) o mantener los segmentos WAL en el archivo mientras dure el retraso.
¿Cómo hace esto PostgreSQL?
Es interesante ver cómo PostgreSQL implementa la recuperación diferida. Miremos a recoveryApplyDelay(XlogReaderState)
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* nothing to do if no delay configured */
if (recovery_min_apply_delay <= 0)
return false;
/* no delay is applied on a database not yet consistent */
if (!reachedConsistency)
return false;
/*
* Is it a COMMIT record?
*
* We deliberately choose not to delay aborts since they have no effect on
* MVCC. We already allow replay of records that don't have a timestamp,
* so there is already opportunity for issues caused by early conflicts on
* standbys.
*/
if (XLogRecGetRmid(record) != RM_XACT_ID)
return false;
xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
if (xact_info != XLOG_XACT_COMMIT &&
xact_info != XLOG_XACT_COMMIT_PREPARED)
return false;
if (!getRecordTimestamp(record, &xtime))
return false;
recoveryDelayUntilTime =
TimestampTzPlusMilliseconds(xtime, recovery_min_apply_delay);
/*
* Exit without arming the latch if it's already past time to apply this
* record
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Shortened:
// Use WaitLatch until we reached recoveryDelayUntilTime
// and then
break;
}
return true;
}
La conclusión es que el retraso se basa en el tiempo físico registrado en la marca de tiempo de confirmación de la transacción (xtime
). Como puede ver, el retraso solo se aplica a las confirmaciones y no afecta a otras entradas: todos los cambios se aplican directamente y la confirmación se retrasa, por lo que solo veremos los cambios después del retraso configurado.
Cómo utilizar una réplica retrasada para restaurar datos
Digamos que tenemos un clúster de base de datos y una réplica con un retraso de ocho horas en producción. Veamos cómo recuperar datos usando un ejemplo.
Cuando nos enteramos del problema,
SELECT pg_xlog_replay_pause();
Con una pausa, no teníamos riesgo de que la réplica repitiera la solicitud. DELETE
. Algo útil si necesitas tiempo para resolverlo todo.
La cuestión es que la réplica diferida debe llegar al momento anterior a la solicitud. DELETE
. Sabíamos aproximadamente el momento físico de la expulsión. hemos eliminado recovery_min_apply_delay
y agregado recovery_target_time
в recovery.conf
. Así es como la réplica llega al momento justo sin demora:
recovery_target_time = '2018-10-12 09:25:00+00'
Con las marcas de tiempo, es mejor reducir el exceso para no perderse. Es cierto que cuanto mayor es la disminución, más datos perdemos. Nuevamente, si perdemos la solicitud DELETE
, todo se eliminará nuevamente y tendrás que comenzar de nuevo (o incluso realizar una copia de seguridad en frío para PITR).
Reiniciamos la instancia de Postgres diferida y los segmentos WAL se repitieron hasta el tiempo especificado. Puede realizar un seguimiento del progreso en esta etapa preguntando:
SELECT
-- current location in WAL
pg_last_xlog_replay_location(),
-- current transaction timestamp (state of the replica)
pg_last_xact_replay_timestamp(),
-- current physical time
now(),
-- the amount of time still to be applied until recovery_target_time has been reached
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;
Si la marca de tiempo ya no cambia, la recuperación estará completa. La acción se puede personalizar. recovery_target_action
La base de datos volvió a su estado antes de esa desafortunada solicitud. Ahora puedes, por ejemplo, exportar datos. Exportamos los datos de las etiquetas eliminadas y todos los enlaces a problemas y solicitudes de fusión y los trasladamos a la base de datos de producción. Si las pérdidas son a gran escala, simplemente puede promocionar la réplica y utilizarla como principal. Pero entonces se perderán todos los cambios después del punto en el que nos hayamos recuperado.
En lugar de marcas de tiempo, es mejor utilizar ID de transacción. Es útil registrar estos ID, por ejemplo, para declaraciones DDL (como DROP TABLE
), mediante el uso log_statements = 'ddl'
. Si tuviéramos un ID de transacción, tomaríamos recovery_target_xid
y ejecutó todo hasta la transacción antes de la solicitud DELETE
.
Volver al trabajo es muy sencillo: elimina todos los cambios de recovery.conf
y reinicie Postgres. La réplica pronto volverá a tener un retraso de ocho horas y estamos preparados para problemas futuros.
Beneficios de recuperación
Con una réplica diferida en lugar de una copia de seguridad en frío, no tendrá que pasar horas restaurando la imagen completa desde el archivo. Por ejemplo, nos lleva cinco horas obtener la copia de seguridad básica completa de 2 TB. Y luego aún tendrá que aplicar todo el WAL diario para recuperarse al estado deseado (en el peor de los casos).
Una réplica diferida es mejor que una copia de seguridad en frío de dos maneras:
- No es necesario eliminar toda la copia de seguridad básica del archivo.
- Hay una ventana fija de ocho horas de segmentos WAL que deben repetirse.
También verificamos constantemente si es posible crear un PITR desde WAL, y rápidamente notaríamos corrupción u otros problemas con el archivo WAL al monitorear el retraso de la réplica diferida.
En este ejemplo, nos tomó 50 minutos restaurar, lo que significa que la velocidad fue de 110 GB de datos WAL por hora (el archivo todavía estaba en
Resultados: dónde es útil una réplica diferida (y dónde no)
Utilice la replicación retrasada como primeros auxilios si perdió datos accidentalmente y notó este problema dentro del retraso configurado.
Pero tenga en cuenta: la replicación no es una copia de seguridad.
La copia de seguridad y la replicación tienen diferentes propósitos. Una copia de seguridad en frío será útil si accidentalmente realizaste DELETE
o DROP TABLE
. Realizamos una copia de seguridad desde el almacenamiento en frío y restauramos el estado anterior de la tabla o de toda la base de datos. Pero al mismo tiempo la petición DROP TABLE
se reproduce casi instantáneamente en todas las réplicas del clúster de trabajo, por lo que la replicación ordinaria no ayudará aquí. La replicación en sí mantiene la base de datos disponible cuando se alquilan servidores individuales y distribuye la carga.
Incluso con una réplica diferida, a veces realmente necesitamos una copia de seguridad en frío en un lugar seguro si ocurre una falla en el centro de datos, daños ocultos u otros eventos que no se notan de inmediato. La replicación por sí sola no sirve aquí.
Nota. En
Fuente: habr.com