26.2. Servidores Standby de envío de registros (Log-Shipping) #

26.2.1. Planificación
26.2.2. Funcionamiento del servidor Standby
26.2.3. Preparación del primario para los servidores Standby
26.2.4. Configuración de un servidor Standby
26.2.5. Replicación en flujo (Streaming Replication)
26.2.6. Slots de replicación (Replication Slots)
26.2.7. Replicación en cascada (Cascading Replication)
26.2.8. Replicación síncrona (Synchronous Replication)
26.2.9. Archivado continuo en el Standby

El archivado continuo se puede utilizar para crear una configuración de clúster de alta disponibilidad (HA) con uno o más servidores standby listos para hacerse cargo de las operaciones si el servidor primario falla. Esta capacidad se conoce ampliamente como warm standby o envío de registros (log shipping).

El servidor primario y el standby trabajan juntos para proporcionar esta capacidad, aunque los servidores están solo débilmente acoplados. El servidor primario funciona en modo de archivado continuo, mientras que cada servidor standby funciona en modo de recuperación continua, leyendo los archivos WAL del primario. No se requiere realizar cambios en las tablas de la base de datos para habilitar esta capacidad, por lo que ofrece una baja sobrecarga de administración en comparación con algunas otras soluciones de replicación. Esta configuración también tiene un impacto de rendimiento relativamente bajo en el servidor primario.

El movimiento directo de registros WAL de un servidor de base de datos a otro se describe típicamente como envío de registros. PostgreSQL implementa el envío de registros basado en archivos transfiriendo registros WAL un archivo (segmento WAL) a la vez. Los archivos WAL (16MB) se pueden enviar de forma fácil y económica a cualquier distancia, ya sea a un sistema adyacente, a otro sistema en el mismo sitio o a otro sistema en el otro lado del planeta. El ancho de banda requerido para esta técnica varía según la tasa de transacciones del servidor primario. El envío de registros basado en registros individuales es más detallado y transmite los cambios del WAL de forma incremental a través de una conexión de red (consulta Section 26.2.5).

Cabe señalar que el envío de registros es asíncrono, es decir, los registros WAL se envían después de la confirmación de la transacción. Como resultado, existe una ventana para la pérdida de datos en caso de que el servidor primario sufra una falla catastrófica; las transacciones que aún no se hayan enviado se perderán. El tamaño de la ventana de pérdida de datos en el envío de registros basado en archivos se puede limitar mediante el uso del parámetro archive_timeout, que se puede establecer en un valor tan bajo como unos pocos segundos. Sin embargo, una configuración tan baja aumentará sustancialmente el ancho de banda requerido para el envío de archivos. La replicación en flujo (streaming replication) (consulta Section 26.2.5) permite una ventana de pérdida de datos mucho menor.

El rendimiento de la recuperación es lo suficientemente bueno como para que el standby esté típicamente a solo unos instantes de la disponibilidad completa una vez activado. Como resultado, esto se denomina una configuración warm standby que ofrece alta disponibilidad. Restaurar un servidor desde una copia de seguridad base archivada y realizar un rollforward llevará considerablemente más tiempo, por lo que esa técnica solo ofrece una solución para la recuperación ante desastres, no para la alta disponibilidad. Un servidor standby también se puede utilizar para consultas de solo lectura, en cuyo caso se denomina servidor hot standby. Consulta Section 26.4 para obtener más información.

26.2.1. Planificación #

Por lo general, es aconsejable crear los servidores primario y standby de modo que sean lo más parecidos posible, al menos desde la perspectiva del servidor de base de datos. En particular, los nombres de ruta asociados con los espacios de tablas se pasarán sin modificar, por lo que tanto el servidor primario como el standby deben tener las mismas rutas de montaje para los espacios de tablas si se utiliza esa característica. Ten en cuenta que si se ejecuta CREATE TABLESPACE en el primario, cualquier nuevo punto de montaje necesario para él debe crearse en el primario y en todos los servidores standby antes de ejecutar el comando. El hardware no tiene por qué ser exactamente el mismo, pero la experiencia demuestra que mantener dos sistemas idénticos es más fácil que mantener dos sistemas diferentes a lo largo de la vida útil de la aplicación y del sistema. En cualquier caso, la arquitectura de hardware debe ser la misma — el envío de, por ejemplo, un sistema de 32 bits a uno de 64 bits no funcionará.

