25.3. Archivado continuo y recuperación diferida en el tiempo (PITR) #

25.3.1. Configuración del archivado de WAL
25.3.2. Realización de un respaldo base
25.3.3. Realización de un respaldo incremental
25.3.4. Realización de un respaldo base utilizando la API de bajo nivel
25.3.5. Recuperación mediante un respaldo de archivo continuo
25.3.6. Líneas de tiempo
25.3.7. Consejos y ejemplos
25.3.8. Advertencias

En todo momento, PostgreSQL mantiene un registro de escritura anticipada (write ahead log - WAL) en el subdirectorio pg_wal/ del directorio de datos del clúster. El registro registra cada cambio realizado en los archivos de datos de la base de datos. Este registro existe principalmente para fines de seguridad ante fallos: si el sistema falla, la base de datos puede restaurarse a un estado consistente «reproduciendo» las entradas del registro realizadas desde el último punto de control (checkpoint). Sin embargo, la existencia del registro hace posible utilizar una tercera estrategia para respaldar bases de datos: podemos combinar un respaldo a nivel del sistema de archivos con el respaldo de los archivos WAL. Si se necesita una recuperación, restauramos el respaldo del sistema de archivos y luego reproducimos los archivos WAL respaldados para llevar el sistema a un estado actual. Este enfoque es más complejo de administrar que cualquiera de los enfoques anteriores, pero tiene algunos beneficios significativos:

Note

pg_dump and pg_dumpall no producen respaldos a nivel de sistema de archivos y no se pueden utilizar como parte de una solución de archivado continuo. Dichos volcados son lógicos y no contienen suficiente información para ser utilizados por la reproducción de WAL.

Al igual que con la técnica de respaldo simple del sistema de archivos, este método solo admite la restauración de un clúster de bases de datos completo, no un subconjunto. También requiere mucho almacenamiento de archivo: el respaldo base puede ser voluminoso, y un sistema con mucha actividad generará muchos megabytes de tráfico WAL que deben archivarse. Aun así, es la técnica de respaldo preferida en muchas situaciones donde se necesita una alta confiabilidad.

Para recuperarte con éxito utilizando el archivado continuo (también llamado «respaldo en línea» por muchos proveedores de bases de datos), necesitas una secuencia continua de archivos WAL archivados que se extienda al menos hasta la hora de inicio de tu respaldo. Por lo tanto, para comenzar, debes configurar y probar tu procedimiento para archivar archivos WAL antes de tomar tu primer respaldo base. En consecuencia, primero discutiremos la mecánica del archivado de archivos WAL.

25.3.1. Configuración del archivado de WAL #

En un sentido abstract, un sistema PostgreSQL en ejecución produce una secuencia indefinidamente larga de registros WAL. El sistema divide físicamente esta secuencia en archivos de segmento WAL, que normalmente son de 16MB cada uno (aunque el tamaño del segmento se puede alterar durante initdb). A los archivos de segmento se les asignan nombres numéricos que reflejan su posición en la secuencia WAL abstracta. Cuando no se utiliza el archivado de WAL, el sistema normalmente crea solo unos pocos archivos de segmento y luego los «recicla» renombrando los archivos de segmento que ya no se necesitan con números de segmento más altos. Se asume que los archivos de segmento cuyos contenidos preceden al último punto de control ya no son de interés y se pueden reciclar.

Al archivar datos WAL, necesitamos capturar el contenido de cada archivo de segmento una vez que se llena, y guardar esos datos en algún lugar antes de que el archivo de segmento se recicle para su reutilización. Dependiendo de la aplicación y del hardware disponible, podría haber muchas formas diferentes de «guardar los datos en algún lugar»: podríamos copiar los archivos de segmento a un directorio montado por NFS en otra máquina, escribirlos en una unidad de cinta (asegurándote de tener una forma de identificar el nombre original de cada archivo), o agruparlos y grabarlos en CDs, o cualquier otra cosa. Para proporcionar flexibilidad al administrador de la base de datos, PostgreSQL intenta no hacer suposiciones sobre cómo se realizará el archivado. En su lugar, PostgreSQL permite al administrador especificar un comando de shell o una biblioteca de archivado para que se ejecute con el fin de copiar un archivo de segmento completado a donde sea necesario. Esto podría ser tan sencillo como un comando de shell que use cp, o podría invocar una función C compleja; todo depende de ti.

Para habilitar el archivado de WAL, establece el parámetro de configuración wal_level en replica o superior, archive_mode en on, especifica el comando de shell a utilizar en el parámetro de configuración archive_command o especifica la biblioteca a utilizar en el parámetro de configuración archive_library. En la práctica, estas configuraciones siempre se colocarán en el archivo postgresql.conf.

In archive_command, %p se reemplaza por la ruta del archivo a archivar, mientras que %f se reemplaza solo por el nombre del archivo. (La ruta es relativa al directorio de trabajo actual, es decir, el directorio de datos del clúster). Usa %% si necesitas incrustar un carácter % real en el comando. El comando útil más sencillo es algo como:

archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'  # Unix
archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"'  # Windows

que copiará los segmentos WAL archivables al directorio /mnt/server/archivedir. (Este es un ejemplo, no una recomendación, y podría no funcionar en todas las plataformas). Después de reemplazar los parámetros %p y %f, el comando real ejecutado podría verse así:

test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065

Se generará un comando similar para cada nuevo archivo a archivar.

El comando de archivo se ejecutará bajo la propiedad del mismo usuario con el que se ejecuta el servidor PostgreSQL. Dado que la serie de archivos WAL que se están archivando contiene prácticamente todo lo que hay en tu base de datos, querrás asegurarte de que los datos archivados estén protegidos de miradas indiscretas; por ejemplo, archívalos en un directorio que no tenga acceso de lectura para el grupo o para todo el mundo.

