¿Por qué pg_wal (pg_xlog) se está llenando?

Problema

A veces, los archivos comienzan a acumularse en el directorio pg_wal (o pg_xlog en las versiones de PostgreSQL anteriores a la 10).

Esto puede deberse a un aumento repentino y temporal de la carga de trabajo transaccional (por ejemplo, cuando se programa un VACUUM a una hora fija o cuando ocurren los cierres del día). En estos casos, lo único que hay que hacer es monitorear la situación y esperar a que disminuya la carga de trabajo. Generalmente esto ocurre a horas específicas y es fácil de identificar la causa.

Sin embargo hay casos, en que algún problema adicional esté causando este fenómeno. Por lo que podría ser una buena idea investigarlo si no se soluciona en un tiempo razonable o cuando la ocurrencia es impredecible. En estos casos, de no detectar y arreglar el problema a tiempo puede ocurrir que los archivos sigan acumulándose hasta que el disco se llene, y a partir de ese momento no se ejecutarán más transacciones, lo cual llevará a un tiempo de inactividad.

Nunca eliminen archivos directamente de pg_walpg_xlogpg_clog, etc. ¡Se corromperá la base de datos!

Causa del problema

Las situaciones más comunes en las que se produce este fenómeno son:

  1. Un slot de replicación inactivo (Importante: ¡No lo eliminen! Vean más abajo)
  2. Un comando de archivado continuo (archive_command) que está fallando
  3. Valores excesivos de min_wal_size y max_wal_size (en la versión 9.4 y anteriores, checkpoint_segments) o wal_keep_size (en la versión 12 y anteriores, wal_keep_segments)
  4. Fallos en los puntos de control (checkpoint) que impidan la eliminación del WAL

Soluciones

Slots de replicación

Importante: Nunca eliminen un slot de replicación sin saber para qué sirve, aunque no aparezca como "activo".

Los slots de replicación se aseguran de que un servidor primario u origen de datos no elimine un archivo WAL hasta que los clientes conectados (servidores de réplica física o lógica) hayan utilizado sus datos. Si la réplica no está activa, quizá por que se apagó para un mantenimiento programado, PostgreSQL preservará los archivos WAL hasta que el slot se active de nuevo o sea eliminado.

Para determinar si un slot de replicación por el momento no está siendo utilizado (inactivo), utilicen esta consulta:

SELECT * FROM pg_replication_slots;

    slot_name   | plugin | slot_type | datoid | database | active |    xmin    | catalog_xmin |  restart_lsn  
  --------------+--------+-----------+--------+----------+--------+------------+--------------+---------------
   slot_node30  |        | physical  |        |          | t      | 3557567510 |              | 3705/2A440EC8
   slot_node209 |        | physical  |        |          | t      | 3557569748 |              | 3705/2A440EC8
   slot_node21  |        | physical  |        |          | t      | 3557562449 |              | 3705/2A440EC8
   slot_node53  |        | physical  |        |          | f      | 3545071332 |              | 36DF/7C7E0000
   slot_node32  |        | physical  |        |          | t      | 3545071332 |              | 3705/2A440EC8

  (5 rows)

Noten que hay un slot marcado como inactivo (active = 'f'). Además, su valor de restartlsn es muy inferior a los otros valores. Esto puede significar que el slot de replicación ya no es necesario, aunque esto debería verificarse de forma concluyente antes de eliminarlo. Si el slot sigue siendo necesario para un nodo o un servicio que está temporalmente fuera de línea, o que está presentando un error, etc, entonces eliminarlo puede perjudicar irremediablemente el funcionamiento de ese nodo o servicio. Especialmente en sistemas con arquitecturas complejas de replicación (como las que pueden lograrse con la replicación lógica nativa, pglogical u otras) es vital que no se eliminen slots sin una comprobación muy cuidadosa.

Si están absolutamente seguros de que el slot ya no es requerido por ningún servicio o nodo existente pueden eliminarlo con: SELECT pg_drop_replication_slot('slot_node53')

Si es Barman quien ha solicitado ese slot de replicación, pueden reanudar el flujo de WAL o eliminar los slots de replicación. En el primer caso, se debe chequear que el parámetro streaming_archiver en el servidor barman está en on luego de eso el comando barman cron se encargará del resto. En cambio, si es necesario eliminar el slot, se puede utilizar el comando barman receive-wal --drop-slot [SERVER_ID].

Archivado continuo de WAL con archive_command

A partir de PostgreSQL 9.4, es posible diagnosticar problemas con el archivado continuo a través de la siguiente consulta:

