GuilleSQL :: Microsoft SQL Server, SSIS, y más !!

PostgreSQL: Hot Physical Backup and Restore


Una de las tareas más importantes para un Administrador de Base de Datos es ser capaz de hacer correctamente un Backup y un Restore de una Instancia o Base de Datos. En el presente artículo vamos a describir paso a paso cómo realizar un Backup físico en caliente de una Instancia PostgreSQL 9.2 (lo que se conoco como un Backup Base, una copia del directorio data) y el correspondiente Restore sobre la misma Instancia, dejando dicha Instancia levantada en un estado consistente.

Descripción del Escenario

Partimos de una instalación del PostgreSQL 9.2.18 con archivado de WAL comprimido sobre Centos7 utilizando únicamente los tablespaces por defecto. Las principales rutas son las siguientes:

  • Directorio Data: /var/lib/pgsql/data
  • Directorio Archivado de WAL comprimido: /var/lib/pgsql/PostgresqlWalCompr
  • Directorio para almacenar los Backups: /var/lib/pgsql/PostgresqlBackup

La configuración del archivado de WAL en el fichero postgresql.conf es la siguiente:

wal_level = archive
archive_mode = on
archive_command = '/usr/local/bin/omnipitr-archive -D /var/lib/pgsql/data -l /var/log/wal/wal.log -dl gzip=/var/lib/pgsql/PostgresqlWalCompr -v "%p"'

La idea es realizar un Backup físico en caliente (sin parada de servicio) a nivel de sistema de ficheros de toda la Instancia (ya sea con un tar comprimido o con algún otro método), y seguidamente simular una recuperación de dicha copia sobre la misma Instancia, sin necesidad de crear el fichero recovery.conf.

Esta es una forma típica de acometer el Backup de PostgreSQL. Una forma bastante rápida, poco intrusiva (impacta menos que un pg_dump), y que permite recuperar todas las bases de datos a un mismo momento. Sin embargo también tiene algunos inconvenientes o desventajas, ya que sólo se puede recuperar sobre otra Instancia de PostgreSQL que esté en la misma versión y además implica recuperar la Instancia completa (no es posible recuperar una única base de datos).

Backup listo para recuperar (Ready to Restore) en caliente de PostgreSQL (PostgreSQL Hot Physical Backup)

Para realizar el backup físico en caliente, conectados con el usuario postgres, lo primero que deberemos hacer es poner la Instancia en modo Backup utilizando la función pg_start_backup, seguidamente realizaremos la copia del directorio data utilizando la forma que más nos guste (por ejemplo un tar comprimido), para seguidamente salir del modo Backup utilizando la función pg_stop_backup. Todo esto lo podríamos resumir en los siguientes comandos:

su - postgres
cd  /var/lib/pgsql
psql -c "select pg_start_backup('Daily Backup'), current_timestamp"
tar -cvz -f /var/lib/pgsql/PostgresqlBackup/data.tar.gz data/
psql -c "select pg_stop_backup(), current_timestamp"

Si deseamos utilizar una herramienta de Backup como Veritas o DataProtector, podemos utilizar como Pre-Script el comando pg_start_backup, y como Post-Script el comando pg_stop_backup, y así poder realizar la copia del filesystem correctamente con Veritas, DataProtector, o la herramienta que más nos guste, con la ventaja de no necesitar espacio adicional pudiendo hacer el Backup directamente a cinta.

Cabe comentar, que al poner la Instancia en modo Backup con la función pg_start_backup, se crea automáticamente el fichero backup_label dentro del directorio data, que podremos consultar al hacer el restore si lo necesitamos.

IMPORTANTE: El principal problema, es que el directorio pg_xlog podría no tener todas las transacciones necesarias (WAL), en cuyo caso tendríamos un Backup inconsistente.

Ahora ha llegado el momento de ver cómo recuperar el Backup que acabamos de realizar. Una de las ventajas del método que vamos a ver es que no vamos a necesitar crear el fichero recovery.conf, simplificando el proceso de recuperación.

Para poder recuperar el Backup que acabamos de hacer, deberemos detener el servicio de PostgreSQL, eliminar o mover el directorio data (recomendable moverlo por si fuera necesario más adelante, o hacer un tar comprimido para ahorrar espacio), recuperar el directorio data, y arrancar PostgreSQL de nuevo. Esto lo podemos realizar con los siguientes comandos:

pg_ctl -D /var/lib/pgsql/data -m fast stop
mv data data-old # También es posible hacer un tar comprimido
tar -xvzf /var/lib/pgsql/PostgresqlBackup/data.tar.gz
pg_ctl -D /var/lib/pgsql/data start

Después de arrancar la Instancia de PostgreSQL, comenzará la recuperación, de tal modo que al finalizar el Recovery, se renombrará automáticamente el fichero backup_label como backup_label.old. El fichero backup_label también le podemos consultar antes de hacer el restore para asegurarnos a que momento vamos a restaurar, es decir, la fecha del backup.