Es importante que el comando de archivo devuelva un estado de salida cero si y solo si tiene éxito. Al obtener un resultado cero, PostgreSQL asumirá que el archivo se ha archivado correctamente y lo eliminará o reciclará. Sin embargo, un estado distinto de cero le dice a PostgreSQL que el archivo no se archivó; lo intentará de nuevo periódicamente hasta que tenga éxito.

Otra forma de archivar es utilizar un módulo de archivo personalizado como archive_library. Dado que tales módulos se escriben en C, crear uno propio puede requerir un esfuerzo considerablemente mayor que escribir un comando de shell. Sin embargo, los módulos de archivo pueden ser más eficientes que el archivado a través de shell, y tendrán acceso a muchos recursos útiles del servidor. Para obtener más información sobre los módulos de archivo, consulta Chapter 49.

Cuando el comando de archivo es terminado por una señal (que no sea SIGTERM, que se utiliza como parte de un apagado del servidor) o por un error del shell con un estado de salida superior a 125 (como comando no encontrado), o si la función de archivo emite un ERROR o FATAL, el proceso archivador se aborta y el postmaster lo reinicia. En tales casos, el fallo no se reporta en la vista pg_stat_archiver.

Los comandos y bibliotecas de archivo generalmente deben diseñarse para rechazar la sobrescritura de cualquier archivo de archivo preexistente. Esta es una característica de seguridad importante para preservar la integridad de tu archivo en caso de error del administrador (como enviar la salida de dos servidores diferentes al mismo directorio de archivo). Es aconsejable probar la biblioteca de archivo propuesta para asegurarse de que no sobrescriba un archivo existente.

En casos raros, PostgreSQL puede intentar volver a archivar un archivo WAL que ya fue archivado previamente. Por ejemplo, si el sistema falla antes de que el servidor realice un registro duradero del éxito del archivado, el servidor intentará archivar el archivo nuevamente después de reiniciar (siempre que el archivado aún esté habilitado). Cuando un comando o biblioteca de archivo encuentra un archivo preexistente, debe devolver un estado cero o true, respectivamente, si el archivo WAL tiene un contenido idéntico al archivo preexistente y este último está completamente guardado en el almacenamiento. Si un archivo preexistente contiene un contenido diferente al del archivo WAL que se está archivando, el comando o biblioteca de archivo debe devolver un estado distinto de cero o false, respectivamente.

El comando de ejemplo anterior para Unix evita sobrescribir un archivo preexistente al incluir un paso de test separado. En algunas plataformas Unix, cp tiene modificadores como -i que se pueden usar para hacer lo mismo de manera menos verbosa, pero no debes confiar en ellos sin verificar que se devuelva el estado de salida correcto. (En particular, GNU cp devolverá el estado cero cuando se usa -i y el archivo de destino ya existe, lo cual no es el comportamiento deseado).

Al diseñar tu configuración de archivado, considera qué sucederá si el comando o biblioteca de archivo falla repetidamente porque algún aspecto requiere la intervención del operador o porque el archivo se queda sin espacio. Por ejemplo, esto podría ocurrir si escribes en cinta sin un autocambiador; cuando la cinta se llene, no se podrá archivar nada más hasta que se cambie la cinta. Debes asegurarte de que cualquier condición de error o solicitud a un operador humano se reporte adecuadamente para que la situación se pueda resolver con relativa rapidez. El directorio pg_wal/ continuará llenándose con archivos de segmento WAL hasta que se resuelva la situación. (Si el sistema de archivos que contiene pg_wal/ se llena, PostgreSQL realizará un apagado PANIC. No se perderá ninguna transacción confirmada, pero la base de datos permanecerá fuera de línea hasta que liberes algo de espacio).

La velocidad del comando o biblioteca de archivo no es importante siempre que pueda mantener el ritmo promedio con el que tu servidor genera datos WAL. El funcionamiento normal continúa incluso si el proceso de archivado se retrasa un poco. Si el archivado se retrasa significativamente, esto aumentará la cantidad de datos que se perderían en caso de un desastre. También significará que el directorio pg_wal/ contendrá una gran cantidad de archivos de segmento aún no archivados, lo que eventualmente podría exceder el espacio en disco disponible. Se te aconseja monitorear el proceso de archivado para asegurarte de que funcione como deseas.

Al escribir tu comando o biblioteca de archivo, debes asumir que los nombres de los archivos a archivar pueden tener hasta 64 caracteres de largo y pueden contener cualquier combinación de letras ASCII, dígitos y puntos. No es necesario preservar la ruta relativa original (%p) pero sí es necesario conservar el nombre del archivo (%f).

Ten en cuenta que, aunque el archivado de WAL te permitirá restaurar cualquier modificación realizada en los datos de tu base de datos de PostgreSQL, no restaurará los cambios realizados en los archivos de configuración (es decir, postgresql.conf, pg_hba.conf y pg_ident.conf), ya que estos se editan manualmente en lugar de mediante operaciones SQL. Es posible que desees mantener los archivos de configuración en una ubicación que esté cubierta por tus procedimientos regulares de respaldo del sistema de archivos. Consulta Section 19.2 para saber cómo reubicar los archivos de configuración.