SELECT *,
    current_setting('archive_mode')::BOOLEAN
        AND (last_failed_wal IS NULL
            OR last_failed_wal <= last_archived_wal)
        AS is_archiving
    FROM pg_stat_archiver;

Si la columna calculada is_archiving que aparece en la consulta anterior tiene el valor false hay un problema en el archivado.

Previo a 9.4 la única forma de saber si el archivado esta fallando es analizando los registros del servidor. Un archive_command que no funcione reportará un error similar al siguiente:

FATAL: archive command failed with exit code 25 
DETAIL:  The failed archive command was: /usr/bin/scp -B /Volumes/DataDrive/data/pg_xlog/000000010000007400000086 postgres@10.0.204.55:/Volumes/DataDrive/wals_from_master/000000010000007400000086
LOG:  archiver process (PID 17771) exited with exit code 1

El siguiente comando grep puede facilitar la detección de errores de archive_command en un archivo de registro de mayor tamaño: grep -C10 'FATAL: archive command failed with'.

Si se utiliza Barman para realizar respaldos, hay que asegurarse de que exista suficiente espacio disponible en el sistema y que el comando barman check devuelva SUCCESS.

Existen dos opciones:

  1. Solucionar la condición que está causando el fallo del comando (por ejemplo, montar una partición de red, liberar espacio en una partición remota o en el servidor de respaldos, o instalar claves SSH para permitir el acceso no interactivo, etc.)
  2. Eliminar el comando de archivado (archive_command) y configurar algo que siempre funcione como 'exit 0'. Hay que considerar que esto detendrá el archivado y, por lo tanto, cualquier réplica o solución de respaldo que no sea en flujo y que dependa del archivado, dejará de funcionar. Si la operación es temporal, esto provocaría una ruptura en la ventana de recuperabilidad de la solución de recuperación ante desastres.

No borren los archivos WAL directamente.

Configuración de retención de WAL excesiva

PostgreSQL puede ser configurado para retener WAL extra en pg_wal (pg_xlog en versiones anteriores). Esto resulta necesario para permitir que las réplicas físicas en flujo que no están utilizando slots de replicación físicos funcionen correctamente si se retrasan con respecto al maestro o si sus conexiones se interrumpen. Sin un slot físico que indique al maestro que debe guardar WAL para ellas, será eliminado cuando el maestro ya no lo requiera.

La opción wal_keep_size (wal_keep_segments en versión 12 y anteriores) controla esta retención adicional de WAL. Si no es posible averiguar la razón por la que se retiene el WAL (y no se debe a un slot muy retrasado o a un archivo que esté fallando) comprueben si la retención es razonable para la cantidad de espacio disponible en pg_wal.

Si se utilizan únicamente réplicas con slots de replicación, o si se dispone de un archive_command y las réplicas contienen un restore_command que utiliza el archivo wal, no será necesario ningún wal_keep_size.

Problemas de configuración de los puntos de control

PostgreSQL permite controlar el momento en que se realiza un checkpoint del sistema. Un punto de control asegura que todo el WAL anterior al punto de control se aplique por completo, sincroniza varias cachés y búferes, y luego elimina o recicla el WAL obsoleto.

Los puntos de control que se ejecutan con demasiada frecuencia pueden causar problemas de rendimiento (como detener las operaciones de E/S) por lo que a menudo se configuran para que sean distribuidos. Sin embargo, si se permite que los puntos de control se ejecuten con demasiada frecuencia, el servidor puede ser incapaz de mantener el ritmo de generación de nuevos WAL, especialmente cuando se realizan escrituras muy pesadas.

Lo que activa el límite de tamaño de WAL para un punto de control forzado es la opción max_wal_size( en PostgreSQL 9.5 y versiones superiores), y min_wal_size para la cantidad de WAL que se debe mantener para el reciclaje. En 9.4 y versiones anteriores el límite de puntos de control es controlado por checkpoint_segments.

Si estos valores son demasiado elevados, es posible que el sistema no compense correctamente la acumulación de WAL.

Fallos en los puntos de control

También es posible que los puntos de control fallen cuando algo no funciona en PostgreSQL. Si los puntos de control fallan, PostgreSQL no podrá eliminar el WAL que se acumulará en pg_wal.

Revisen si existe algún error en los registros de PostgreSQL relacionado con los puntos de control.

Puede activarse también la opción de configuración log_checkpoints.

Puede ser instructivo forzar un punto de control con el comando SQL CHECKPOINT; y observar qué ocurre.

Pueden comprobar cuándo se produjo el último punto de control con éxito utilizando pg_controldata (a menos que se trate de un sistema cerrado en el que no tengan acceso al directorio de datos).