Si lo deseamos podemos consultar el comienzo del último fichero de log de PostgreSQL, para comprobar cómo ha ido el arranque de nuestra Instancia tras la recuperación, y asegurarnos que está todo OK. Como podemos ver en el siguiente pantallazo, hemos recuperado correctamente el estado de nuestra Instancia a las a las 20:46 del 14/01/2017 (en el pantallazo anterior podemos ver que el Backup comenzó a las 20:35 y finalizó a las 20:46). Para esto podemos utilizar un comando head como el siguiente.

head -n 20 data/pg_log/postgresql-2017-01-14_215344.csv 

La salida de su ejecución debería ser algo así.

Backup físico excluyendo el directorio de WAL

Ahora vamos a hacer el backup físico del filesystem excluyendo el directorio de WAL, que aunque resulta más complicado, didácticamente es bastante interesante para conocer mejor como funciona PostgreSQL en este tipo de situaciones. Al excluir el directorio de WAL (data/pg_xlog), deberemos incluir una copia del archivado de WAL, ya que necesitaremos dichas transacciones para poder recuperar nuestra Instancia, que es lo que complica un poco todo el proceso, tanto de Backup como de Restore. En cualquier caso, esto lo podríamos realizar con los siguientes comandos:

su - postgres
cd  /var/lib/pgsql
psql -c "select pg_start_backup('Daily Backup'), current_timestamp"
tar -cvz --exclude="pg_xlog/*" -f /var/lib/pgsql/PostgresqlBackup/data.tar.gz data/
psql -c "select pg_stop_backup(), current_timestamp"
tar -cvzf /var/lib/pgsql/PostgresqlBackup/archive.tar.gz PostgresqlWalCompr/

Para poder recuperar el Backup que acabamos de hacer, deberemos detener el servicio de PostgreSQL, eliminar o mover el directorio data (recomendable moverlo por si fuera necesario más adelante, o bien hacer un tar comprimido), y recuperar el directorio data. Esto lo podemos realizar con los siguientes comandos:

pg_ctl -D /var/lib/pgsql/data -m fast stop
mv data data-old # un tar comprimido también vale
tar -xvzf /var/lib/pgsql/PostgresqlBackup/data.tar.gz

Si no tuviésemos los WAL archivados comprimidos, los recuperaríamos también (en nuestro caso de ejemplo, como no los hemos eliminado, no hace falta recuperarlos).

tar -xvzf /var/lib/pgsql/PostgresqlBackup/archive.tar.gz

En nuestro Backup excluimos el directorio data/pg_xlog, por lo que no tendremos ningún WAL, aunque tenemos los WAL archivados comprimidos. Vamos a necesitar algunos ficheros WAL, pero a priori no sabemos cuáles. Para saber qué ficheros WAL necesitamos, en primer lugar visualizaremos el fichero backup_label del directorio data.

Podemos observar que el WAL de inicio es el 0000000100000000000000CE. Sabiendo esto, podemos consultar los ficheros archivados de WAL como se muestra en el siguiente ejemplo, para averiguar los ficheros WAL que hacen falta. En nuestro caso tan sólo hace falta uno (ver START WAL LOCATION y STOP WAL LOCATION), el fichero 0000000100000000000000CE, por lo que lo descomprimiremos y lo copiaremos a la carpeta de WAL, para seguidamente arrancar PostgreSQL.

ls PostgresqlWalCompr/0000000100000000000000CE*.*
gzip -d PostgresqlWalCompr/0000000100000000000000CE.00000020.backup.gz
cat PostgresqlWalCompr/0000000100000000000000CE.00000020.backup
gzip -d PostgresqlWalCompr/0000000100000000000000CE.gz
cp PostgresqlWalCompr/0000000100000000000000CE data/pg_xlog/
pg_ctl -D /var/lib/pgsql/data start

A continuación podemos ver un ejemplo de su ejecución.

Después de arrancar la Instancia de PostgreSQL, comenzará la recuperación, de tal modo que al finalizar el Recovery, se renombrará automáticamente el fichero backup_label como backup_label.old, y funcionando que es gerundio.

¿Y si no tenemos los ficheros WAL?

Si por cualquier motivo no tuviésemos los ficheros WAL necesarios para poder arrancar la Instancia de PostgreSQL, lo más probable es que al intentar arrancar PostgreSQL se aborté y registre en el LOG una secuencia de mensajes similares a la siguiente:

could not open file ""pg_xlog/0000000100000000000000CC"" (log file 0, segment 204): No such file or directory
invalid checkpoint record
could not locate required checkpoint record. If you are not restoring from a backup, try removing the file /var/lib/pgsql/data/backup_label
startup process (PID 6877) exited with exit code 1
aborting startup due to startup process failure

En el siguiente pantallazo se muestra un ejemplo del contenido que podemos encontrarnos en el LOG de PostgreSQL.