En general, el envío de registros entre servidores que ejecutan diferentes niveles de versiones principales (major releases) de PostgreSQL no es posible. Es política del PostgreSQL Global Development Group no realizar cambios en los formatos de disco durante las actualizaciones de versiones menores (minor releases), por lo que es probable que funcione correctamente la ejecución de diferentes niveles de versiones menores en los servidores primario y standby. Sin embargo, no se ofrece soporte formal para ello y se aconseja mantener los servidores primario y standby en la misma versión siempre que sea posible. Al actualizar a una nueva versión menor, la política más segura es actualizar primero los servidores standby — es más probable que una nueva versión menor pueda leer los archivos WAL de una versión menor anterior que al revés.

26.2.2. Funcionamiento del servidor Standby #

Un servidor entra en modo standby si existe un archivo standby.signal en el directorio de datos cuando se inicia el servidor.

En modo standby, el servidor aplica continuamente el WAL recibido del servidor primario. El servidor standby puede leer el WAL de un archivo WAL (consulta restore_command) o directamente del primario a través de una conexión TCP (replicación en flujo). El servidor standby también intentará restaurar cualquier WAL que se encuentre en el directorio pg_wal del clúster standby. Esto suele suceder después de un reinicio del servidor, cuando el standby vuelve a reproducir el WAL que se transmitió en flujo desde el primario antes del reinicio, pero también puedes copiar manualmente los archivos a pg_wal en cualquier momento para que se vuelvan a reproducir.

Al inicio, el standby comienza restaurando todo el WAL disponible en la ubicación del archivo, llamando a restore_command. Una vez que llega al final del WAL disponible allí y restore_command falla, intenta restaurar cualquier WAL disponible en el directorio pg_wal. Si eso falla, y se ha configurado la replicación en flujo, el standby intenta conectarse al servidor primario y comenzar a transmitir en flujo el WAL desde el último registro válido encontrado en el archivo o en pg_wal. Si eso falla o si la replicación en flujo no está configurada, o si la conexión se desconecta más tarde, el standby vuelve al paso 1 e intenta restaurar el archivo desde el archivo nuevamente. Este bucle de reintentos desde el archivo, pg_wal y a través de la replicación en flujo continúa hasta que el servidor se detiene o es promovido.

El modo standby se abandona y el servidor cambia al funcionamiento normal cuando se ejecuta pg_ctl promote o se llama a pg_promote(). Antes de la conmutación por error, se restaurará cualquier WAL disponible inmediatamente en el archivo o en pg_wal, pero no se realiza ningún intento de conectarse al primario.

26.2.3. Preparación del primario para los servidores Standby #

Configura el archivado continuo en el primario en un directorio de archivo accesible desde el standby, tal como se describe in Section 25.3. La ubicación del archivo debe ser accesible desde el standby incluso cuando el primario esté caído, es decir, debe residir en el propio servidor standby o en otro servidor de confianza, no en el servidor primario.

Si deseas utilizar la replicación en flujo, configura la autenticación en el servidor primario para permitir conexiones de replicación desde los servidores standby; es decir, crea un rol y proporciona una entrada o entradas adecuadas en pg_hba.conf con el campo database establecido en replication. Asegúrate también de que max_wal_senders esté establecido en un valor lo suficientemente grande en el archivo de configuración del servidor primario. Si se van a utilizar slots de replicación, asegúrate de que max_replication_slots también esté configurado con un valor lo suficientemente alto.

Realiza una copia de seguridad base tal como se describe en Section 25.3.2 para inicializar el servidor standby.

26.2.4. Configuración de un servidor Standby #

Para configurar el servidor standby, restaura la copia de seguridad base tomada del servidor primario (consulta Section 25.3.5). Crea un archivo standby.signal en el directorio de datos del clúster standby. Configura restore_command con un comando simple para copiar archivos desde el archivo WAL. Si planeas tener múltiples servidores standby para propósitos de alta disponibilidad, asegúrate de que recovery_target_timeline esté configurado en latest (el valor predeterminado), para hacer que el servidor standby siga el cambio de línea de tiempo (timeline) que ocurre al realizar la conmutación por error a otro standby.

Note

restore_command debería devolver inmediatamente un error si el archivo no existe; el servidor volverá a intentar el comando si es necesario.

