Error de archivo WAL duplicado en Barman

Problema

Es posible que, debido a un comportamiento inesperado, Barman reciba por segunda vez un archivo WAL que ya ha sido archivado, generando un error de archivo WAL duplicado. Se trata de un evento raro que (por el momento) no es manejado directamente por Barman y que requiere una intervención manual.

IMPORTANTE: a lo largo de este documento, supondremos que el nombre del servidor en cuestión es angus. Cámbienlo por el nombre real del servidor.

Generalmente, es la misma plataforma de monitoreo en la cual está integrado Barman (por ejemplo, icinga) la que envía con prontitud alertas al presentarse este problema. Lo hace por medio de:

BARMAN CRITICAL - 1 server out of xx have issues * angus FAILED: archiver errors

Como alternativa, este error puede comprobarse de forma manual ejecutando el siguiente comando en el servidor de Barman:

barman check angus

En la salida, la sección archiver errors mostrará la información correspondiente.

Solución

Es necesario inyectar el archivo WAL correcto en el directorio WALs adecuado del servidor en Barman. Esta operación debe realizarse con extremo cuidado.

En caso de que el archivo WAL no presente problemas, no será necesario hacer nada (aparte de limpiar el directorio de trabajo).

De lo contrario, si el archivo presenta problemas, habrá que sustituirlo por el correcto.

En primer lugar, hay que verificar el algoritmo de compresión utilizado con el servidor:

# barman show-server angus | grep compression
	compression: gzip
	custom_compression_filter: None
	custom_decompression_filter: None
	network_compression: False

En este caso, Barman utiliza gzip para la compresión WAL.

A continuación, hará falta entrar en el directorio de trabajo y escribir:

# If you have followed the diagnostic steps, the file now called '00000001000007C9000000CF'
# was previously '00000001000007C9000000CF.20181209T212501Z.duplicate'

gzip 00000001000007C9000000CF 
mv 00000001000007C9000000CF.gz 00000001000007C9000000CF
# Copy the duplicate WAL in the correct directory
cp 00000001000007C9000000CF \
  $(barman show-server angus | grep -P '^\twals_directory' | cut -f 2 -d ':')/00000001000007C9/

La última operación inyecta el fichero WAL comprimido en el archivo.

IMPORTANTE: En base a los comentarios recibidos durante las operaciones de soporte, se añadirá un comando al mismo Barman para la gestión de este (raro) problema.

Pasos de diagnóstico

Preliminares

Preparen en el directorio Barman un directorio de trabajo, como el siguiente, que se utilizará para la investigación durante la resolución del incidente:

mkdir ~/wal-investigation

Asegúrense de que en el servidor donde se ejecuta la investigación esté instalado pg_waldump (o pg_xlogdump), con la misma versión principal que el servidor PostgreSQL que produjo el WAL a verificar.

Desactivar las alertas

En primer lugar, deberán detenerse las alertas, simplemente moviendo el archivo duplicado fuera del directorio de errores (en los valores de configuración de Barman: errors_directory).

Localicen la ruta completa de errors_directory para el servidor en cuestión (en el ejemplo de abajo, angus), con el siguiente comando:

# barman show-server angus | grep directory

backup_directory: /srv/barman/angus
barman_lock_directory: /srv/barman
basebackups_directory: /srv/barman/angus/base
data_directory: /srv/postgresql/data
errors_directory: /srv/barman/angus/errors
incoming_wals_directory: /srv/barman/angus/incoming
streaming_wals_directory: /srv/barman/angus/streaming
wals_directory: /srv/barman/angus/wals

Los archivos WAL en el directorio errors_directory son renombrados automáticamente por Barman, el cual añadirá la marca de tiempo del archivo y el sufijo .duplicate.

Podrá obtenerse la lista de archivos que contienen los errores del servidor angus con el siguiente comando:

find $(barman show-server angus | grep -P '^\terrors_directory' | cut -f 2 -d ':') -type f -name '*.duplicate'

Un ejemplo de archivo duplicado podría ser el siguiente:

00000001000007C9000000CF.20181209T212501Z.duplicate

Esto significa que un archivo WAL llamado 00000001000007C9000000CF había sido previamente archivado.

Para dejar de recibir la alerta, muevan los archivos en el directorio ~/wal-investigation para su posterior análisis. Esta operación se puede automatizar con:

mv $( \
  find $( \
	  barman show-server angus | grep -P '^\terrors_directory' | cut -f 2 -d ':'
	  ) -type f -name '*.duplicate' \
	)	~/wal-investigation

Recuperar el archivo WAL archivado

A continuación, recuperen el archivo WAL archivado de Barman mediante el comando get-wal:

barman get-wal --output-directory ~/wal-investigation angus 00000001000007C9000000CF

El comando get-wal gestionará de forma transparente la descompresión del archivo WAL, según sea necesario.

Comprobar los archivos con pg_waldump

Por último, podrá ejecutarse pg_waldump con el fichero archivado y los duplicados, dentro del directorio ~/wal-investigation.

Sugerimos guardar el resultado en un archivo para su posterior análisis.

Empiecen con el archivado:

pg_waldump 00000001000007C9000000CF &> 00000001000007C9000000CF.archived.txt
mv 00000001000007C9000000CF 00000001000007C9000000CF.archived

Luego con el duplicado (en caso de tener varios archivos con el mismo nombre, hay que repetir la operación para cada uno de ellos):

 mv 00000001000007C9000000CF.20181209T212501Z.duplicate 00000001000007C9000000CF
pg_waldump 00000001000007C9000000CF &> 00000001000007C9000000CF.duplicate.txt

Ahora busquen errores en los archivos de texto (por ejemplo pg_waldump: FATAL: error in WAL record at 7C9/CFFFF858: invalid record length at 7C9/CFFFF8C8: wanted 24, got 0).

Para una comparación línea por línea se puede utilizar el comando diff, por ejemplo:

diff 00000001000007C9000000CF.*.txt

Causa del problema

Cuando barman recibe un archivo WAL (ya sea en el subdirectorio de streaming o de entrada) con el mismo nombre pero un checksum MD5 distinto al de uno que ya ha sido archivado, lo pondrá dentro del subdirectorio errors para ese servidor.

IMPORTANTE: El archivo que barman mueve en el directorio de errores es simplemente el último que llegó, no necesariamente el defectuoso.

El motivo suele pertenecer a cualquiera de estas categorías:

  • caída anormal del servidor PostgreSQL de origen, que causó que el primer archivo WAL se corrompiera
  • inyección de WAL desde un servidor PostgreSQL incorrecto (generalmente por haber definido un directorio de entrada incorrecto en el script archive_command)