Cómo configurar la replicación en flujo de PostgreSQL con ranuras de replicación en Debian 10

PostgreSQL es un sistema de gestión de bases de datos relacionales (RDBMS) potente y con muchas funciones. Es gratuito y de código abierto, y lleva desarrollándose desde 1996. Postgres ofrece distintos modos de archivar y replicar datos, uno de los cuales es la replicación en flujo. En este modo, una instancia primaria (maestra) maneja la base de datos principal activa y ejecuta las operaciones. La instancia secundaria (esclava) copia todos los cambios de la primaria, manteniendo una copia idéntica de la base de datos activa. El servidor secundario también puede aceptar consultas de sólo lectura. Si el primario falla, el servidor secundario puede salir del modo de espera y funcionar como el nuevo maestro (esto se llama failover).

La replicación de PostgreSQL suele basarse en el registro de escritura anticipada (WAL), el proceso de registrar los cambios de datos antes de escribirlos en el disco. Estos registros de WAL se copian a un segundo nodo como archivos (envío de registros basado en archivos), o se transmiten directamente entre nodos (replicación en flujo). En la mayoría de los casos, esto último reduce el retraso de los cambios en el nodo maestro para que los reciba el nodo en espera.

El problema de utilizar la replicación en flujo sin el envío de registros basado en archivos es que el servidor secundario puede perder algunos registros WAL si el primario los descarta demasiado pronto. Hay una serie de parámetros de configuración que pueden reducir este riesgo, pero a menudo conllevan un coste de almacenamiento innecesario. La solución son las ranuras de replicación, una función proporcionada por Postgres que garantiza que el servidor primario sólo descarte los registros WAL después de que los haya recibido el nodo en espera.

Vamos a configurar la replicación en flujo con ranuras de replicación en dos nodos de Debian 10.

Requisitos

  • Dos instancias idénticas de Debian 10.
  • Acceso a la raíz de ambas instancias.
  • La variable de entorno $EDITOR debe estar configurada en ambas instancias.

Paso 1: Instalar PostgreSQL

Actualiza y reinicia ambos nodos:

apt update
apt upgrade -y
reboot

Instala Postgres en ambos nodos y asegúrate de que PostgreSQL está habilitado y funcionando:

apt install -y postgresql
systemctl enable --now [email protected]

NOTA: Al actualizar PostgreSQL, actualizar primero el standby es la opción más segura según su documentación.

Paso 2: Configuración inicial

Por defecto, PostgreSQL sólo escucha en la interfaz loopback y no es accesible externamente. Cambia la dirección de escucha en ambos nodos editando postgresql.conf:

$EDITOR /etc/postgresql/11/main/postgresql.conf

Busca la siguiente línea:

#listen_addresses = 'localhost'

Cámbiala por:

listen_addresses = 'node_ip_address,127.0.0.1'

Si ambos nodos comparten la misma red local, puedes utilizar direcciones privadas para node_ip_address, aunque Postgres no será accesible desde Internet. En caso contrario, utiliza direcciones públicas.

Guarda el cambio y luego reinicia ambas instancias:

systemctl restart [email protected]

Paso 3: Configuración del maestro

Este paso sólo se refiere al servidor primario/maestro.

Abre el terminal de Postgres:

sudo -u postgres psql

El nodo en espera utilizará un usuario para conectarse al maestro. Créalo:

postgres=# CREATE ROLE replicator LOGIN REPLICATION ENCRYPTED PASSWORD 'replicator_password';

A continuación, crea una ranura de replicación y sal:

postgres=# SELECT * FROM pg_create_physical_replication_slot('replicator');
postgres=# \q

En aras de la simplicidad, el rol de replicación y la ranura se denominan ambos «replicador», aunque no tienen por qué ser idénticos.

A continuación, crea una entrada en pg_hba.conf para permitir que el usuario replicador se conecte desde el standby al master. Ábrela:

$EDITOR /etc/postgresql/11/main/pg_hba.conf

Añade la siguiente línea al final:

host	replication	replicator	standby_ip_address/32		md5

Reinicia la instancia maestra:

systemctl restart [email protected]

Paso 4: Copia de seguridad base

Los comandos de este paso deben ejecutarse en el servidor secundario/esclavo.

Primero, detén Postgres en el nodo secundario:

systemctl stop [email protected]

Haz una copia de seguridad del directorio de datos antiguo:

mv /var/lib/postgresql/11/main/ /var/lib/postgresql/11/main.bak