Si deseas utilizar la replicación en flujo, rellena primary_conninfo con una cadena de conexión libpq, incluyendo el nombre del host (o la dirección IP) y cualquier detalle adicional necesario para conectarse al servidor primario. Si el primario necesita una contraseña para la autenticación, la contraseña también debe especificarse en primary_conninfo.

Si estás configurando el servidor standby para propósitos de alta disponibilidad, configura el archivado de WAL, las conexiones y la autenticación de la misma manera que el servidor primario, porque el servidor standby funcionará como un servidor primario después de la conmutación por error.

Si estás utilizando un archivo WAL, su tamaño se puede minimizar utilizando el parámetro archive_cleanup_command para eliminar los archivos que el servidor standby ya no necesita. La utilidad pg_archivecleanup está diseñada específicamente para ser utilizada con archive_cleanup_command en configuraciones típicas de un solo standby, consulta pg_archivecleanup. Ten en cuenta, sin embargo, que si estás utilizando el archivo para propósitos de copia de seguridad, debes conservar los archivos necesarios para recuperarse de al menos la copia de seguridad base más reciente, incluso si el standby ya no los necesita.

Un ejemplo sencillo de configuración es:

primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass options=''-c wal_sender_timeout=5000'''
restore_command = 'cp /path/to/archive/%f %p'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'

Puedes tener cualquier número de servidores standby, pero si utilizas la replicación en flujo, asegúrate de configurar max_wal_senders con un valor lo suficientemente alto en el primario para permitir que se conecten simultáneamente.

26.2.5. Replicación en flujo (Streaming Replication) #

La replicación en flujo permite que un servidor standby se mantenga más actualizado de lo que es posible con el envío de registros basado en archivos. El standby se conecta al primario, el cual transmite los registros WAL al standby a medida que se generan, sin esperar a que se llene el archivo WAL.

La replicación en flujo es asíncrona por defecto (consulta Section 26.2.8), en cuyo caso existe un pequeño retraso entre la confirmación de una transacción en el primario y el momento en que los cambios se vuelven visibles en el standby. Sin embargo, este retraso es mucho menor que con el envío de registros basado en archivos, típicamente por debajo de un segundo, asumiendo que el standby es lo suficientemente potente como para mantenerse al día con la carga. Con la replicación en flujo, no se requiere archive_timeout para reducir la ventana de pérdida de datos.

Si utilizas la replicación en flujo sin el archivado continuo basado en archivos, el servidor podría reciclar los segmentos WAL antiguos antes de que el standby los haya recibido. Si esto ocurre, el standby deberá volver a inicializarse a partir de una nueva copia de seguridad base. Puedes evitar esto configurando wal_keep_size en un valor lo suficientemente grande como para garantizar que los segmentos WAL no se reciclen demasiado pronto, o configurando un slot de replicación para el standby. Si configuras un archivo WAL que sea accesible desde el standby, estas soluciones no son necesarias, ya que el standby siempre puede utilizar el archivo para ponerse al día siempre que conserve suficientes segmentos.

Para utilizar la replicación en flujo, configura un servidor standby de envío de registros basado en archivos tal como se describe en la Section 26.2. El paso que convierte un standby de envío de registros basado en archivos en un standby de replicación en flujo es configurar el parámetro primary_conninfo para que apunte al servidor primario. Configura listen_addresses y las opciones de autenticación (consulta pg_hba.conf) en el servidor primario de modo que el servidor standby pueda conectarse a la pseudobase de datos replication en el servidor primario (consulta Section 26.2.5.1).

En los sistemas que admiten la opción de socket keepalive, la configuración de tcp_keepalives_idle, tcp_keepalives_interval y tcp_keepalives_count ayuda a que el primario note rápidamente una conexión rota.

Configura el número máximo de conexiones concurrentes desde los servidores standby (consulta max_wal_senders para obtener más detalles).

Cuando se inicia el standby y primary_conninfo está configurado correctamente, el standby se conectará al primario después de reproducir todos los archivos WAL disponibles en el archivo. Si la conexión se establece con éxito, verás un proceso walreceiver en el standby y un proceso walsender correspondiente en el primario.

26.2.5.1. Autenticación #

Es muy importante que los privilegios de acceso para la replicación se configuren de modo que solo los usuarios de confianza puedan leer el flujo de WAL, ya que es fácil extraer información privilegiada de él. Los servidores standby deben autenticarse ante el primario utilizando una cuenta que tenga el privilegio REPLICATION o que sea un superusuario. Se recomienda crear una cuenta de usuario dedicada con privilegios REPLICATION y LOGIN para la replicación. Si bien el privilegio REPLICATION otorga permisos muy elevados, no permite al usuario modificar ningún dato en el sistema primario, a diferencia de lo que hace el privilegio SUPERUSER.

La autenticación de clientes para la replicación se controla mediante un registro en el archivo pg_hba.conf que especifica replication en el campo database. Por ejemplo, si el standby se está ejecutando en la IP del host 192.168.1.100 y el nombre de la cuenta para la replicación es foo, el administrador puede añadir la siguiente línea al archivo pg_hba.conf en el primario:

# Permitir que el usuario "foo" desde el host 192.168.1.100 se conecte al primario
# como standby de replicación si se proporciona correctamente la contraseña del usuario.
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    replication     foo             192.168.1.100/32        scram-sha-256

El nombre del host y el número de puerto del primario, el nombre del usuario de conexión y la contraseña se especifican en primary_conninfo. La contraseña también se puede configurar en el archivo ~/.pgpass en el standby (especifica replication en el campo database). Por ejemplo, si el primario se está ejecutando en la IP del host 192.168.1.50, puerto 5432, el nombre de la cuenta para la replicación es foo y la contraseña es foopass, el administrador puede añadir la siguiente línea al archivo postgresql.conf en el standby:

# El standby se conecta al primario que se está ejecutando en el host 192.168.1.50
# y el puerto 5432 como el usuario "foo" cuya contraseña es "foopass".
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'

26.2.5.2. Monitoreo #

Un indicador de salud importante de la replicación en flujo es la cantidad de registros WAL generados en el primario, pero que aún no se han aplicado en el standby. Puedes calcular este retraso comparando la ubicación actual de escritura de WAL en el primario con la última ubicación de WAL recibida por el standby. Estas ubicaciones se pueden recuperar utilizando pg_current_wal_lsn en el primario y pg_last_wal_receive_lsn en el standby, respectivamente (consulta Table 9.97 y Table 9.98 para obtener más detalles). La última ubicación de recepción de WAL en el standby también se muestra en el estado del proceso del receptor de WAL (walreceiver), que se muestra mediante el comando ps (consulta Section 27.1 para obtener más detalles).

Puedes recuperar una lista de procesos emisores de WAL (walsender) a través de la vista pg_stat_replication. Las grandes diferencias entre pg_current_wal_lsn y el campo sent_lsn de la vista podrían indicar que el servidor primario está bajo una carga pesada, mientras que las diferencias entre sent_lsn y pg_last_wal_receive_lsn en el standby podrían indicar un retraso en la red, o que el standby está bajo una carga pesada.

En un hot standby, el estado del proceso del receptor de WAL se puede recuperar a través de la vista pg_stat_wal_receiver. Una gran diferencia entre pg_last_wal_replay_lsn y el campo flushed_lsn de la vista indica que el WAL se está recibiendo más rápido de lo que se puede reproducir.

26.2.6. Slots de replicación (Replication Slots) #

Los slots de replicación proporcionan una forma automatizada de garantizar que el servidor primario no elimine los segmentos WAL hasta que hayan sido recibidos por todos los standbys, y de que el primario no elimine las filas que podrían causar un conflicto de recuperación incluso cuando el standby esté desconectado.

En lugar de utilizar slots de replicación, es posible evitar la eliminación de los segmentos WAL antiguos utilizando wal_keep_size, o almacenando los segmentos en un archivo utilizando archive_command o archive_library. Una desventaja de estos métodos es que a menudo resultan en la retención de más segmentos WAL de los requeridos, mientras que los slots de replicación retienen únicamente el número de segmentos que se sabe que son necesarios.

Del mismo modo, hot_standby_feedback por sí solo, sin utilizar también un slot de replicación, proporciona protección contra la eliminación de las filas relevantes por parte del vacuum, pero no proporciona protección durante ningún período de tiempo en el que el standby no esté conectado.

Caution

Ten cuidado, ya que los slots de replicación pueden hacer que el servidor retenga tantos segmentos WAL que llenen el espacio asignado para pg_wal. Se puede utilizar el parámetro max_slot_wal_keep_size para limitar el tamaño de los archivos WAL retenidos por los slots de replicación.

26.2.6.1. Consulta y manipulación de slots de replicación #

Cada slot de replicación tiene un nombre, que puede contener letras minúsculas, números y el carácter de subrayado.

Los slots de replicación existentes y su estado se pueden ver en la vista pg_replication_slots.

Los slots se pueden crear y eliminar a través del protocolo de replicación en flujo (consulta Section 54.4) o mediante funciones SQL (consulta Section 9.28.6).

26.2.6.2. Ejemplo de configuración #

Puedes crear un slot de replicación como este:

postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
  slot_name  | lsn
-------------+-----
  node_a_slot |

postgres=# SELECT slot_name, slot_type, active FROM pg_replication_slots;
  slot_name  | slot_type | active
-------------+-----------+--------
  node_a_slot | physical  | f
(1 row)

Para configurar el standby para que use este slot, se debe configurar primary_slot_name en el standby. Aquí hay un ejemplo sencillo:

primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
primary_slot_name = 'node_a_slot'

26.2.7. Replicación en cascada (Cascading Replication) #

La característica de replicación en cascada permite que un servidor standby acepte conexiones de replicación y transmita registros WAL a otros standbys, actuando como un retransmisor (relay). Esto se puede utilizar para reducir el número de conexiones directas al primario y también para minimizar los costos de ancho de banda entre sitios.

Un standby que actúa tanto como receptor como emisor se conoce como standby en cascada (cascading standby). Los standbys que están conectados más directamente al primario se conocen como servidores ascendentes (upstream), mientras que aquellos servidores standby que están más alejados son servidores descendentes (downstream). La replicación en cascada no impone límites en el número o la disposición de los servidores descendentes, aunque cada standby se conecta a un solo servidor ascendente que eventualmente se vincula a un único servidor primario.

Un standby en cascada envía no solo los registros WAL recibidos del primario, sino también los restaurados desde el archivo. Por lo tanto, incluso si la conexión de replicación en alguna conexión ascendente se interrumpe, la replicación en flujo continúa descendente mientras haya nuevos registros WAL disponibles.

La replicación en cascada es actualmente asíncrona. Los parámetros de replicación síncrona (consulta Section 26.2.8) no tienen efecto en la replicación en cascada en la actualidad.

La retroalimentación de hot standby (hot standby feedback) se propaga hacia arriba, independientemente de la disposición en cascada.

Si un servidor standby ascendente es promovido para convertirse en el nuevo primario, los servidores descendentes continuarán transmitiendo desde el nuevo primario si recovery_target_timeline está configurado en 'latest' (el valor predeterminado).

Para utilizar la replicación en cascada, configura el standby en cascada de modo que pueda aceptar conexiones de replicación (es decir, configura max_wal_senders y hot_standby, y configura la autenticación basada en host). También deberás configurar primary_conninfo en el standby descendente para que apunte al standby en cascada.

26.2.8. Replicación síncrona (Synchronous Replication) #

La replicación en flujo de PostgreSQL es asíncrona por defecto. Si el servidor primario se cae, es posible que algunas transacciones que fueron confirmadas no se hayan replicado en el servidor standby, lo que provoca la pérdida de datos. La cantidad de pérdida de datos es proporcional al retraso de replicación en el momento de la conmutación por error.

La replicación síncrona ofrece la capacidad de confirmar que todos los cambios realizados por una transacción se han transferido a uno o más servidores standby síncronos. Esto amplía el nivel estándar de durabilidad que ofrece la confirmación de una transacción. Este nivel de protección se denomina replicación segura en 2 (2-safe replication) en la teoría de las ciencias de la computación, y segura en el grupo-1 (group-1-safe / group-safe y 1-safe) cuando synchronous_commit está configurado en remote_write.

Al solicitar la replicación síncrona, cada confirmación de una transacción de escritura esperará hasta recibir la confirmación de que la transacción se ha escrito en el registro de escritura anticipada en el disco tanto del servidor primario como del standby. La única posibilidad de que se pierdan datos es si tanto el primario como el standby sufren caídas al mismo tiempo. Esto puede proporcionar un nivel de durabilidad mucho más alto, aunque solo si el administrador del sistema es cauteloso sobre la ubicación y gestión de los dos servidores. Esperar la confirmación aumenta la confianza del usuario en que los cambios no se perderán en caso de caídas del servidor, pero también aumenta necesariamente el tiempo de respuesta para la transacción que lo solicita. El tiempo de espera mínimo es el tiempo de ida y vuelta (round-trip time) entre el primario y el standby.

Las transacciones de solo lectura y las cancelaciones de transacciones no necesitan esperar las respuestas de los servidores standby. Las confirmaciones de subtransacciones no esperan las respuestas de los servidores standby, solo las confirmaciones de nivel superior. Las acciones de larga duración, como la carga de datos o la construcción de índices, no esperan hasta el mensaje de confirmación final. Todas las acciones de confirmación en dos fases requieren esperas de confirmación, incluyendo tanto la preparación como la confirmación.

Un standby síncrono puede ser un standby de replicación física o un suscriptor de replicación lógica. También puede ser cualquier otro consumidor de flujo de replicación física o lógica de WAL que sepa cómo enviar los mensajes de retroalimentación adecuados. Además de los sistemas de replicación física y lógica integrados, esto incluye programas especiales como pg_receivewal y pg_recvlogical, así como algunos sistemas de replicación de terceros y programas personalizados. Consulta la documentación respectiva para obtener detalles sobre el soporte de replicación síncrona.

26.2.8.1. Configuración básica #

Una vez configurada la replicación en flujo, la configuración de la replicación síncrona requiere solo un paso de configuración adicional: synchronous_standby_names debe configurarse con un valor no vacío. synchronous_commit también debe configurarse en on, pero dado que este es el valor predeterminado, normalmente no se requiere ningún cambio. (Consulta Section 19.5.1 y Section 19.6.2). Esta configuración hará que cada confirmación espere la confirmación de que el standby ha escrito el registro de confirmación en el almacenamiento duradero. synchronous_commit puede ser configurado por usuarios individuales, por lo que se puede configurar en el archivo de configuración, para usuarios o bases de datos particulares, o dinámicamente por las aplicaciones, con el fin de controlar la garantía de durabilidad transacción por transacción.

Después de que se ha escrito un registro de confirmación en el disco en el primario, el registro WAL se envía al standby. El standby envía mensajes de respuesta cada vez que se escribe un nuevo lote de datos WAL en el disco, a menos que wal_receiver_status_interval esté configurado en cero en el standby. En el caso de que synchronous_commit esté configurado en remote_apply, el standby envía mensajes de respuesta cuando se reproduce el registro de confirmación, haciendo que la transacción sea visible. Si el standby se elige como un standby síncrono, de acuerdo con la configuración de synchronous_standby_names en el primario, los mensajes de respuesta de ese standby se considerarán junto con los de otros standbys síncronos para decidir cuándo liberar las transacciones que esperan la confirmación de que se ha recibido el registro de confirmación. Estos parámetros permiten al administrador especificar qué servidores standby deben ser standbys síncronos. Ten en cuenta que la configuración de la replicación síncrona se realiza principalmente en el primario. Los standbys con nombre deben estar conectados directamente al primario; el primario no sabe nada sobre los servidores standby descendentes que utilizan replicación en cascada.

Configurar synchronous_commit en remote_write hará que cada confirmación espere la confirmación de que el standby ha recibido el registro de confirmación y lo ha escrito en su propio sistema operativo, pero no que los datos se hayan vaciado al disco en el standby. Esta configuración proporciona una garantía de durabilidad más débil que la que ofrece on: el standby podría perder los datos en caso de una caída del sistema operativo, aunque no por una caída de PostgreSQL. Sin embargo, es una configuración útil en la práctica porque puede disminuir el tiempo de respuesta de la transacción. La pérdida de datos solo podría ocurrir si tanto el primario como el standby fallan y la base de datos del primario se corrompe al mismo tiempo.

Configurar synchronous_commit en remote_apply hará que cada confirmación espere hasta que los standbys síncronos actuales informen que han reproducido la transacción, haciéndola visible para las consultas de los usuarios. En casos sencillos, esto permite el balanceo de carga con consistencia causal.

Los usuarios dejarán de esperar si se solicita un apagado rápido (fast shutdown). Sin embargo, al igual que al utilizar la replicación asíncrona, el servidor no se apagará por completo hasta que todos los registros WAL pendientes se transfieran a los servidores standby conectados actualmente.

26.2.8.2. Múltiples standbys síncronos #

La replicación síncrona admite uno o más servidores standby síncronos; las transacciones esperarán hasta que todos los servidores standby que se consideran síncronos confirmen la recepción de sus datos. El número de standbys síncronos de los que las transacciones deben esperar respuestas se especifica en synchronous_standby_names. Este parámetro también especifica una lista de nombres de standby y el método (FIRST y ANY) para elegir los standbys síncronos de entre los enumerados.

El método FIRST especifica una replicación síncrona basada en prioridades y hace que las confirmaciones de las transacciones esperen hasta que sus registros WAL se repliquen en el número solicitado de standbys síncronos elegidos en función de sus prioridades. A los standbys cuyos nombres aparecen antes en la lista se les asigna una prioridad más alta y se considerarán síncronos. Los otros servidores standby que aparecen más adelante en esta lista representan standbys síncronos potenciales. Si alguno de los standbys síncronos actuales se desconecta por cualquier motivo, se reemplazará inmediatamente con el siguiente standby de mayor prioridad.

Un ejemplo de synchronous_standby_names para múltiples standbys síncronos basados en prioridades es:

synchronous_standby_names = 'FIRST 2 (s1, s2, s3)'

En este ejemplo, si se están ejecutando cuatro servidores standby s1, s2, s3 y s4, los dos standbys s1 y s2 se elegirán como standbys síncronos porque sus nombres aparecen al principio de la lista de nombres de standby. s3 es un standby síncrono potencial y asumirá el papel de standby síncrono cuando falle cualquiera de los servidores s1 o s2. s4 es un standby asíncrono ya que su nombre no está en la lista.

El método ANY especifica una replicación síncrona basada en quórum y hace que las confirmaciones de transacciones esperen hasta que sus registros WAL se repliquen en al menos el número solicitado de standbys síncronos de la lista.

Un ejemplo de synchronous_standby_names para múltiples standbys síncronos basados en quórum es:

synchronous_standby_names = 'ANY 2 (s1, s2, s3)'

En este ejemplo, si se están ejecutando cuatro servidores standby s1, s2, s3 y s4, las confirmaciones de transacciones esperarán las respuestas de al menos dos standbys cualesquiera de entre s1, s2 y s3. s4 es un standby asíncrono ya que su nombre no está en la lista.

Los estados síncronos de los servidores standby se pueden ver utilizando la vista pg_stat_replication.

26.2.8.3. Planificación del rendimiento #

La replicación síncrona suele requerir servidores standby cuidadosamente planificados y ubicados para garantizar que el rendimiento de las aplicaciones sea aceptable. La espera no utiliza recursos del sistema, pero los bloqueos de transacciones continúan manteniéndose hasta que se confirma la transferencia. Como resultado, el uso descuidado de la replicación síncrona reducirá el rendimiento de las aplicaciones de bases de datos debido al aumento de los tiempos de respuesta y a una mayor contención.

PostgreSQL permite al desarrollador de la aplicación especificar el nivel de durabilidad requerido a través de la replicación. Esto se puede especificar para el sistema en general, aunque también se puede especificar para usuarios o conexiones específicas, o incluso para transacciones individuales.

Por ejemplo, la carga de trabajo de una aplicación podría consistir en: un 10% de los cambios son datos importantes de los clientes, mientras que un 90% de los cambios son datos menos importantes que la empresa puede permitirse perder más fácilmente si se pierden, como los mensajes de chat entre usuarios.

Con las opciones de replicación síncrona especificadas a nivel de aplicación (en el primario), podemos ofrecer replicación síncrona para los cambios más importantes, sin ralentizar la mayor parte de la carga de trabajo total. Las opciones a nivel de aplicación son una herramienta importante y práctica para permitir los beneficios de la replicación síncrona para las aplicaciones de alto rendimiento.

Debes tener en cuenta que el ancho de banda de la red debe ser mayor que la tasa de generación de datos WAL.

26.2.8.4. Planificación para la alta disponibilidad #

synchronous_standby_names especifica el número y los nombres de los standbys síncronos de los que esperarán respuestas las confirmaciones de transacciones realizadas cuando synchronous_commit esté configurado en on, remote_apply o remote_write. Dichas confirmaciones de transacciones podrían no completarse nunca si alguno de los standbys síncronos fallara.

La mejor solución para la alta disponibilidad es asegurarse de mantener tantos standbys síncronos como se soliciten. Esto se puede lograr nombrando múltiples standbys síncronos potenciales usando synchronous_standby_names.

En una replicación síncrona basada en prioridades, los standbys cuyos nombres aparecen antes en la lista se utilizarán como standbys síncronos. Los standbys enumerados después de estos asumirán el papel de standby síncrono si uno de los actuales fallara.

En una replicación síncrona basada en quórum, todos los standbys que aparecen en la lista se utilizarán como candidatos para standbys síncronos. Incluso si uno de ellos fallara, los otros standbys seguirán realizando el papel de candidatos de standby síncrono.

Cuando un standby se conecta por primera vez al primario, aún no estará sincronizado correctamente. Esto se describe como el modo de puesta al día (catchup). Una vez que el retraso entre el standby y el primario llega a cero por primera vez, pasamos al estado de transmisión en flujo (streaming) en tiempo real. La duración de la puesta al día puede ser larga inmediatamente después de crear el standby. Si el standby se apaga, el período de puesta al día aumentará de acuerdo con la cantidad de tiempo que el standby haya estado inactivo. El standby solo puede convertirse en un standby síncrono una vez que ha alcanzado el estado de transmisión en flujo. Este estado se puede ver utilizando la vista pg_stat_replication.

Si el primario se reinicia mientras las confirmaciones esperan confirmación, esas transacciones en espera se marcarán como completamente confirmadas una vez que la base de datos primaria se recupere. No hay forma de estar seguro de que todos los standbys hayan recibido todos los datos WAL pendientes en el momento de la caída del primario. Es posible que algunas transacciones no se muestren como confirmadas en el standby, a pesar de que se muestren como confirmadas en el primario. La garantía que ofrecemos es que la aplicación no recibirá una confirmación explícita del éxito de la confirmación de una transacción hasta que se sepa que los datos WAL han sido recibidos de forma segura por todos los standbys síncronos.

Si realmente no puedes mantener tantos standbys síncronos como se soliciten, debes disminuir el número de standbys síncronos de los que las confirmaciones de transacciones deben esperar respuestas en synchronous_standby_names (o desactivarlo) y volver a cargar el archivo de configuración en el servidor primario.

Si el primario está aislado de los servidores standby restantes, debes realizar una conmutación por error al mejor candidato de los otros servidores standby restantes.

Si necesitas volver a crear un servidor standby mientras las transacciones están esperando, asegúrate de que las funciones pg_backup_start() y pg_backup_stop() se ejecuten en una sesión con synchronous_commit = off, de lo contrario esas solicitudes esperarán indefinidamente a que aparezca el standby.

26.2.9. Archivado continuo en el Standby #

Cuando se utiliza el archivado continuo de WAL en un standby, existen dos escenarios diferentes: el archivo WAL se puede compartir entre el primario y el standby, o el standby puede tener su propio archivo WAL. Cuando el standby tiene su propio archivo WAL, configura archive_mode en always, y el standby llamará al comando de archivado para cada segmento WAL que reciba, ya sea restaurándolo desde el archivo o mediante la replicación en flujo. El archivo compartido se puede manejar de manera similar, pero el comando archive_command o la biblioteca archive_library debe comprobar si el archivo que se está archivando ya existe y si el archivo existente tiene un contenido idéntico. Esto requiere más cuidado en el archive_command o en la archive_library, ya que debe tener cuidado de no sobrescribir un archivo existente con contenido diferente, sino devolver éxito si el mismo archivo exacto se archiva dos veces. Y todo eso debe hacerse libre de condiciones de carrera, si dos servidores intentan archivar el mismo archivo al mismo tiempo.

Si archive_mode está configurado en on, el archivador no está habilitado durante la recuperación o el modo standby. Si el servidor standby es promovido, comenzará a archivar después de la promoción, pero no archivará ningún archivo WAL o de historial de líneas de tiempo (timeline history) que no haya generado él mismo. Para obtener una serie completa de archivos WAL en el archivo, debes asegurarte de que todo el WAL esté archivado antes de que llegue al standby. Esto es intrínsecamente cierto con el envío de registros basado en archivos, ya que el standby solo puede restaurar los archivos que se encuentran en el archivo, pero no si la replicación en flujo está habilitada. Cuando un servidor no está en modo de recuperación, no hay diferencia entre los modos on y always.