sql >> Base de Datos >  >> RDS >> PostgreSQL

Al realizar PITR, ¿sería posible pausar/reanudar en PostgreSQL?

Sí, verdaderamente posible y manejado inteligentemente por PostgreSQL. Para hacer una demostración de esto, primero necesito seguir la técnica estándar de Recuperación en un punto en el tiempo en PostgreSQL. Varios Libros/Artículos/Blogs demostrados extremadamente bien por autores extraordinarios, por lo tanto, no voy a entrar en detalles de cómo hacerlo, sin embargo, me dirijo directamente al tema, es decir, cómo hacer una pausa mientras se recupera con la misma técnica. Podría decirse que presenté una expresión matemática de PITR como "PITR =(Última copia de seguridad del sistema de archivos (LFB) + Archivos WAL generados después de LFB + WAL no archivados en $PGDATA/pg_xlogs actuales)". Para una mejor comprensión, he puesto esto en un gráfico, porque aclara más la idea:(Lo siento, este blog es un poco largo, sin saberlo, sucedió mientras entraba en detalles del concepto)

Pasos de PITR, que voy a seguir con ligeros cambios de los que hablaré pronto:

Paso 1. Restaure la copia de seguridad a nivel del sistema de archivos (FSB) más reciente en cualquier ubicación donde se planee realizar la recuperación.
Paso 2. Si FSB es tar, descomprímalo y limpie el directorio pg_xlog dejando archive_status. Si la copia de seguridad ha excluido este directorio, cree el directorio pg_xlog vacío en FSB.
Paso 3. Copie WAL no archivados del clúster bloqueado $PGDATA/pg_xlog en $FSB/pg_xlog (Paso 2)
Paso 4. Eliminar el postmaster.pid del directorio FSB.
Paso 5. Cree el archivo recovery.conf en el directorio FSB.
Paso 6. Inicie el clúster (FSB).

Deberíamos ponernos en duda, ¿cuándo se requiere pausar la recuperación?. Tal vez, para evitar múltiples restauraciones de base o recuperación de avance, pero verificar entre o revertir datos de tablas en particular o interés para ver hasta qué punto se ha recuperado :). Recuerde, pausa en los medios de recuperación, está permitiendo conectarse mientras se recupera. Para resumir esto, he reproducido una situación en el gráfico de una mejora en las filas de una tabla en particular hasta un percance.

Del diagrama anterior, es aceptable que las filas de una tabla DEMO fueran 10,00,000 cuando se realizó la copia de seguridad a nivel del sistema de archivos ($PGDATA) y 40,00,000 filas antes del bloqueo. En mi máquina virtual local, hice la situación sobre la base de HORA en lugar de fecha.

Requisito previo:
1. Copia de seguridad a nivel del sistema de archivos cuando las tablas DEMO tienen 10,00,000 filas.
2. A partir de ese momento, WAL Archives antes del bloqueo donde la tabla DEMO tenía 40,00,000 filas.
3. Ubicación de los archivos WAL:/opt/PostgreSQL/9.3/archives.
4. Directorio de datos:/opt/PostgreSQL/9.3/data (PGDATA)
5. Ubicación de la copia de seguridad:/opt/PostgreSQL/9.3/backups

Tenga en cuenta que trabajar con la recuperación de pausa necesita cambios obligatorios en el clúster principal ($PGDATA) "wal_level" establecido en "hot_standby" y en el clúster de recuperación (copia de seguridad a nivel del sistema de archivos) "hot_standby" establecido en "ON". Realicé estos cambios en el clúster principal, reinicié el clúster para que tuviera efecto e inicié la copia de seguridad. Si no le importa, tome nota de que es simplemente una demostración, por lo que es posible que mis archivos WAL no sean números gigantes, ya que están en pocos números. También he enumerado archivos WAL aquí, que se generaron desde el momento de la copia de seguridad hasta el bloqueo.

-bash-4.1$ psql -c "select count(*), now() from demo;"
count | now
---------+-------------------------------
1000000 | 2014-04-04 15:06:04.036928-07
(1 row)

-bash-4.1$ pg_basebackup -D /opt/PostgreSQL/9.3/backup/data_pitr -- I have my $PGDATA, $PGUSER, $PGPORT set, so its a straight command in my case
NOTICE: pg_stop_backup complete, all required WAL segments have been archived

Estado actual de los archivos WAL y $PGDATA/pg_xlog

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001C
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001D
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/data/pg_xlog | tail -4
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
drwx------ 2 postgres postgres 4.0K Apr 4 16:13 archive_status

Bien, ahora tenemos la copia de respaldo, permite INSERTAR algunos registros en tres partes anotando la hora, por lo que ayudará a pausar la recuperación y, además, ver los WAL producidos desde la época de FSB.

-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
2000000 | 2014-04-04 16:06:34.941615-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
3000000 | 2014-04-04 16:10:31.136725-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
4000000 | 2014-04-04 16:13:00.136725-07
(1 row)