El comando o función de archivo solo se invoca en los segmentos WAL completados. Por lo tanto, si tu servidor genera poco tráfico WAL (o tiene períodos de inactividad donde lo hace), podría haber un largo retraso entre la finalización de una transacción y su registro seguro en el almacenamiento de archivo. Para poner un límite a la antigüedad de los datos no archivados, puedes establecer el parámetro archive_timeout para obligar al servidor a cambiar a un nuevo archivo de segmento WAL al menos con esa frecuencia. Ten en cuenta que los archivos archivados prematuramente debido a un cambio forzado siguen teniendo la misma longitud que los archivos completamente llenos. Por lo tanto, no es aconsejable establecer un archive_timeout muy corto; inflará tu almacenamiento de archivo. Las configuraciones de archive_timeout de un minuto más o menos suelen ser razonables.

Además, puedes forzar un cambio de segmento manualmente con pg_switch_wal si deseas asegurarte de que una transacción recién finalizada se archive lo antes posible. En el cuadro Table 9.97 se enumeran otras funciones de utilidad relacionadas con la gestión de WAL.

Cuando wal_level is minimal, algunos comandos SQL se optimizan para evitar el registro WAL, como se describe en Section 14.4.7. Si el archivado o la replicación en streaming se activaran durante la ejecución de una de estas sentencias, WAL no contendría suficiente información para la recuperación de archivos. (La recuperación de fallos no se ve afectada). Por esta razón, wal_level solo se puede cambiar al iniciar el servidor. Sin embargo, archive_command y archive_library se pueden cambiar al recargar el archivo de configuración. Si estás archivando a través de shell y deseas detener temporalmente el archivado, una forma de hacerlo es establecer archive_command como una cadena vacía (''). Esto hará que los archivos WAL se acumulen en pg_wal/ hasta que se vuelva a establecer un archive_command que funcione.

25.3.2. Realización de un respaldo base #

La forma más sencilla de realizar un respaldo base es utilizar la herramienta pg_basebackup. Puede crear un respaldo base ya sea como archivos normales o como un archivo tar. Si se requiere más flexibilidad de la que puede proporcionar pg_basebackup, también puedes realizar un respaldo base utilizando la API de bajo nivel (consulta Section 25.3.4).

No es necesario preocuparse por la cantidad de tiempo que se tarda en realizar un respaldo base. Sin embargo, si normalmente ejecutas el servidor con full_page_writes desactivado, es posible que notes una disminución del rendimiento mientras se ejecuta el respaldo, ya que full_page_writes se fuerza eficazmente durante el modo de respaldo.

Para hacer uso del respaldo, necesitarás conservar todos los archivos de segmento WAL generados durante y después del respaldo del sistema de archivos. Para ayudarte a hacer esto, el proceso de respaldo base crea un archivo de historial de respaldo (backup history file) que se almacena inmediatamente en el área de archivo WAL. Este archivo lleva el nombre del primer archivo de segmento WAL que necesitas para el respaldo del sistema de archivos. Por ejemplo, si el archivo WAL inicial es 0000000100001234000055CD, el archivo de historial de respaldo se llamará algo así como 0000000100001234000055CD.007C9330.backup. (La segunda parte del nombre del archivo representa una posición exacta dentro del archivo WAL y normalmente se puede ignorar). Una vez que hayas archivado de forma segura el respaldo del sistema de archivos y los archivos de segmento WAL utilizados durante el respaldo (como se especifica en el archivo de historial de respaldo), todos los segmentos WAL archivados con nombres numéricamente inferiores ya no son necesarios para recuperar el respaldo del sistema de archivos y se pueden eliminar. Sin embargo, deberías considerar conservar varios conjuntos de respaldo para estar absolutamente seguro de que puedes recuperar tus datos.

El archivo de historial de respaldo es solo un pequeño archivo de texto. Contiene la etiqueta que le diste a pg_basebackup, así como las horas de inicio y fin y los segmentos WAL del respaldo. Si utilizó la etiqueta para identificar el archivo de volcado asociado, entonces el archivo de historial archivado es suficiente para indicarte qué archivo de volcado restaurar.

Dado que tienes que conservar todos los archivos WAL archivados desde tu último respaldo base, el intervalo entre respaldos base normalmente debería elegirse en función de la cantidad de almacenamiento que desees gastar en archivos WAL archivados. También debes considerar cuánto tiempo estás dispuesto a pasar recuperando, en caso de que sea necesario realizar la recuperación; el sistema tendrá que reproducir todos esos segmentos WAL, y eso podría llevar un tiempo si ha pasado mucho tiempo desde el último respaldo base.

25.3.3. Realización de un respaldo incremental #

Puedes usar pg_basebackup para tomar un respaldo incremental especificando la opción --incremental. Debes proporcionar, como argumento para --incremental, el manifiesto de respaldo de un respaldo anterior del mismo servidor. En el respaldo resultante, los archivos que no son de relación se incluirán en su totalidad, pero algunos archivos de relación pueden reemplazarse por archivos incrementales más pequeños que contienen solo los bloques que han cambiado desde el respaldo anterior y los metadatos suficientes para reconstruir la versión actual del archivo.

Para determinar qué bloques deben respaldarse, el servidor utiliza resúmenes de WAL, que se almacenan en el directorio de datos, dentro del directorio pg_wal/summaries. Si los archivos de resumen requeridos no están presentes, fallará el intento de realizar un respaldo incremental. Los resúmenes presentes en este directorio deben cubrir todos los LSN desde el LSN de inicio del respaldo anterior hasta el LSN de inicio del respaldo actual. Dado que el servidor busca resúmenes de WAL justo después de establecer el LSN de inicio del respaldo actual, es probable que los archivos de resumen necesarios no estén presentes instantáneamente en el disco, pero el servidor esperará a que aparezcan los archivos faltantes. Esto también ayuda si el proceso de resumen de WAL se ha retrasado. Sin embargo, si los archivos necesarios ya se han eliminado, o si el resumidor de WAL no se pone al día lo suficientemente rápido, el respaldo incremental fallará.