Utiliza el siguiente comando para clonar el directorio de datos del maestro en el esclavo:

pg_basebackup -h master_ip_address -U replicator -D /var/lib/postgresql/11/main/ -P --password --slot replicator

Se te pedirá una contraseña. Introduce la contraseña que elegiste para el rol de replicador durante su creación en el maestro. Una vez completada la transferencia, concede la propiedad del directorio de datos al usuario postgres:

chown -R postgres:postgres /var/lib/postgresql/11/main

Paso 5: Configuración del Standby

Este paso sólo se refiere al servidor secundario/esclavo.

Activa el modo de espera en caliente en postgresql.conf:

$EDITOR /etc/postgresql/11/main/postgresql.conf

Busca y descomenta la siguiente línea:

#hot_standby = on

Crea el archivo recovery. conf en el directorio de datos de Postgres:

$EDITOR /var/lib/postgresql/11/main/recovery.conf

Habilita el modo de espera:

standby_mode = 'on'

Establece los parámetros de conexión de replicación utilizando las credenciales creadas en el maestro:

primary_conninfo = 'host=master_ip_address port=5432 user=replicator password=replicator_password'

Establece el nombre de la ranura de replicación que has creado en el maestro:

primary_slot_name = 'replicator'

Establece la ruta de un archivo de activación de la conmutación por error:

trigger_file = '/var/lib/postgresql/11/main/failover.trigger'

Si se establece el parámetro archivo_desencadenante, Postgres saldrá del modo de espera e iniciará el funcionamiento normal como servidor primario cuando se cree este archivo desencadenante. Este parámetro no es necesario.

Tras crear recovery.conf, concede la propiedad al usuario postgres:

chown postgres:postgres /var/lib/postgresql/11/main/recovery.conf

Ahora puedes iniciar Postgres:

systemctl start [email protected]

Ahora está en modo de espera y debería replicar cualquier transacción nueva.

Probando

Probar la replicación

Para probar la replicación, realiza cualquier acción de escritura en el maestro. Por ejemplo, crea una nueva base de datos en el maestro:

sudo -u postgres psql -c "CREATE DATABASE replitest"

Espera unos segundos y luego lista las bases de datos en el esclavo:

sudo -u postgres psql -c "\l"

Deberías ver que la base de datos de la prueba de replicación fue efectivamente replicada por el servidor en espera:

List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 replitest | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
(4 rows)

Probar la conmutación por error

NOTA: Para probar la conmutación por error como se muestra aquí, será necesario reiniciar el servidor en espera después de la conmutación por error.

Como Postgres está en modo de espera, no deberías poder realizar ninguna operación de escritura en el nodo secundario antes de la conmutación por error. Por ejemplo, ejecuta el siguiente comando:

sudo -u postgres psql -c "CREATE DATABASE test"

El comando debería fallar:

ERROR:  cannot execute CREATE DATABASE in a read-only transaction

Para señalar la conmutación por error, crea el archivo de activación especificado en recovery.conf

touch /var/lib/postgresql/11/main/failover.trigger

Espera unos segundos y luego intenta realizar una operación de escritura. Por ejemplo:

sudo -u postgres psql -c "CREATE DATABASE test2"

Como Postgres ya no está funcionando como standby, la operación tendrá éxito. Postgres también cambiará el nombre de tu archivo recovery . conf por recovery.done, y eliminará el archivo de activación.

Para volver al modo de espera, detén Postgres en el (antiguo) nodo secundario:

systemctl stop [email protected]

Restablece el directorio de datos:

mv /var/lib/postgresql/11/main/ /var/lib/postgresql/11/main.2.bak
pg_basebackup -h master_ip_address -U replicator -D /var/lib/postgresql/11/main/ -P --password --slot replicator
chown -R postgres:postgres /var/lib/postgresql/11/main

Y vuelve a crear recovery.conf:

cp /var/lib/postgresql/11/main.2.bak/recovery.done /var/lib/postgresql/11/main/recovery.conf

Por último, reinicia Postgres:

systemctl start [email protected]

La instancia secundaria vuelve a estar en modo de espera. Es posible que quieras volver a probar la replicación en este punto.

Para terminar

Elimina cualquier base de datos innecesaria en el nodo maestro, por ejemplo:

sudo -u postgres psql
postgres=# DROP DATABASE replitest;

Y elimina los directorios de datos antiguos en el nodo en espera:

rm /var/lib/postgresql/11/main.bak -r
rm /var/lib/postgresql/11/main.2.bak -r

También te podría gustar...