Verifique el número de WAL producidos durante el INSERTO.

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000020
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000021
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000022
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000023
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000024
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000025
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000026
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000027
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000028
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000029
-rw------- 1 postgres postgres 16M Apr 4 16:10 00000001000000000000002A
-rw------- 1 postgres postgres 16M Apr 4 16:13 00000001000000000000002B

Suponga que en este punto ocurrió un percance y tiene que hacer la recuperación usando archivos FSB + WAL + WAL no archivados (si corresponde). Durante la recuperación, quiero hacer una pausa tres veces para ver cada recuperación de 20,00,000, 30,00,000 y 40,00,000 filas de la tabla DEMO al conectarme a la base de datos en modo de SOLO LECTURA. Para cada reanudación de la recuperación, es necesario reiniciar el clúster de recuperación saltando a la nueva línea de tiempo en recovery.conf/recovery_target_time. Además, en $FSB/postgresql.conf, tenemos que configurar hot_standby=on. Aquí está mi archivo recovery.conf:

-bash-4.1$ more recovery.conf
pause_at_recovery_target = true
#recovery_target_time = '2014-04-04 16:06:34' # For 2 lakh records
#recovery_target_time = '2014-04-04 16:10:31' # For 3 lakh records
#recovery_target_time = '2014-04-04 16:13:00' # For 4 lakh records
restore_command = 'cp /opt/PostgreSQL/9.3/archives/%f %p'

Comencemos la recuperación de 20,00,000 registros:

-bash-4.1$ /opt/PostgreSQL/9.3/bin/pg_ctl -D /opt/PostgreSQL/9.3/data_pitr/ start
server starting

Now in logs:

-bash-4.1$ more postgresql-2014-04-04_162524.log
2014-04-04 16:25:24 PDT-24187---[] LOG: starting point-in-time recovery to 2014-02-06 18:48:56-08
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001E" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: redo starts at 0/1E0000C8
2014-04-04 16:25:24 PDT-24187---[] LOG: consistent recovery state reached at 0/1E000190
2014-04-04 16:25:24 PDT-24185---[] LOG: database system is ready to accept read only connections
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001F" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "000000010000000000000020" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000021" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000022" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery stopping before commit of transaction 1833, time 2014-04-04 16:06:23.893487-07
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery has paused
2014-04-04 16:25:25 PDT-24187---[] HINT: Execute pg_xlog_replay_resume() to continue

Genial, vea en los registros que se ha pausado y una SUGERENCIA inteligente que pide reanudar. Aquí, si la recuperación fue satisfactoria, puede reanudarla llamando a "select pg_xlog_replay_resume();" (puede comprobarlo). No reanudemos ahora, sin embargo, verifique la cantidad de filas recuperadas al conectarse al servidor.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
2000000 | t
(1 row)

Bien, ha llegado al punto y se detuvo donde lo solicité. Avancemos un paso más para recuperar 30,00,000 filas. Ahora, establezca la siguiente línea de tiempo en recovery.conf/recovery_target_time y reinicie el clúster.

2014-04-04 16:28:40 PDT-24409---[] LOG:  restored log file "00000001000000000000002A" from archive
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery stopping before commit of transaction 1836, time 2014-04-04 16:10:40.141175-07
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery has paused
2014-04-04 16:28:40 PDT-24409---[] HINT: Execute pg_xlog_replay_resume() to continue.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
3000000 | t
(1 row)

Bien..., hagamos el último intento de hacer una pausa en 40,00,000 filas.

2014-04-04 20:09:07 PDT-4723---[] LOG:  restored log file "00000001000000000000002B" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001000000000000002C': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: redo done at 0/2B0059A0
2014-04-04 20:09:07 PDT-4723---[] LOG: last completed transaction was at log time 2014-04-04 16:11:12.264512-07
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000001000000000000002B" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000002.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000003.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000004.history" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000005.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: selected new timeline ID: 5
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: archive recovery complete
2014-04-04 20:09:08 PDT-4721---[] LOG: database system is ready to accept connections
2014-04-04 20:09:08 PDT-4764---[] LOG: autovacuum launcher started

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
4000000 | f
(1 row)

Vaya, ¿qué pasó, por qué no ha hecho una pausa y de qué se queja?. Tenga en cuenta que si no hay archivos WAL presentes en el momento de recovery_target_time, entonces no se detendrá y esperará que haya llegado al último punto y abra la base de datos para LEER/ESCRIBIR. En los registros, sin mucho esfuerzo, estaba buscando el archivo "00000001000000000000002C", que no está disponible, porque en ese momento el clúster se bloqueó. Es posible que algunos no reconozcan este comportamiento, pero es un hecho y tiene sentido cuando no hay archivos WAL presentes, entonces no hay razón para pausar la recuperación. Si es necesario hacer una pausa incluso después de que no haya archivos WAL, utilice standby_mode='on' (HOT_STANDBY), en este método no saldrá de la recuperación sino que esperará a los archivos WAL.

Espero que haya sido útil.