Al restaurar un respaldo incremental, será necesario tener no solo el respaldo incremental en sí, sino también todos los respaldos anteriores que se requieren para proporcionar los bloques omitidos del respaldo incremental. Consulta pg_combinebackup para obtener más información sobre este requisito. Ten en cuenta que existen restricciones sobre el uso de pg_combinebackup cuando se ha cambiado el estado de las sumas de comprobación (checksums) del clúster; consulta las limitaciones de pg_combinebackup.

Ten en cuenta que todos los requisitos para hacer uso de un respaldo completo también se aplican a un respaldo incremental. Por ejemplo, sigues necesitando todos los archivos de segmento WAL generados durante y después del respaldo del sistema de archivos, y cualquier archivo de historial WAL relevante. Y sigues necesitando crear un archivo recovery.signal (o standby.signal) y realizar la recuperación, como se describe en Section 25.3.5. El requisito de tener disponibles los respaldos anteriores en el momento de la restauración y de utilizar pg_combinebackup es un requisito adicional sobre todo lo demás. Ten en cuenta que PostgreSQL no tiene un mecanismo incorporado para determinar qué respaldos se siguen necesitando como base para restaurar respaldos incrementales posteriores. Debes hacer un seguimiento de las relaciones entre tus respaldos completos e incrementales por tu cuenta, y asegurarte de no eliminar los respaldos anteriores si pudieran ser necesarios al restaurar respaldos incrementales posteriores.

Los respaldos incrementales normalmente solo tienen sentido para bases de datos relativamente grandes donde una parte significativa de los datos no cambia, o cambia lentamente. Para una base de datos pequeña, es más sencillo ignorar la existencia de respaldos incrementales y simplemente tomar respaldos completos, que son más fáciles de administrar. Para una base de datos grande que se modifica mucho en su totalidad, los respaldos incrementales no serán mucho más pequeños que los respaldos completos.

Un respaldo incremental solo es posible si la reproducción comenzara desde un punto de control posterior al del respaldo anterior del que depende. Si tomas el respaldo incremental en el servidor primario, esta condición siempre se cumple, porque cada respaldo desencadena un nuevo punto de control. En un servidor en espera (standby), la reproducción comienza desde el punto de reinicio (restartpoint) más reciente. Por lo tanto, un respaldo incremental de un servidor en espera puede fallar si ha habido muy poca actividad desde el respaldo anterior, ya que es posible que no se haya creado ningún punto de reinicio nuevo.

25.3.4. Realización de un respaldo base utilizando la API de bajo nivel #

En lugar de tomar un respaldo base completo o incremental utilizando pg_basebackup, puedes tomar un respaldo base utilizando la API de bajo nivel. Este procedimiento contiene algunos pasos más que el método pg_basebackup, pero es relativamente sencillo. Es muy importante que estos pasos se ejecuten en secuencia, y que se verifique el éxito de un paso antes de proceder al siguiente.

Se pueden ejecutar múltiples respaldos simultáneamente (tanto los que se inician con esta API de respaldo como los que se inician con pg_basebackup).

  1. Asegúrate de que el archivado de WAL esté habilitado y funcione.

  2. Conéctate al servidor (no importa a qué base de datos) como un usuario con derechos para ejecutar pg_backup_start (superuser, o un usuario al que se le haya concedido EXECUTE en la función) y emite el comando:

    SELECT pg_backup_start(label => 'label', fast => false);
    

    donde label es cualquier cadena que quieras utilizar para identificar de forma única esta operación de respaldo. La conexión que llama a pg_backup_start debe mantenerse hasta el final del respaldo, o este se abortará automáticamente.

    Los respaldos en línea siempre se inician al principio de un punto de control. Por defecto, pg_backup_start esperará a que se complete el próximo punto de control programado regularmente, lo que puede llevar mucho tiempo (consulta los parámetros de configuración checkpoint_timeout y checkpoint_completion_target). Esto suele ser preferible, ya que minimiza el impacto en el sistema en ejecución. Si deseas iniciar el respaldo lo antes posible, pasa true como segundo parámetro a pg_backup_start y solicitará un punto de control inmediato, que terminará lo más rápido posible utilizando la mayor cantidad de E/S posible.

  3. Realiza el respaldo utilizando cualquier herramienta de respaldo del sistema de archivos conveniente, como tar o cpio (not pg_dump o pg_dumpall). No es necesario ni deseable detener el funcionamiento normal de la base de datos mientras haces esto. Consulta Section 25.3.4.1 para conocer los aspectos a tener en cuenta durante este respaldo.

  4. En la misma conexión que antes, emite el comando:

    SELECT * FROM pg_backup_stop(wait_for_archive => true);
    

    Esto finaliza el modo de respaldo. En un servidor primario, también realiza un cambio automático al siguiente segmento WAL. En un servidor en espera, no es posible cambiar automáticamente los segmentos WAL, por lo que es posible que desees ejecutar pg_switch_wal en el primario para realizar un cambio manual. El motivo del cambio es organizar que el último archivo de segmento WAL escrito durante el intervalo de respaldo esté listo para archivar.

    pg_backup_stop devolverá una fila con tres valores. El segundo de estos campos debe escribirse en un archivo llamado backup_label en el directorio raíz del respaldo. El tercer campo debe escribirse en un archivo llamado tablespace_map, a menos que el campo esté vacío. Estos archivos son vitales para que el respaldo funcione y deben escribirse byte por byte sin modificaciones, lo que puede requerir abrir el archivo en modo binario.

  5. Una vez que se hayan archivado los archivos de segmento WAL activos durante el respaldo, habrás terminado. El archivo identificado por el primer valor de retorno de pg_backup_stop es el último segmento requerido para formar un conjunto completo de archivos de respaldo. En un primario, si archive_mode está habilitado y el parámetro wait_for_archive es true, pg_backup_stop no retorna hasta que el último segmento se haya archivado. En un servidor en espera, archive_mode debe ser always para que pg_backup_stop espere. El archivado de estos archivos ocurre automáticamente ya que has configurado archive_command o archive_library. En la mayoría de los casos esto sucede rápidamente, pero se te aconseja monitorear tu sistema de archivado para asegurarte de que no haya retrasos. Si el proceso de archivado se ha retrasado debido a fallos del comando o biblioteca de archivo, seguirá reintentando hasta que el archivado tenga éxito y se complete el respaldo. Si deseas establecer un límite de tiempo en la ejecución de pg_backup_stop, establece un valor de statement_timeout adecuado, pero ten en cuenta que si pg_backup_stop termina debido a esto, es posible que tu respaldo no sea válido.

    Si el proceso de respaldo monitorea y asegura que todos los archivos de segmento WAL requeridos para el respaldo se archiven correctamente, entonces el parámetro wait_for_archive (que por defecto es true) se puede establecer en false para que pg_backup_stop retorne tan pronto como el registro de detención del respaldo se escriba en el WAL. Por defecto, pg_backup_stop esperará hasta que todo el WAL se haya archivado, lo que puede llevar algún tiempo. Esta opción debe utilizarse con precaución: si el archivado de WAL no se monitorea correctamente, es posible que el respaldo no incluya todos los archivos WAL y, por lo tanto, esté incompleto y no se pueda restaurar.

