PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Ao executar o PITR, seria possível Pausar/Retomar no PostgreSQL?

Sim, realmente possível e tratado com inteligência pelo PostgreSQL. Para demonstrar isso, primeiro preciso seguir a técnica padrão de Point in Time Recovery no PostgreSQL. Vários Livros/Artigos/Blogs extremamente bem demonstrados por autores extraordinários, portanto, não entrarei em detalhes de como fazê-lo, no entanto, indo diretamente ao assunto, ou seja, como pausar enquanto se recupera com a mesma técnica. Indiscutivelmente, eu apresentei uma expressão matemática fora do PITR como “PITR =(Último Backup do Sistema de Arquivos (LFB) + Arquivos WAL gerados após LFB + WALs não arquivados no atual $ PGDATA/pg_xlogs)”. Para melhor compreensão, coloquei isso em gráfico, pois esclarece mais o pensamento:(Desculpe, este blog é um pouco longo, sem saber isso aconteceu ao entrar em detalhes do conceito)

Etapas do PITR, que seguirei com pequenas mudanças que falarei em breve:

Etapa 1. Restaure o backup no nível do sistema de arquivos (FSB) mais recente para qualquer local onde a recuperação esteja planejada.
Etapa 2. Se o FSB for tar, descompacte-o e limpe o diretório pg_xlog deixando archive_status. Se o backup excluiu este diretório, crie o diretório pg_xlog vazio no FSB.
Etapa 3. Copie WALs não arquivados do cluster com falha $PGDATA/pg_xlog para $FSB/pg_xlog (Etapa 2)
Etapa 4. Exclua o postmaster.pid do diretório FSB.
Etapa 5. Crie o arquivo recovery.conf no diretório FSB.
Etapa 6. Inicie o cluster (FSB).

Devemos colocar a questão, ao pausar a recuperação necessária?. Talvez, para evitar várias restaurações de base ou recuperação de roll-forward, mas verifique entre ou reverta dados ou interesses de uma determinada tabela para ver até que ponto ela se recuperou :). Lembre-se, pausar na recuperação significa permitir a conexão durante a recuperação. Para delinear isso, reproduzi uma situação no gráfico de uma melhoria de linhas de uma tabela específica até um contratempo.

A partir do diagrama acima, é aceitável que as linhas da tabela DEMO sejam 10.00.000 quando o backup no nível do sistema de arquivos ($PGDATA) foi feito e 40.00.000 linhas antes da falha. Na minha VM local, fiz a situação com base em TIME em vez de data.

Pré-requisito:
1. Backup em nível de sistema de arquivos quando tabelas DEMO com 10.00.000 linhas.
2. Desse ponto em diante, o WAL Archives antes do crash onde a tabela DEMO tinha 40.00.000 linhas.
3. Localização dos Arquivos WAL:/opt/PostgreSQL/9.3/archives.
4. Diretório de dados:/opt/PostgreSQL/9.3/data (PGDATA)
5. Local de backup:/opt/PostgreSQL/9.3/backups

Lembre-se de que trabalhar com recuperação de pausa precisa de alterações obrigatórias no cluster principal ($PGDATA) “wal_level” definido como “hot_standby” e no cluster de recuperação (backup no nível do sistema de arquivos) “hot_standby” definido como “ON”. Fiz essas alterações no cluster principal, reiniciei o cluster para entrar em vigor e iniciei o backup. Se você não se importa de anotar, é apenas uma demonstração, então meus arquivos WAL podem não ser números gigantescos, pois são em poucos números. Também listei os arquivos WAL aqui, que foram gerados desde o momento do backup até o travamento.
-bash-4.1$ psql -c "select count(*), now() from demo;"
count | now
---------+-------------------------------
1000000 | 2014-04-04 15:06:04.036928-07
(1 row)

-bash-4.1$ pg_basebackup -D /opt/PostgreSQL/9.3/backup/data_pitr -- I have my $PGDATA, $PGUSER, $PGPORT set, so its a straight command in my case
NOTICE: pg_stop_backup complete, all required WAL segments have been archived

Estado atual dos arquivos WAL e $PGDATA/pg_xlog
-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001C
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001D
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/data/pg_xlog | tail -4
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
drwx------ 2 postgres postgres 4.0K Apr 4 16:13 archive_status

Tudo bem agora, temos a cópia de backup, permite INSERT alguns registros em três partes, observando o tempo, para ajudar a pausar a recuperação e, além disso, ver os WAL's produzidos a partir da época do FSB.
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
2000000 | 2014-04-04 16:06:34.941615-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
3000000 | 2014-04-04 16:10:31.136725-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
4000000 | 2014-04-04 16:13:00.136725-07
(1 row)

