¿Qué son las ranuras de replicación?
En los días en que aún no se introdujeron las "ranuras de replicación", administrar los segmentos WAL era un desafío. En la replicación de transmisión estándar, el maestro no tiene conocimiento del estado del esclavo. Tome el ejemplo de un maestro que ejecuta una gran transacción, mientras que un nodo en espera está en modo de mantenimiento durante un par de horas (como actualizar los paquetes del sistema, ajustar la seguridad de la red, actualizar el hardware, etc.). En algún momento, el maestro elimina su registro de transacciones (segmentos WAL) a medida que pasa el punto de control. Una vez que el esclavo está fuera de mantenimiento, posiblemente tenga un retraso de esclavo enorme y tenga que ponerse al día con el maestro. Eventualmente, el esclavo obtendrá un problema fatal como el siguiente:
LOG: started streaming WAL from primary at 0/73000000 on timeline 1
FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 000000010000000000000073 has already been removed
El enfoque típico es especificar en su postgresql.conf una secuencia de comandos de archivo WAL que copiará los archivos WAL en una o más ubicaciones de archivo a largo plazo. Si no tiene ningún recurso de reserva u otros clientes de replicación de transmisión, básicamente el servidor puede descartar el archivo WAL una vez que el script de archivo haya terminado o responda correctamente. Pero aún necesitará algunos archivos WAL recientes para la recuperación de fallas (los datos de los archivos WAL recientes se reproducen durante la recuperación de fallas. En nuestro ejemplo de un nodo en espera que se coloca durante un largo período de mantenimiento, surgen problemas cuando vuelve a conectarse y pregunta principal para un archivo WAL que el principal ya no tiene, la replicación falla.
Este problema se solucionó en PostgreSQL 9.4 a través de "Ranuras de replicación".
Si no usa ranuras de replicación, una forma común de reducir el riesgo de fallar en la replicación es configurar wal_keep_segments lo suficientemente alto para que los archivos WAL que puedan ser necesarios no se roten o reciclen. La desventaja de este enfoque es que es difícil determinar qué valor es mejor para su configuración. No necesitará mantenimiento diario o no necesitará retener una gran cantidad de archivos WAL que consumen su almacenamiento en disco. Si bien esto funciona, no es una solución ideal, ya que arriesgar espacio en disco en el maestro puede hacer que las transacciones entrantes fallen.
Los enfoques alternativos de no usar ranuras de replicación son configurar PostgreSQL con archivado continuo y proporcionar un comando de restauración para dar acceso a la réplica al archivo. Para evitar la acumulación de WAL en el principal, puede usar un volumen o dispositivo de almacenamiento independiente para los archivos WAL, por ejemplo, SAN o NFS. Otra cosa es con la replicación síncrona, ya que requiere que el primario tenga que esperar a que los nodos en espera confirmen la transacción. Esto significa que asegura que los archivos WAL se hayan aplicado a los nodos en espera. Pero aún así, es mejor que proporcione comandos de archivado desde el primario para que una vez que los WAL se reciclen en el primario, tenga la seguridad de que tiene copias de seguridad de WAL en caso de recuperación. Aunque en algunas situaciones, la replicación síncrona no es una solución ideal, ya que conlleva cierta sobrecarga de rendimiento en comparación con la replicación asíncrona.
Tipos de ranuras de replicación
Hay dos tipos de ranuras de replicación. Estos son:
Ranuras de replicación físicas
Se puede utilizar para la replicación de transmisión estándar. Se asegurarán de que los datos no se reciclen demasiado pronto.
Ranuras de replicación lógica
La replicación lógica hace lo mismo que las ranuras de replicación física y se utilizan para la replicación lógica. Sin embargo, se utilizan para la decodificación lógica. La idea detrás de la decodificación lógica es dar a los usuarios la oportunidad de adjuntar el registro de transacciones y decodificarlo con un complemento. Permite extraer los cambios realizados en la base de datos y por lo tanto en el registro de transacciones en cualquier formato y para cualquier propósito.
En este blog, usaremos ranuras de replicación física y cómo lograr esto usando ClusterControl.
Ventajas y desventajas de usar ranuras de replicación
Las ranuras de replicación son definitivamente beneficiosas una vez habilitadas. De forma predeterminada, las "ranuras de replicación" no están habilitadas y deben configurarse manualmente. Entre las ventajas de usar Slots de replicación están
- Asegura que el maestro conserve suficientes segmentos WAL para que todas las réplicas los reciban
- Evita que el maestro elimine filas que podrían causar un conflicto de recuperación en las réplicas
- Un maestro solo puede reciclar el registro de transacciones una vez que lo hayan consumido todas las réplicas. La ventaja aquí es que un esclavo nunca puede retrasarse tanto como para necesitar una resincronización.
Las ranuras de replicación también vienen con algunas advertencias.
- Una ranura de replicación huérfana puede provocar un crecimiento ilimitado del disco debido a la acumulación de archivos WAL del maestro
- Los nodos esclavos colocados bajo un mantenimiento prolongado (como días o semanas) y que están vinculados a una ranura de replicación tendrán un crecimiento de disco ilimitado debido a la acumulación de archivos WAL del maestro
Puede monitorear esto consultando pg_replication_slots para determinar las ranuras que no se utilizan. Volveremos a revisar esto un poco más tarde.
Uso de ranuras de replicación
Como se indicó anteriormente, hay dos tipos de ranuras de replicación. Para este blog, usaremos ranuras de replicación física para la replicación de transmisión.
Creación de una ranura de replicación
Crear una replicación es simple. Debe invocar la función existente pg_create_physical_replication_slot para hacer esto y debe ejecutarse y crearse en el nodo principal. La función es simple,
maximus_db=# \df pg_create_physical_replication_slot
Schema | pg_catalog
Name | pg_create_physical_replication_slot
Result data type | record
Argument data types | slot_name name, immediately_reserve boolean DEFAULT false, OUT slot_name name, OUT xlog_position pg_lsn
Type | normal
p. ej. Creando una ranura de replicación llamada slot1,
postgres=# SELECT pg_create_physical_replication_slot('slot1');
-[ RECORD 1 ]-----------------------+---------
pg_create_physical_replication_slot | (slot1,)
Los nombres de las ranuras de replicación y su configuración subyacente son solo para todo el sistema y no para todo el clúster. Por ejemplo, si tiene el nodo A (maestro actual) y los nodos en espera nodo B y nodo C, creando la ranura en un nodo A maestro, a saber, "ranura 1", los datos no estarán disponibles para el nodo B y el nodo C. Por lo tanto, cuando esté a punto de producirse una conmutación por error/conmutación, debe volver a crear las ranuras que ha creado.
Descartar una ranura de replicación
Las ranuras de replicación no utilizadas deben descartarse o eliminarse. Como se indicó anteriormente, cuando hay ranuras de replicación huérfanas o ranuras que no se han asignado a ningún cliente o nodo en espera, puede generar problemas de espacio en disco ilimitado si no se eliminan. Por lo tanto, es muy importante que estos se dejen caer cuando ya no se usen. Para colocarlo, simplemente invoque pg_drop_replication_slot. Esta función tiene la siguiente definición:
maximus_db=# \df pg_drop_replication_slot
Schema | pg_catalog
Name | pg_drop_replication_slot
Result data type | void
Argument data types | name
Type | normal
Dejarlo es simple:
maximus_db=# select pg_drop_replication_slot('slot2');
-[ RECORD 1 ]------------+-
pg_drop_replication_slot |
Supervisión de las ranuras de replicación de PostgreSQL
Supervisar sus ranuras de replicación es algo que no querrá perderse. Simplemente recopile la información de la vista pg_replication_slots en el nodo principal/principal como se muestra a continuación:
postgres=# select * from pg_replication_slots;
-[ RECORD 1 ]-------+-----------
slot_name | main_slot
plugin |
slot_type | physical
datoid |
database |
active | t
active_pid | 16297
xmin |
catalog_xmin |
restart_lsn | 2/F4000108
confirmed_flush_lsn |
-[ RECORD 2 ]-------+-----------
slot_name | main_slot2
plugin |
slot_type | physical
datoid |
database |
active | f
active_pid |
xmin |
catalog_xmin |
restart_lsn |
confirmed_flush_lsn |
El resultado anterior muestra que se ha tomado main_slot, pero no main_slot2.
Otra cosa que puede hacer es monitorear cuánto retraso tiene con respecto a las máquinas tragamonedas. Para lograr esto, simplemente puede usar la consulta basada en el resultado de la muestra a continuación:
postgres=# SELECT redo_lsn, slot_name,restart_lsn,
round((redo_lsn-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
redo_lsn | slot_name | restart_lsn | gb_behind
------------+-----------+-------------+-----------
1/8D400238 | slot1 | 0/9A000000 | 3.80
Pero redo_lsn no está presente en 9.6, deberá usar redo_location, por lo que en 9.6,
imbd=# SELECT redo_location, slot_name,restart_lsn,
round((redo_location-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
-[ RECORD 1 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot
restart_lsn | 2/F6008CC0
gb_behind | 0.00
-[ RECORD 2 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot2
restart_lsn | 2/F6008CC0
gb_behind | 0.00
Requisitos de variables del sistema
La implementación de ranuras de replicación requiere una configuración manual. Hay variables que debe tener en cuenta que requieren cambios y se especifican en su postgresql.conf. Ver a continuación:
- max_replication_slots:si se establece en 0, significa que las ranuras de replicación están totalmente deshabilitadas. Si está utilizando versiones de PostgreSQL <10, esta ranura debe especificarse en un valor distinto de 0 (predeterminado). Desde PostgreSQL 10, el valor predeterminado es 10. Esta variable especifica el número máximo de ranuras de replicación. Establecerlo en un valor más bajo que el número de ranuras de replicación existentes actualmente evitará que el servidor se inicie.
- wal_level:al menos debe ser una réplica o superior (la réplica es la opción predeterminada). La configuración de hot_standby o el archivo se asignará a la réplica. Para una ranura de replicación física, la réplica es suficiente. Para las ranuras de replicación lógica, se prefiere la lógica.
- max_wal_senders:establecido en 10 de forma predeterminada, 0 en la versión 9.6, lo que significa que la replicación está deshabilitada. Le sugerimos que configure esto al menos en 16, especialmente cuando se ejecuta con ClusterControl.
- hot_standby:en las versiones <10, debe configurarlo en activado, que está desactivado de forma predeterminada. Esto es importante para los nodos en espera, lo que significa que, cuando está activado, puede conectarse y ejecutar consultas durante la recuperación o en modo de espera.
- primary_slot_name:esta variable se establece a través de recovery.conf en el nodo en espera. Esta es la ranura que utilizará el receptor o el nodo en espera cuando se conecte con el remitente (o primario/maestro).
Debe tener en cuenta que estas variables en su mayoría requieren un reinicio del servicio de la base de datos para recargar nuevos valores.
Uso de ranuras de replicación en un entorno PostgreSQL de ClusterControl
Ahora, veamos cómo podemos usar ranuras de replicación física e implementarlas dentro de una configuración de Postgres administrada por ClusterControl.
Implementación de nodos de base de datos PostgreSQL
Comencemos a implementar un clúster PostgreSQL de 3 nodos usando ClusterControl usando la versión 9.6 de PostgreSQL esta vez.
ClusterControl implementará nodos con las siguientes variables del sistema definidas según sus valores predeterminados o valores ajustados. en:
postgres=# select name, setting from pg_settings where name in ('max_replication_slots', 'wal_level', 'max_wal_senders', 'hot_standby');
name | setting
-----------------------+---------
hot_standby | on
max_replication_slots | 0
max_wal_senders | 16
wal_level | replica
(4 rows)
En las versiones de PostgreSQL> 9.6, el valor predeterminado de max_replication_slots es 10, que está habilitado de manera predeterminada, pero no en las versiones 9.6 o anteriores, que está deshabilitado de manera predeterminada. Debe asignar max_replication_slots superior a 0. En este ejemplo, establecí max_replication_slots en 5.
[email protected]:~# grep 'max_replication_slots' /etc/postgresql/9.6/main/postgresql.conf
# max_replication_slots = 0 # max number of replication slots
max_replication_slots = 5
y reiniciamos el servicio,
[email protected]:~# pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
9.6 main 5432 online postgres /var/lib/postgresql/9.6/main pg_log/postgresql-%Y-%m-%d_%H%M%S.log
[email protected]:~# pg_ctlcluster 9.6 main restart
Configuración de las ranuras de replicación para los nodos principal y de reserva
No hay ninguna opción en ClusterControl para hacer esto, por lo que debe crear sus ranuras manualmente. En este ejemplo, creé las ranuras en el servidor principal 192.168.30.100:
192.168.10.100:5432 [email protected]_db=# SELECT pg_create_physical_replication_slot('slot1'), pg_create_physical_replication_slot('slot2');
pg_create_physical_replication_slot | pg_create_physical_replication_slot
-------------------------------------+-------------------------------------
(slot1,) | (slot2,)
(1 row)
Comprobando lo que acabamos de crear,
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | f | | | | |
slot2 | | physical | | | f | | | | |
(2 rows)
Ahora, en los nodos en espera, necesitamos actualizar recovery.conf y agregar la variable primary_slot_name y cambiar application_name para que sea más fácil identificar el nodo. Así es como se ve en el host 192.168.30.110 recovery.conf:
[email protected]:/var/lib/postgresql/9.6/main/pg_log# cat ../recovery.conf
standby_mode = 'on'
primary_conninfo = 'application_name=node11 host=192.168.30.100 port=5432 user=cmon_replication password=m8rLmZxyn23Lc2Rk'
recovery_target_timeline = 'latest'
primary_slot_name = 'slot1'
trigger_file = '/tmp/failover_5432.trigger'
Hacer lo mismo en el host 192.168.30.120 pero cambiar el application_name y establecer el primary_slot_name ='slot2'.
Comprobación del estado de la ranura de replicación:
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | t | 24252 | | | 0/CF0A4218 |
slot2 | | physical | | | t | 11635 | | | 0/CF0A4218 |
(2 rows)
¿Qué más necesitas?
Dado que ClusterControl no es compatible con las ranuras de replicación en este momento, hay cosas que debe tener en cuenta. ¿Que son estos? Entremos en detalles.
Proceso de conmutación por error/conmutación
Cuando se intenta una conmutación por error automática o una conmutación a través de ClusterControl, las ranuras no se conservarán en los nodos principal y en espera. Debe volver a crear esto manualmente, verificar las variables si están configuradas correctamente y modificar el archivo recovery.conf en consecuencia.
Reconstruir un esclavo a partir de un maestro
Al reconstruir un esclavo, el archivo recovery.conf no se conservará. Esto significa que la configuración de recovery.conf que tiene el nombre_ranura_principal se borrará. Debe especificar esto manualmente nuevamente y verificar la vista pg_replication_slots para determinar si las ranuras se usan correctamente o se dejan huérfanas.
Si desea reconstruir el nodo esclavo/en espera a partir de un maestro, es posible que deba considerar especificar la variable de entorno PGAPPNAME como el siguiente comando:
$ export PGAPPNAME="app_repl_testnode15"; /usr/pgsql-9.6/bin/pg_basebackup -h 192.168.10.190 -U cmon_replication -D /var/lib/pgsql/9.6/data -p5434 -W -S main_slot -X s -R -P
Especificar el parámetro -R es muy importante, ya que volverá a crear el archivo recovery.conf, mientras que -S especificará qué nombre de ranura usar al reconstruir el nodo en espera.
Conclusión
La implementación de las ranuras de replicación en PostgreSQL es sencilla, pero hay ciertas advertencias que debe recordar. Al implementar con ClusterControl, deberá actualizar algunas configuraciones durante la conmutación por error o las reconstrucciones de esclavos.