25.3.4.1. Respaldo del directorio de datos #

Algunas herramientas de respaldo del sistema de archivos emiten advertencias o errores si los archivos que intentan copiar cambian mientras se realiza la copia. Al tomar un respaldo base de una base de datos activa, esta situación es normal y no constituye un error. Sin embargo, debes asegurarte de que puedes distinguir las quejas de este tipo de los errores reales. Por ejemplo, algunas versiones de rsync devuelven un código de salida independiente para «archivos de origen desaparecidos» (vanished source files), y puedes escribir un script controlador para aceptar este código de salida como un caso que no es un error. Además, algunas versiones de GNU tar devuelven un código de error indistinguible de un error fatal si un archivo se truncó mientras tar lo estaba copiando. Afortunadamente, las versiones de GNU tar 1.16 y posteriores salen con 1 si un archivo cambió durante el respaldo, y con 2 para otros errores. Con GNU tar versión 1.23 y posteriores, puedes utilizar las opciones de advertencia --warning=no-file-changed --warning=no-file-removed para ocultar los mensajes de advertencia relacionados.

Asegúrate de que tu respaldo incluya todos los archivos que se encuentran bajo el directorio del clúster de la base de datos (por ejemplo, /usr/local/pgsql/data). Si utilizas tablespaces que no residen debajo de este directorio, ten cuidado de incluirlos también (y asegúrate de que tu respaldo archive los enlaces simbólicos como enlaces, de lo contrario la restauración dañará tus tablespaces).

Sin embargo, deberías omitir del respaldo los archivos dentro del subdirectorio pg_wal/ del clúster. Este ligero ajuste vale la pena porque reduce el riesgo de errores al restaurar. Esto es fácil de organizar si pg_wal/ es un enlace simbólico que apunta a algún lugar fuera del directorio del clúster, lo cual es una configuración común de todos modos por razones de rendimiento. También es posible que desees excluir postmaster.pid y postmaster.opts, que registran información sobre el postmaster en ejecución, no sobre el postmaster que eventualmente utilizará este respaldo. (Estos archivos pueden confundir a pg_ctl).

A menudo también es una buena idea omitir del respaldo los archivos dentro del directorio pg_replslot/ del clúster, de modo que los slots de replicación que existen en el primario no formen parte del respaldo. De lo contrario, el uso posterior del respaldo para crear una espera activa puede dar lugar a la retención indefinida de archivos WAL en el nodo de espera, y posiblemente a la acumulación de datos en el primario si la retroalimentación de espera activa (hot standby feedback) está habilitada, porque los clientes que utilizan esos slots de replicación seguirán conectándose y updating los slots en el primario, no en el de espera. Incluso si el respaldo solo está destinado a crear un nuevo primario, no se espera que copiar los slots de replicación sea particularmente útil, ya que el contenido de esos slots probablemente estará muy desactualizado para cuando el nuevo primario entre en línea.

El contenido de los directorios pg_dynshmem/, pg_notify/, pg_serial/, pg_snapshots/, pg_stat_tmp/ y pg_subtrans/ (pero no los directorios en sí) se puede omitir del respaldo, ya que se inicializarán al iniciar el postmaster.

Cualquier archivo o directorio que comience con pgsql_tmp se puede omitir del respaldo. Estos archivos se eliminan al iniciar el postmaster y los directorios se recrearán según sea necesario.

Los archivos pg_internal.init se pueden omitir del respaldo siempre que se encuentre un archivo con ese nombre. Estos archivos contienen datos de caché de relaciones que siempre se reconstruyen durante la recuperación.

El archivo de etiqueta de respaldo (backup label) incluye la cadena de etiqueta que le diste a pg_backup_start, así como la hora en la que se ejecutó pg_backup_start y el nombre del archivo WAL inicial. En caso de confusión, por lo tanto, es posible mirar dentro de un archivo de respaldo y determinar exactamente de qué sesión de respaldo provino el archivo de volcado. El archivo de mapa de tablespaces incluye los nombres de los enlaces simbólicos tal como existen en el directorio pg_tblspc/ y la ruta completa de cada enlace simbólico. Estos archivos no son meramente para tu información; su presencia y contenido son críticos para el correcto funcionamiento del proceso de recuperación del sistema.