Mal asunto. Estamos jodidos. En esta situación existe riesgo de corrupción de datos debido a transacciones parcialmente confirmadas que NO han podido ser re-hechas (REDO) ni des-hechas (ROLLBACK). Así que, nos queda cómo última opción, utilizar el comando pg_resetxlog para resetear los WAL y la información de control asociada. Tras esto, lo más probable es que seamos capaces de arrancar PostgreSQL pero dado que puede almacenar información inconsistente, no debemos de confiar más en esta instancia de PostgreSQL, siendo muy recomendable hacer un export (pg_dumpall) de las bases de datos, reconstruir la instancia (initdb), cargar de nuevo los datos (pg_restore), y comprobar si hay alguna inconsistencia que deba ser reparada. Sin entrar en todos estos detalles, a continuación se muestra un ejemplo de cómo utilizar pg_resetxlog para resetear los WAL y conseguir arrancar PostgreSQL.

Poco más por hoy. Como siempre, confío que la lectura resulte de interés.

 


]
[Autor: GuilleSQL]


Comentarios

Lissy - 23/10/2018 (UTC)
Hola, vi tu post y me interesa saber si conoces alguna manera de restaurar una base de datos en postgresql sin usar la consola. o sea, por dentro de la aplicacion web tengo un boton donde necesito mandar a ejecutar el script para q me realice una restaura completa de la base de datos, esto significa con el usuario autenticado en el sistema. no he encontrado un post donde diga como hacerlo desde dentro, no se puede hacer asi??? trabajo sobre windows



Miembros de
Miembros de GITCA (Global IT Community Association)

Menu de Usuario
  Iniciar Sesión
  Registrarse
  Restablecer Contraseña
  Ventajas de Registrarse

Acerca de
  Contigo desde Oct 2007
  771 usuarios registrados
  86146 pageloads/mes
  Ranking Alexa 498160

Social Networks
Sigue a Portal GuilleSQL en Linkedin !!
Sigue a Portal GuilleSQL en Twitter !!



Archivo

Marzo de 2019 (1)
Octubre de 2018 (1)
Julio de 2018 (1)
Junio de 2018 (4)
Mayo de 2018 (5)
Abril de 2018 (3)
Marzo de 2018 (2)
Febrero de 2018 (7)
Enero de 2018 (1)
Diciembre de 2017 (15)
Noviembre de 2017 (7)
Junio de 2017 (3)
Mayo de 2017 (1)
Marzo de 2017 (3)
Enero de 2017 (4)
Junio de 2016 (1)
Mayo de 2016 (2)
Abril de 2016 (2)
Septiembre de 2015 (2)
Agosto de 2015 (2)
Junio de 2015 (10)
Mayo de 2015 (4)
Abril de 2015 (8)
Marzo de 2015 (11)
Octubre de 2014 (3)
Septiembre de 2014 (7)
Agosto de 2014 (5)
Julio de 2014 (2)
Mayo de 2014 (4)
Abril de 2014 (4)
Marzo de 2014 (4)
Febrero de 2014 (1)
Enero de 2014 (5)
Diciembre de 2013 (8)
Noviembre de 2013 (2)
Octubre de 2013 (7)
Septiembre de 2013 (6)
Agosto de 2013 (1)
Julio de 2013 (6)
Junio de 2013 (11)
Mayo de 2013 (7)
Abril de 2013 (6)
Febrero de 2013 (5)
Enero de 2013 (7)
Diciembre de 2012 (12)
Noviembre de 2012 (13)
Octubre de 2012 (5)
Septiembre de 2012 (3)
Agosto de 2012 (6)
Julio de 2012 (4)
Junio de 2012 (1)
Mayo de 2012 (2)
Abril de 2012 (7)
Marzo de 2012 (16)
Febrero de 2012 (9)
Enero de 2012 (5)
Diciembre de 2011 (10)
Noviembre de 2011 (10)
Octubre de 2011 (4)
Septiembre de 2011 (5)
Agosto de 2011 (2)
Julio de 2011 (2)
Junio de 2011 (4)
Mayo de 2011 (2)
Abril de 2011 (6)
Marzo de 2011 (4)
Febrero de 2011 (10)
Enero de 2011 (5)
Diciembre de 2010 (6)
Noviembre de 2010 (4)
Octubre de 2010 (8)
Septiembre de 2010 (4)
Agosto de 2010 (1)
Julio de 2010 (3)
Mayo de 2010 (5)
Abril de 2010 (6)
Marzo de 2010 (8)
Febrero de 2010 (3)
Enero de 2010 (1)
Diciembre de 2009 (9)
Noviembre de 2009 (14)
Octubre de 2009 (2)
Septiembre de 2009 (8)
Agosto de 2009 (2)
Julio de 2009 (10)
Junio de 2009 (9)
Mayo de 2009 (10)
Abril de 2009 (9)
Marzo de 2009 (3)
Febrero de 2009 (2)
Enero de 2009 (3)
Noviembre de 2008 (2)
Octubre de 2008 (2)
Septiembre de 2008 (2)
Agosto de 2008 (5)
Julio de 2008 (5)
Junio de 2008 (1)
Mayo de 2008 (3)
Abril de 2008 (2)
Marzo de 2008 (2)
Febrero de 2008 (2)
Enero de 2008 (5)
Noviembre de 2007 (2)
Octubre de 2007 (2)






Copyright © 2007 GuilleSQL, todos los derechos reservados.