Verifique o número de WAL’s produzidos durante o INSERT.
-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000020
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000021
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000022
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000023
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000024
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000025
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000026
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000027
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000028
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000029
-rw------- 1 postgres postgres 16M Apr 4 16:10 00000001000000000000002A
-rw------- 1 postgres postgres 16M Apr 4 16:13 00000001000000000000002B

Suponha que neste momento aconteceu um acidente e você tenha que fazer a recuperação usando arquivos FSB + WAL + WALs não arquivados (se houver). Durante a recuperação, quero pausar três vezes para ver cada recuperação de 20.00.000, 30.00.000 e 40.00.000 linhas da tabela DEMO conectando-se ao banco de dados no modo READ-ONLY. Para cada retomada de recuperação, é necessário reiniciar o cluster de recuperação, passando para uma nova linha do tempo em recovery.conf/recovery_target_time. Além disso, em $FSB/postgresql.conf, temos que definir hot_standby=on. Aqui está meu arquivo recovery.conf:
-bash-4.1$ more recovery.conf
pause_at_recovery_target = true
#recovery_target_time = '2014-04-04 16:06:34' # For 2 lakh records
#recovery_target_time = '2014-04-04 16:10:31' # For 3 lakh records
#recovery_target_time = '2014-04-04 16:13:00' # For 4 lakh records
restore_command = 'cp /opt/PostgreSQL/9.3/archives/%f %p'

Vamos iniciar a recuperação de 20.00.000 registros:
-bash-4.1$ /opt/PostgreSQL/9.3/bin/pg_ctl -D /opt/PostgreSQL/9.3/data_pitr/ start
server starting

Now in logs:

-bash-4.1$ more postgresql-2014-04-04_162524.log
2014-04-04 16:25:24 PDT-24187---[] LOG: starting point-in-time recovery to 2014-02-06 18:48:56-08
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001E" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: redo starts at 0/1E0000C8
2014-04-04 16:25:24 PDT-24187---[] LOG: consistent recovery state reached at 0/1E000190
2014-04-04 16:25:24 PDT-24185---[] LOG: database system is ready to accept read only connections
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001F" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "000000010000000000000020" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000021" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000022" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery stopping before commit of transaction 1833, time 2014-04-04 16:06:23.893487-07
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery has paused
2014-04-04 16:25:25 PDT-24187---[] HINT: Execute pg_xlog_replay_resume() to continue

Legal, veja nos logs ele pausou e uma dica inteligente pedindo para retomar. Aqui, se a recuperação foi satisfatória, você pode retomá-la chamando “select pg_xlog_replay_resume();”(Você pode conferir). Não vamos retomar agora, mas verifique o número de linhas recuperadas conectando-se ao servidor.
-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
2000000 | t
(1 row)

Bom, chegou ao ponto e parou onde eu pedi. Vamos avançar mais um passo para recuperar 30.00.000 linhas. Agora, defina a próxima linha do tempo em recovery.conf/recovery_target_time e reinicie o cluster.
2014-04-04 16:28:40 PDT-24409---[] LOG:  restored log file "00000001000000000000002A" from archive
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery stopping before commit of transaction 1836, time 2014-04-04 16:10:40.141175-07
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery has paused
2014-04-04 16:28:40 PDT-24409---[] HINT: Execute pg_xlog_replay_resume() to continue.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
3000000 | t
(1 row)

Legal…, vamos dar a última tentativa de pausar em 40.00.000 linhas.
2014-04-04 20:09:07 PDT-4723---[] LOG:  restored log file "00000001000000000000002B" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001000000000000002C': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: redo done at 0/2B0059A0
2014-04-04 20:09:07 PDT-4723---[] LOG: last completed transaction was at log time 2014-04-04 16:11:12.264512-07
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000001000000000000002B" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000002.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000003.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000004.history" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000005.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: selected new timeline ID: 5
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: archive recovery complete
2014-04-04 20:09:08 PDT-4721---[] LOG: database system is ready to accept connections
2014-04-04 20:09:08 PDT-4764---[] LOG: autovacuum launcher started

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
4000000 | f
(1 row)

Ops, o que aconteceu, por que não parou e o que está reclamando?. Lembre-se de que, se nenhum arquivo WAL estiver presente no momento de recovery_target_time, ele não fará uma pausa e esperará que tenha chegado ao último ponto e aberto o banco de dados para READ/WRITE. Nos logs, sem muito esforço, ele estava caçando o arquivo “00000001000000000000002C” que não está disponível, porque naquele momento o cluster travou. Alguns podem não reconhecer esse comportamento, mas é fato e faz sentido quando não há arquivos WAL presentes, não há motivo para pausar a recuperação. Se for necessário pausar mesmo após nenhum arquivo WAL, use standby_mode='on' (HOT_STANDBY), neste método ele não sairá da recuperação, mas aguarde os Arquivos WAL.

Espero que tenha sido útil.