También es posible realizar un respaldo mientras el servidor está detenido. En este caso, obviamente no puedes utilizar pg_backup_start ni pg_backup_stop, y por lo tanto tendrás que valerte por ti mismo para hacer un seguimiento de qué respaldo es cuál y hasta qué punto retroceden los archivos WAL asociados. En general, es mejor seguir el procedimiento de archivado continuo descrito anteriormente.

25.3.5. Recuperación mediante un respaldo de archivo continuo #

Bien, ha ocurrido lo peor y necesitas recuperarte desde tu respaldo. Aquí está el procedimiento:

  1. Detén el servidor, si está ejecutándose.

  2. Si tienes espacio para hacerlo, copia todo el directorio de datos del clúster y cualquier tablespace a una ubicación temporal en caso de que los necesites más adelante. Ten en cuenta que esta precaución requerirá que tengas suficiente espacio libre en tu sistema para albergar dos copias de tu base de datos existente. Si no tienes suficiente espacio, deberías al menos guardar el contenido del subdirectorio pg_wal del clúster, ya que podría contener archivos WAL que no se archivaron antes de que el sistema se cayera.

  3. Elimina todos los archivos y subdirectorios existentes bajo el directorio de datos del clúster y bajo los directorios raíz de cualquier tablespace que estés utilizando.

  4. Si estás restaurando un respaldo completo, puedes restaurar los archivos de la base de datos directamente en los directorios de destino. Asegúrate de que se restauren con la propiedad correcta (¡el usuario del sistema de la base de datos, no root!) y con los permisos correctos. Si estás utilizando tablespaces, debes verificar que los enlaces simbólicos en pg_tblspc/ se hayan restaurado correctamente.

  5. Si estás restaurando un respaldo incremental, necesitarás restaurar el respaldo incremental y todos los respaldos anteriores de los que depende directa o indirectamente en la máquina donde estás realizando la restauración. Estos respaldos deberán colocarse en directorios separados, no en los directorios de destino donde deseas que termine el servidor en ejecución. Una vez hecho esto, utiliza pg_combinebackup para extraer datos del respaldo completo y de todos los respaldos incrementales posteriores y escribir un respaldo completo sintético en los directorios de destino. Como se indicó anteriormente, verifica que los permisos y los enlaces de los tablespaces sean correctos.

  6. Elimina cualquier archivo presente en pg_wal/; estos provienen del respaldo del sistema de archivos y, por lo tanto, probablemente estén obsoletos en lugar de estar actualizados. Si no archivaste pg_wal/ en absoluto, recrealo con los permisos adecuados, teniendo cuidado de asegurarte de restablecerlo como un enlace simbólico si lo tenías configurado de esa manera antes.

  7. Si tienes archivos de segmento WAL no archivados que guardaste en el paso 2, cópialos en pg_wal/. (Es mejor copiarlos, no moverlos, para que sigas teniendo los archivos sin modificar si surge un problema y tienes que empezar de nuevo).

  8. Establece los parámetros de configuración de recuperación en postgresql.conf (consulta Section 19.5.5) y crea un archivo recovery.signal en el directorio de datos del clúster. También es posible que desees modificar temporalmente pg_hba.conf para evitar que los usuarios normales se conecten hasta que estés seguro de que la recuperación fue exitosa.

  9. Inicia el servidor. El servidor entrará en modo de recuperación y procederá a leer los archivos WAL archivados que necesite. Si la recuperación se interrumpe debido a un error externo, el servidor puede simplemente reiniciarse y continuará con la recuperación. Al finalizar el proceso de recuperación, el servidor eliminará recovery.signal (para evitar volver a entrar accidentalmente en el modo de recuperación más adelante) y luego comenzará las operaciones normales de la base de datos.

  10. Inspecciona el contenido de la base de datos para asegurarte de que te has recuperado al estado deseado. Si no es así, regresa al paso 1. Si todo está bien, permite que tus usuarios se conecten restaurando pg_hba.conf a su estado normal.

La parte clave de todo esto es configurar una recuperación que describa cómo deseas recuperarte y hasta qué punto debe ejecutarse. Lo único que absolutamente debes especificar es el restore_command, que le indica a PostgreSQL cómo recuperar los segmentos de archivos WAL archivados. Al igual que el archive_command, esta es una cadena de comando de shell. Puede contener %f, que se reemplaza por el nombre del archivo WAL deseado, y %p, que se reemplaza por la ruta del archivo donde copiar el archivo WAL. (La ruta es relativa al directorio de trabajo actual, es decir, el directorio de datos del clúster). Escribe %% si necesitas incrustar un carácter % real en el comando. El comando útil más sencillo es algo como:

restore_command = 'cp /mnt/server/archivedir/%f %p'

que copiará los segmentos WAL previamente archivados desde el directorio /mnt/server/archivedir. Por supuesto, puedes utilizar algo mucho más complicado, tal vez incluso un script de shell que solicite al operador que monte una cinta adecuada.

Es importante que el comando devuelva un estado de salida distinto de cero en caso de fallo. Se llamará al comando solicitando archivos que no están presentes en el archivo; debe devolver un valor distinto de cero cuando se le solicite. Esta no es una condición de error. Una excepción es que si el comando fue terminado por una señal (que no sea SIGTERM, que se utiliza como parte de un apagado del servidor de la base de datos) o por un error del shell (como comando no encontrado), la recuperación se abortará y el servidor no se iniciará.

