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