Postgresql

El Point In Time Recovery (PITR) o backup continuo es una funcionalidad cada día mas interesante, pues nos permite recuperar los datos de nuestra base de datos minutos antes de un desastre lógico.

WAL-E es una herramienta para conseguir backup continuo de postgresql con almacenamiento en el sistema de Amazon S3. Utiliza un paquete python con diversas utilidades de consola para operar con los backups y subir los ficheros necesarios al bucket.

Backups

Con WAL-E podemos hacer dos backups diferentes, el de los archivos WAL con todas la transacciones que se van realizando y el de pg_basebackups de postgresql.

Para los archivos WAL se debe cambiar la configuración de postgresql y en adelante utilice el comando wal-e necesario para ir subiendo los ficheros.

Para los basebackups, wal-e proporciona un comando que se encarga de la operación en postgresql y subir el fichero resultante. Este comando deberemos ejecutarlo periódicamente.

Con estos dos backups juntos podemos restaurar a cualquier punto en el tiempo, pues tenemos todo el registro de transacciones que ha ocurrido. La dependencia entre los dos backup es fuerte, es necesario siempre un basebackup como origen para poder restaurar las transacciones del WAL y no podremos restaurar transacciones que no se correspondan con su basebackup. La restauración de un basebackup sin tener los WAL es posible, pero no lo és la restauración de los WALs sin tener su basebackup correspondiente.

Instalación

La instalación de wal-e es sencilla, está empaqueta en PyPI y es suficiente con hacer:

$ pip install wal-e

Aunque wal-e también permite almacenar en Swift o Azure, voy a explicar cómo lo hacemos subiendo a Amazon S3.

Para la conexión con Amazon S3 wal-e utiliza la librería de python boto, que es fácilmente configurable via variables de entorno con la credenciales que tengamos de acceso.

Para facilitar la configuración de estas variables de entorno accesibles por todos los procesos involucrados, wal-e propone la utilización de otra herramienta python llamada envdir, que recoge por parámetro la ruta a un directorio para establecer los ficheros que contenga como variables de entorno.

Así pues, configuramos la ruta /etc/wal-e.d/env/ con la acreditación necesaria para conectar a un bucket:

 /etc/wal-e.d/env $ ls -tlr
-rwxr--r-- 1 root postgres 21 Mar 30 16:25 AWS_ACCESS_KEY_ID
-rwxr--r-- 1 root postgres 41 Mar 30 16:26 AWS_SECRET_ACCESS_KEY
-rwxr--r-- 1 root postgres 48 Mar 30 16:40 WALE_S3_PREFIX
-rwxr--r-- 1 root postgres 44 Mar 30 17:23 WALE_S3_ENDPOINT

/etc/wal-e.d/env $ cat WALE_S3_PREFIX
s3://nombre_del_bucket/directorio

/etc/wal-e.d/env $ cat WALE_S3_ENDPOINT
https+path://s3-eu-west-1.amazonaws.com:443

Configuración postgresql

En el archivo de configuración de nuestro postgresql deberemos retocar estas variables:

wal_level = archive 
archive_mode = on
archive_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e wal-push %p'
archive_timeout = 1800

Donde archive_command indica a postgres que utilice wal-e para archivar los ficheros WAL. Con archive_timeout escogemos cada cuando tiempo (en segundos) cerrar un fichero WAL y archivarlo, es decir, subirlo a S3. Este valor dependerá de cada caso, pero teniendo en cuenta un número excesivamente bajo afectará al rendimiento del postgresql.

Es necesario reiniciar el servicio postgresql tras los cambios, no es suficiente con un reload del servicio. En los logs de postgresql podremos ver como se suben los ficheros con el comando de wal-e push y ver si ha ocurrido algún error.

Configuración crons

En el usuario postgres del servidor dejaremos configurado un cron de usuario para que se vayan subiendo los basebackups necesarios cada día. Este comando ya se encarga de conectar a postgresql y realizar las operaciones necesarias al empezar la copia y terminarla.

30 0 * * * /usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e backup-push /var/lib/postgresql/9.5

También podemos configurar otro cron, con el comando wal-e delete para que vaya borrando los backups viejos y configurar la retención, en este ejemplo 30 días:

0 2 * * * /usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e delete --confirm retain 30

Operaciones

Listar los backups

Wal-e proporciona una manera de saber que backups hay disponibles con el comando backup-list.

postgres@host$ /usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e backup-list
wal_e.main   INFO     MSG: starting WAL-E
        DETAIL: The subcommand is "backup-list".
        STRUCTURED: time=2016-04-05T13:04:18.412986-00 pid=25152
name    last_modified   expanded_size_bytes     wal_segment_backup_start        wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop
base_000000010000000000000082_00000040  2016-03-30T15:24:40.000Z                000000010000000000000082        00000040
base_000000010000000000000084_00000040  2016-03-30T15:25:42.000Z                000000010000000000000084        00000040
base_0000000100000000000000DB_00000040  2016-03-30T22:30:13.000Z                0000000100000000000000DB        00000040
base_0000000100000001000000FC_00000040  2016-03-31T22:30:15.000Z                0000000100000001000000FC        00000040
base_00000001000000030000001D_00000040  2016-04-01T22:30:14.000Z                00000001000000030000001D        00000040
base_00000001000000040000003E_00000040  2016-04-02T22:30:12.000Z                00000001000000040000003E        00000040
base_00000001000000050000005F_00000040  2016-04-03T22:30:15.000Z                00000001000000050000005F        00000040
base_000000010000000600000080_00000040  2016-04-04T22:30:14.000Z                000000010000000600000080        00000040

Recuperar un backup

  • El servidor debe estar configurado con wal-e para poder recuperar y nos aseguramos que el servicio de postgresql esté parado.
  • Nos logueamos con el usuario postgres
  • Borramos o movemos el directorio de datos de postgresql:
mv /var/lib/postgresql/9.5/main /var/lib/postgresql/9.5/main_old
  • Ejecutamos el comando fetch para traer un backup. Podemos escoger un backup del listado (name) o LATEST para el último.
/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e backup-fetch /var/lib/postgresql base_000000010000000000000082_00000040
  • Preparamos un fichero para que postgresql sepa cómo recuperar con wal-e. En este punto podemos escoger en qué punto en el tiempo restaurar con el parámetro recovery_target_time.
$ cat /etc/postgresql/9.5/main/recovery.conf
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e wal-fetch "%f" "%p"'
#recovery_target_time = '2016-04-08 09:07:00'
#recovery_target_time = 'latest'
  • Corregimos los permisos de los directorios que se han traído del basebackup:
chown -R postgres:postgres /var/lib/postgresql/9.5/main
$ chmod 0700 /var/lib/postgresql/9.5/main
  • Ya podemos iniciar el servicio de postgresql. En este punto empezará a traer de s3 y restaurar archivos WAL de transacciones hasta llegar a recovery_target_time. (O otro setting que hayamos escogido)

Conclusiones

A veces, desarrollando una aplicación, poder utilizar una copia de datos de un punto en el tiempo otorga una ventaja importante a la hora de resolver o encontrar un problema complicado. Existen otras posibilidades de backup continuo en servidor como Barman, pero según nuestra experiencia, wal-e encaja mejor en muchos casos por su simpleza, pues al no necesitar servidor cuenta con otro punto de fallo menos.

Para terminar os dejo en la mesa otra idea que puede resultar interesante: la de utilizar un usuario de lectura del mismo bucket de backup, para que un entorno de desarrollo o pre-producción inicie con una copia lo más fresca posible de los datos de producción.

blog comments powered by Disqus