No todos los archivos solicitados serán archivos de segmento WAL; también debes esperar solicitudes de archivos con el sufijo .history. Ten en cuenta también que el nombre base de la ruta %p será diferente de %f; no esperes que sean intercambiables.

Los segmentos WAL que no se puedan encontrar en el archivo se buscarán en pg_wal/; esto permite el uso de segmentos recientes no archivados. Sin embargo, los segmentos que estén disponibles en el archivo se utilizarán con preferencia a los archivos en pg_wal/.

Normalmente, la recuperación procederá a través de todos los segmentos WAL disponibles, restaurando así la base de datos al momento actual (o lo más cerca posible dados los segmentos WAL disponibles). Por lo tanto, una recuperación normal finalizará con un mensaje de «archivo no encontrado», dependiendo el texto exacto del mensaje de error de tu elección de restore_command. También es posible que veas un mensaje de error al inicio de la recuperación para un archivo llamado algo así como 00000001.history. Esto también es normal y no indica un problema en situaciones de recuperación sencillas; consulta Section 25.3.6 para su discusión.

Si deseas recuperarte a algún punto anterior en el tiempo (por ejemplo, justo antes de que el administrador de bases de datos junior eliminara tu tabla de transacciones principal), simplemente especifica el punto de detención requerido. Puedes especificar el punto de detención, conocido como el «objetivo de recuperación» (recovery target), ya sea por fecha/hora, punto de restauración con nombre o por la finalización de un ID de transacción específico. A la fecha de escribir este documento, solo las opciones de fecha/hora y punto de restauración con nombre son muy utilizables, ya que no existen herramientas que te ayuden a identificar con precisión qué ID de transacción utilizar.

Note

El punto de detención debe ser posterior a la hora de finalización del respaldo base, es decir, la hora de finalización de pg_backup_stop. No puedes utilizar un respaldo base para recuperarte a un momento en el que ese respaldo estaba en curso. (Para recuperarte a ese momento, debes volver a tu respaldo base anterior y avanzar desde allí).

Si la recuperación encuentra datos WAL dañados, la recuperación se detendrá en ese punto y el servidor no se iniciará. En tal caso, el proceso de recuperación podría volver a ejecutarse desde el principio, especificando un «objetivo de recuperación» antes del punto de corrupción para que la recuperación pueda completarse normalmente. Si la recuperación falla por una razón externa, como un fallo del sistema o si el archivo WAL se ha vuelto inaccesible, la recuperación simplemente se puede reiniciar y se reanudará casi desde donde falló. El reinicio de la recuperación funciona de manera muy similar a los puntos de control en el funcionamiento normal: el servidor fuerza periódicamente todo su estado al disco y luego actualiza el archivo pg_control para indicar que los datos WAL ya procesados no necesitan ser escaneados nuevamente.

25.3.6. Líneas de tiempo #

La capacidad de restaurar la base de datos a un punto anterior en el tiempo crea algunas complejidades que son similares a las historias de ciencia ficción sobre viajes en el tiempo y universos paralelos. Por ejemplo, en la historia original de la base de datos, supongamos que eliminaste una tabla crítica a las 5:15 PM del martes por la tarde, pero no te diste cuenta de tu error hasta el miércoles al mediodía. Sin preocuparte, tomas tu respaldo, lo restauras al punto en el tiempo de las 5:14 PM del martes por la tarde y estás listo y funcionando. En esta historia del universo de la base de datos, nunca eliminaste la tabla. Pero supongamos que luego te das cuenta de que esta no fue una idea tan buena y te gustaría volver a algún momento del miércoles por la mañana en la historia original. No podrás hacerlo si, mientras tu base de datos estaba activa y funcionando, sobrescribió algunos de los archivos de segmento WAL que conducían al momento al que ahora desearías poder regresar. Por lo tanto, para evitar esto, necesitas distinguir la serie de registros WAL generados después de haber realizado una recuperación diferida en el tiempo de aquellos que se generaron en la historia original de la base de datos.

Para lidiar con este problema, PostgreSQL tiene el concepto de líneas de tiempo (timelines). Cada vez que se completa una recuperación de archivo, se crea una nueva línea de tiempo para identificar la serie de registros WAL generados después de esa recuperación. El número de ID de la línea de tiempo es parte de los nombres de los archivos de segmento WAL, por lo que una nueva línea de tiempo no sobrescribe los datos WAL generados por las líneas de tiempo anteriores. Por ejemplo, en el nombre del archivo WAL 0000000100001234000055CD, el 00000001 inicial es el ID de la línea de tiempo en hexadecimal. (Ten en cuenta que en otros contextos, como los mensajes de registro del servidor, los ID de línea de tiempo se imprimen normalmente en decimal).

De hecho, es posible archivar muchas líneas de tiempo diferentes. Aunque eso pueda parecer una característica inútil, a menudo es un salvavidas. Considera la situación en la que no estás muy seguro de a qué punto en el tiempo debes recuperarte, por lo que tienes que realizar varias recuperaciones diferidas en el tiempo mediante prueba y error hasta encontrar el mejor lugar para bifurcarse de la historia antigua. Sin líneas de tiempo, este proceso generaría pronto un caos inmanejable. Con las líneas de tiempo, puedes recuperarte a cualquier estado anterior, incluidos los estados en las ramas de la línea de tiempo que abandonaste antes.

