O que são slots de replicação?
Nos dias em que os "Slots de replicação" ainda não eram introduzidos, gerenciar os segmentos WAL era um desafio. Na replicação de streaming padrão, o mestre não tem conhecimento do status do escravo. Tomemos o exemplo de um mestre que executa uma grande transação, enquanto um nó em espera fica em modo de manutenção por algumas horas (como atualizar os pacotes do sistema, ajustar a segurança da rede, atualizar o hardware etc.). Em algum momento, o mestre remove seu log de transações (segmentos WAL) à medida que o ponto de verificação passa. Uma vez que o escravo está fora de manutenção, ele possivelmente tem um grande atraso no escravo e precisa alcançar o mestre. Eventualmente, o escravo terá um problema fatal como abaixo:
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
A abordagem típica é especificar em seu postgresql.conf um script de arquivamento WAL que copiará arquivos WAL para um ou mais locais de arquivamento de longo prazo. Se você não tiver esperas ou outros clientes de replicação de streaming, basicamente o servidor poderá descartar o arquivo WAL assim que o script de arquivamento for concluído ou responder OK. Mas você ainda precisará de alguns arquivos WAL recentes para recuperação de falhas (os dados de arquivos WAL recentes são reproduzidos durante a recuperação de falhas. Em nosso exemplo de um nó em espera que é colocado por um longo período de manutenção, surgem problemas quando ele volta a ficar online e pergunta o primário para um arquivo WAL que o primário não possui mais, a replicação falhará.
Esse problema foi resolvido no PostgreSQL 9.4 por meio de "Slots de replicação".
Se não estiver usando slots de replicação, uma maneira comum de reduzir o risco de falha na replicação é definir wal_keep_segments alto o suficiente para que os arquivos WAL que possam ser necessários não sejam rotacionados ou reciclados. A desvantagem dessa abordagem é que é difícil determinar qual valor é melhor para sua configuração. Você não precisará de manutenção diariamente ou não precisará reter uma grande pilha de arquivos WAL que consomem seu armazenamento em disco. Embora isso funcione, não é uma solução ideal, pois arriscar espaço em disco no mestre pode fazer com que as transações de entrada falhem.
Uma abordagem alternativa de não usar slots de replicação é configurar o PostgreSQL com arquivamento contínuo e fornecer um comando restore_command para dar à réplica acesso ao arquivo. Para evitar o acúmulo de WAL no primário, você pode usar um volume ou dispositivo de armazenamento separado para os arquivos WAL, por exemplo, SAN ou NFS. Outra coisa é com a replicação síncrona, pois requer que o primário tenha que esperar que os nós em espera confirmem a transação. Isso significa que ele garante que os arquivos WAL foram aplicados aos nós em espera. Ainda assim, é melhor que você forneça comandos de arquivamento do primário para que, uma vez que os WALs sejam reciclados no primário, tenha certeza de que você tem backups do WAL em caso de recuperação. Embora, em algumas situações, a replicação síncrona não seja uma solução ideal, pois apresenta alguma sobrecarga de desempenho em comparação com a replicação assíncrona.
Tipos de slots de replicação
Existem dois tipos de slots de replicação. Esses são:
Slots de replicação física
Pode ser usado para replicação de streaming padrão. Eles garantirão que os dados não sejam reciclados muito cedo.
Slots de replicação lógica
A replicação lógica faz a mesma coisa que os slots de replicação física e são usados para replicação lógica. No entanto, eles são usados para decodificação lógica. A ideia por trás da decodificação lógica é dar aos usuários a chance de anexar ao log de transações e decodificá-lo com um plug-in. Permite extrair alterações feitas no banco de dados e, portanto, no log de transações em qualquer formato e para qualquer finalidade.
Neste blog, usaremos slots de replicação física e como fazer isso usando o ClusterControl.
Vantagens e desvantagens de usar slots de replicação
Slots de replicação são definitivamente benéficos uma vez ativados. Por padrão, os "Slots de replicação" não estão ativados e precisam ser definidos manualmente. Entre as vantagens do uso de Slots de Replicação estão
- Garantir que o mestre retenha segmentos WAL suficientes para que todas as réplicas os recebam
- Evita que o mestre remova linhas que possam causar conflito de recuperação nas réplicas
- Um mestre só pode reciclar o log de transações depois que ele for consumido por todas as réplicas. A vantagem aqui é que um escravo nunca pode ficar para trás tanto que uma ressincronização seja necessária.
Os slots de replicação também vêm com algumas ressalvas.
- Um slot de replicação órfão pode causar crescimento de disco ilimitado devido a arquivos WAL empilhados do mestre
- Os nós escravos colocados sob manutenção longa (como dias ou semanas) e que estão vinculados a um slot de replicação terão um crescimento de disco ilimitado devido a arquivos WAL empilhados do mestre
Você pode monitorar isso consultando pg_replication_slots para determinar os slots que não são usados. Vamos verificar isso um pouco mais tarde.
Usando slots de replicação
Como dito anteriormente, existem dois tipos de slots de replicação. Para este blog, usaremos slots de replicação física para replicação de streaming.
Criando um slot de replicação
Criar uma replicação é simples. Você precisa invocar a função existente pg_create_physical_replication_slot para fazer isso e deve ser executada e criada no nó mestre. A função é simples,
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
ex. Criando um slot de replicação chamado slot1,
postgres=# SELECT pg_create_physical_replication_slot('slot1');
-[ RECORD 1 ]-----------------------+---------
pg_create_physical_replication_slot | (slot1,)
Os nomes dos slots de replicação e sua configuração subjacente são apenas para todo o sistema e não para todo o cluster. Por exemplo, se você tiver nodeA (mestre atual) e nós de espera nodeB e nodeC, criando o slot em um nodeA mestre chamado "slot1", os dados não estarão disponíveis para nodeB e nodeC. Portanto, quando o failover/troca está prestes a acontecer, você precisa recriar os slots que criou.
Descartando um slot de replicação
Os slots de replicação não utilizados devem ser descartados ou excluídos. Conforme declarado anteriormente, quando há slots de replicação órfãos ou slots que não foram atribuídos a nenhum cliente ou nó de espera, isso pode levar a problemas de espaço em disco ilimitado se não for descartado. Portanto, é muito importante que eles sejam descartados quando não forem mais usados. Para eliminá-lo, basta invocar pg_drop_replication_slot. Esta função tem a seguinte definição:
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
Eliminar é simples:
maximus_db=# select pg_drop_replication_slot('slot2');
-[ RECORD 1 ]------------+-
pg_drop_replication_slot |
Monitorando seus slots de replicação PostgreSQL
Monitorar seus slots de replicação é algo que você não pode perder. Basta coletar as informações da visualização pg_replication_slots no nó primário/mestre, como abaixo:
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 |
O resultado acima mostra que main_slot foi usado, mas não main_slot2.
Outra coisa que você pode fazer é monitorar o quanto de atraso nos slots você tem. Para conseguir isso, você pode simplesmente usar a consulta com base no resultado da amostra abaixo:
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
Mas redo_lsn não está presente em 9.6, deve-se usar redo_location, então em 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 variável do sistema
A implementação de slots de replicação requer configuração manual. Existem variáveis que você deve ter em mente que requerem mudanças e devem ser especificadas em seu postgresql.conf. Ver abaixo:
- max_replication_slots – Se definido como 0, significa que os slots de replicação estão totalmente desabilitados. Se você estiver usando versões do PostgreSQL <10, esse slot deve ser especificado diferente de 0 (padrão). Desde o PostgreSQL 10, o padrão é 10. Esta variável especifica o número máximo de slots de replicação. Defini-lo com um valor menor do que o número de slots de replicação existentes no momento impedirá que o servidor seja iniciado.
- wal_level – deve ser pelo menos uma réplica ou superior (a réplica é o padrão). A configuração de hot_standby ou archive será mapeada para a réplica. Para um slot de replicação física, a réplica é suficiente. Para slots de replicação lógica, o lógico é o preferido.
- max_wal_senders – definido como 10 por padrão, 0 na versão 9.6, o que significa que a replicação está desabilitada. Sugerimos que você defina isso para pelo menos 16, especialmente ao executar com ClusterControl.
- hot_standby – nas versões <10, você precisa definir isso como desativado por padrão. Isso é importante para nós em espera, o que significa que, quando ativado, você pode se conectar e executar consultas durante a recuperação ou no modo de espera.
- primary_slot_name – essa variável é definida por meio de recovery.conf no nó de espera. Este é o slot a ser usado pelo receptor ou nó de espera ao conectar com o remetente (ou primário/mestre).
Você deve observar que essas variáveis geralmente exigem uma reinicialização do serviço de banco de dados para recarregar novos valores.
Usando slots de replicação em um ambiente ClusterControl PostgreSQL
Agora, vamos ver como podemos usar slots de replicação física e implementá-los em uma configuração do Postgres gerenciada pelo ClusterControl.
Implantação de nós do banco de dados PostgreSQL
Vamos começar a implantar um cluster PostgreSQL de 3 nós usando ClusterControl usando a versão 9.6 do PostgreSQL desta vez.
ClusterControl implantará nós com as seguintes variáveis de sistema definidas de acordo com seus padrões ou valores ajustados. Dentro:
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)
Nas versões do PostgreSQL> 9.6, o valor padrão de max_replication_slots é 10, que é habilitado por padrão, mas não nas versões 9.6 ou inferiores, que é desabilitado por padrão. Você precisa atribuir max_replication_slots maior que 0. Neste exemplo, defino max_replication_slots como 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
e reiniciei o serviço,
[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
Definindo os slots de replicação para nós primários e de espera
Não há opção no ClusterControl para fazer isso, então você precisa criar seus slots manualmente. Neste exemplo, criei os slots no primário no host 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)
Verificando o que acabamos de criar mostra,
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)
Agora, nos nós de espera, precisamos atualizar o recovery.conf e adicionar a variável primary_slot_name e alterar o application_name para que seja mais fácil identificar o nó. Veja como fica no 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'
Fazendo a mesma coisa no host 192.168.30.120, mas alterou o application_name e defina o primary_slot_name ='slot2'.
Verificando a integridade do slot de replicação:
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)
O que mais você precisa?
Como o ClusterControl não suporta slots de replicação neste momento, há coisas que você precisa levar em consideração. Quem são esses? Vamos entrar em detalhes.
Processo de failover/troca
Quando um failover automático ou alternância por meio do ClusterControl for tentado, os slots não serão retidos nos nós primário e em espera. Você precisa recriar isso manualmente, verificar se as variáveis estão configuradas corretamente e modificar o recovery.conf de acordo.
Reconstruindo um escravo a partir de um mestre
Ao reconstruir um slave, o recovery.conf não será retido. Isso significa que suas configurações do recovery.conf com o nome_do_slot_primário serão apagadas. Você precisa especificar isso manualmente novamente e verificar a visualização pg_replication_slots para determinar se os slots estão sendo usados corretamente ou deixados órfãos.
Se você quiser reconstruir o nó slave/standby a partir de um master, talvez seja necessário especificar a variável env PGAPPNAME como no comando abaixo:
$ 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 o parâmetro -R é muito importante para recriar o recovery.conf, enquanto -S deve especificar qual nome de slot usar ao reconstruir o nó de espera.
Conclusão
A implementação dos Slots de Replicação no PostgreSQL é simples, mas há algumas advertências que você deve lembrar. Ao implantar com o ClusterControl, você precisará atualizar algumas configurações durante o failover ou reconstruções de escravos.