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:
No necesitamos un respaldo del sistema de archivos perfectamente consistente como punto de partida. Cualquier inconsistencia interna en el respaldo se corregirá mediante la reproducción del registro (esto no es muy diferente de lo que sucede durante la recuperación de un fallo). Por lo tanto, no necesitamos una capacidad de instantánea del sistema de archivos, basta con tar o una herramienta de archivado similar.
Dado que podemos combinar una secuencia indefinidamente larga de archivos WAL para la reproducción, el respaldo continuo se puede lograr simplemente continuando el archivado de los archivos WAL. Esto es particularmente valioso para bases de datos grandes, donde puede no ser conveniente tomar un respaldo completo con frecuencia.
No es necesario reproducir las entradas WAL hasta el final. Podríamos detener la reproducción en cualquier punto y tener una instantánea consistente de la base de datos tal como estaba en ese momento. Por lo tanto, esta técnica admite la recuperación diferida en el tiempo (point-in-time recovery): es posible restaurar la base de datos a su estado en cualquier momento desde que se tomó tu respaldo base.
Si alimentamos continuamente la serie de archivos WAL a otra máquina que ha sido cargada con el mismo archivo de respaldo base, tenemos un sistema de espera activa (warm standby): en cualquier momento podemos levantar la segunda máquina y tendrá una copia casi al día de la base de datos.
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.
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.
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.
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.
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).
Asegúrate de que el archivado de WAL esté habilitado y funcione.
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.
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.
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.
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.
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.
Bien, ha ocurrido lo peor y necesitas recuperarte desde tu respaldo. Aquí está el procedimiento:
Detén el servidor, si está ejecutándose.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
Aquí se ofrecen algunos consejos para configurar el archivado continuo.
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.
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'
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
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.
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.