Cada vez que se crea una nueva línea de tiempo, PostgreSQL crea un archivo de «historial de línea de tiempo» (timeline history file) que muestra de qué línea de tiempo se bifurcó y cuándo. Estos archivos de historial son necesarios para permitir que el sistema elija los archivos de segmento WAL correctos cuando se recupera de un archivo que contiene múltiples líneas de tiempo. Por lo tanto, se archivan en el área de archivo WAL al igual que los archivos de segmento WAL. Los archivos de historial son solo pequeños archivos de texto, por lo que es económico y adecuado conservarlos indefinidamente (a diferencia de los archivos de segmento, que son grandes). Puedes, si lo deseas, añadir comentarios a un archivo de historial para registrar tus propias notas sobre cómo y por qué se creó esta línea de tiempo en particular. Dichos comentarios serán especialmente valiosos cuando tengas un bosque de diferentes líneas de tiempo como resultado de la experimentación.

El comportamiento por defecto de la recuperación es recuperarse a la última línea de tiempo encontrada en el archivo. Si deseas recuperarte a la línea de tiempo que estaba vigente cuando se tomó el respaldo base o a una línea de tiempo hija específica (es decir, deseas regresar a algún estado que a su vez se generó después de un intento de recuperación), debes especificar current o el ID de la línea de tiempo de destino en recovery_target_timeline. No puedes recuperarte en líneas de tiempo que se bifurcaron antes que el respaldo base.

25.3.7. Consejos y ejemplos #

Aquí se ofrecen algunos consejos para configurar el archivado continuo.

25.3.7.1. Respaldos en caliente independientes #

Es posible utilizar las facilidades de respaldo de PostgreSQL para producir respaldos en caliente independientes (standalone hot backups). Estos son respaldos que no se pueden utilizar para la recuperación diferida en el tiempo, pero que normalmente son mucho más rápidos de respaldar y restaurar que los volcados de pg_dump. (También son mucho más grandes que los volcados de pg_dump, por lo que en algunos casos la ventaja de velocidad podría verse anulada).

Al igual que con los respaldos base, la forma más sencilla de producir un respaldo en caliente independiente es utilizar la herramienta pg_basebackup. Si incluyes el parámetro -X al llamarlo, todo el registro de escritura anticipada requerido para utilizar el respaldo se incluirá automáticamente en el respaldo, y no se requiere ninguna acción especial para restaurar el respaldo.

25.3.7.2. Registros de archivo comprimidos #

Si el tamaño del almacenamiento de archivo es una preocupación, puedes usar gzip para comprimir los archivos de archivo:

archive_command = 'gzip < %p > /mnt/server/archivedir/%f.gz'

Luego necesitarás usar gunzip durante la recuperación:

restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %p'

25.3.7.3. Scripts de archive_command #

Muchas personas eligen usar scripts para definir su archive_command, de modo que su entrada en postgresql.conf se vea muy simple:

archive_command = 'local_backup_script.sh "%p" "%f"'

Es aconsejable utilizar un archivo de script independiente cada vez que desees utilizar más de un comando en el proceso de archivado. Esto permite gestionar toda la complejidad dentro del script, que puede escribirse en un lenguaje de programación popular como bash o perl.

Ejemplos de requisitos que podrían resolverse dentro de un script incluyen:

  • Copiar datos a un almacenamiento de datos externo seguro

  • Agrupar los archivos WAL de modo que se transfieran cada tres horas, en lugar de uno a la vez

  • Interactuar con otros programas de respaldo y recuperación

  • Interactuar con software de monitoreo para reportar errores

Tip

Al utilizar un script archive_command, es conveniente habilitar logging_collector. Cualquier mensaje escrito en stderr desde el script aparecerá entonces en el registro del servidor de la base de datos, lo que permite diagnosticar fácilmente configuraciones complejas en caso de fallo.

25.3.8. Advertencias #

Al momento de escribir este documento, existen varias limitaciones en la técnica de archivado continuo. Estas probablemente se corregirán en futuras versiones:

  • Si se ejecuta un comando CREATE DATABASE mientras se está realizando un respaldo base, y luego la base de datos plantilla que copió el CREATE DATABASE se modifica mientras el respaldo base aún está en curso, es posible que la recuperación haga que esas modificaciones se propaguen también a la base de datos creada. Esto es, por supuesto, indeseable. Para evitar este riesgo, es mejor no modificar ninguna base de datos plantilla mientras se realiza un respaldo base.

  • Los comandos CREATE TABLESPACE se registran en el WAL con la ruta absoluta literal y, por lo tanto, se reproducirán como creaciones de tablespace con la misma ruta absoluta. Esto podría ser indeseable si el WAL se está reproduciendo en una máquina diferente. Puede ser peligroso incluso si el WAL se está reproduciendo en la misma máquina, pero en un nuevo directorio de datos: la reproducción seguirá sobrescribiendo el contenido del tablespace original. Para evitar posibles sorpresas de este tipo, la mejor práctica es realizar un nuevo respaldo base después de crear o eliminar tablespaces.

También debe tenerse en cuenta que el formato por defecto de WAL es bastante voluminoso, ya que incluye muchas instantáneas de páginas de disco. Estas instantáneas de páginas están diseñadas para admitir la recuperación ante fallos, ya que es posible que necesitemos reparar páginas de disco escritas parcialmente. Dependiendo del hardware y software de tu sistema, el riesgo de escrituras parciales podría ser lo suficientemente pequeño como para ignorarlo, en cuyo caso puedes reducir significativamente el volumen total de archivos WAL archivados desactivando las instantáneas de páginas mediante el parámetro full_page_writes. (Lee las notas y advertencias en Chapter 28 antes de hacerlo). Desactivar las instantáneas de páginas no impide el uso del WAL para operaciones PITR. Un área para futuro desarrollo es comprimir los datos WAL archivados eliminando copias de páginas innecesarias incluso cuando full_page_writes está activado. Mientras tanto, los administradores pueden reducir el número de instantáneas de páginas incluidas en el WAL aumentando los parámetros del intervalo del punto de control tanto como sea factible.