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

Backup incremental do PostgreSQL e recuperação pontual


O PostgreSQL vem com a capacidade de fazer backups incrementais e recuperação pontual fora da caixa. Continue lendo para saber mais sobre as configurações e os procedimentos para conseguir isso.

Começa com arquivos WAL


WAL significa Write Ahead Log . Os WALs são usados ​​em quase todos os sistemas RDBMS modernos para fornecer transações atômicas e duráveis.

Alterações nos dados contidos em um cluster de banco de dados PostgreSQL gerenciado por um único processo do servidor PostgreSQL só são possíveis por meio de transações. As modificações feitas nos dados por transações são registradas como uma sequência ordenada de registros WAL . Esses registros são gravados em arquivos de tamanho fixo chamados arquivos de segmento WAL , ou simplesmente arquivos WAL .

Os arquivos WAL ficam em $PGDATA/pg_wal , onde $PGDATA é o diretório de dados para o cluster de banco de dados. Em uma instalação padrão do Debian, por exemplo, o diretório de arquivos WAL para o cluster principal é /var/lib/postgresql/10/main/pg_wal . Aqui está como ele se parece:
# pwd
/var/lib/postgresql/10/main/pg_wal
# ls -l
total 278532
-rw------- 1 postgres postgres 16777216 May  7 08:48 00000001000000000000000B
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000C
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000D
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000E
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000F
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000010
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000011
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000012
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000013
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000014
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000015
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000016
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000017
-rw------- 1 postgres postgres 16777216 May 16 20:52 000000010000000000000018
-rw------- 1 postgres postgres 16777216 May 16 20:56 000000010000000000000019
-rw------- 1 postgres postgres 16777216 May 26 08:52 00000001000000000000001A
-rw------- 1 postgres postgres 16777216 Jun  2 09:59 00000001000000000000001B
drwx------ 2 postgres postgres     4096 Mar 30 10:06 archive_status

Os arquivos WAL são gerados de forma incremental, em sequência, a partir da criação do cluster. Eles continuam sendo gerados enquanto ocorrerem modificações no cluster. O mecanismo de arquivo WAL é essencial para o funcionamento do PostgreSQL e não pode ser desativado.

Depois que as alterações são gravadas como registros WAL, elas devem ser aplicadas à representação em disco dos próprios dados. Esse processo é chamado deponto de verificação , e acontece em segundo plano automaticamente (também pode ser forçado manualmente). O ponto até o qual o checkpoint foi feito é chamado deponto REDO . O checkpointing também é uma parte essencial da arquitetura Postgres e não pode ser desativado.

Retenção de arquivo WAL


No curso normal da operação do servidor PostgreSQL, os arquivos WAL continuarão sendo escritos no pg_wal diretório. Mas por que tê-los por perto?

Uma razão é a recuperação de falhas. Se o servidor PostgreSQL travar e reiniciar, ele começa a aplicar as alterações dos registros WAL nos arquivos de dados (checkpointing) desde o último ponto REDO. Isso garante que os arquivos de dados sejam consistentes com a última transação concluída.

Outro motivo está relacionado à replicação de streaming. A replicação de streaming funciona enviando registros WAL para standby servidores, que armazenam esses locais e realizam checkpoints. Standbys podem ficar atrás do servidor do qual estão replicando (chamado de primário ). Por exemplo, se o primário gerou 100 registros WAL e o standby recebeu e aplicou os primeiros 80, é necessário que os 20 mais recentes estejam disponíveis para que o standby possa receber e aplicar do registro 81 em diante.

Mas certamente os arquivos WAL muito antigos podem ser excluídos? Sim. O PostgreSQL pode ser instruído a reter os arquivos WAL mais recentes e excluir os mais antigos. Existem três opções de configuração relevantes:
  • wal_keep_segments - define o número mínimo de arquivos WAL mais recentes a serem mantidos no diretório de arquivos WAL
  • max_wal_size - especifica o tamanho total máximo de arquivos WAL no diretório de arquivos WAL. Se isso for excedido, os mais antigos serão excluídos. No entanto, pode haver motivos (incluindo um valor alto para wal_keep_segments ) que pode impedir que essa configuração seja respeitada.
  • min_wal_size - especifica um tamanho total mínimo para arquivos WAL. Enquanto o tamanho real permanecer abaixo desse valor, nenhum arquivo será excluído.

Na vida real não é possível, ou necessário, armazenar todos os arquivos WAL anteriores sob o pg_wal diretório.

Arquivo de arquivo WAL


O valor real dos arquivos WAL é que eles são um fluxo de mudanças que podem ser gravadas e reproduzidas para obter uma réplica consistente de um cluster PostgreSQL. criado – o comando_arquivo opção de configuração.

Esta opção especifica uma cadeia de comandos do shell que é chamada após a criação de cada arquivo WAL. aqui estão alguns exemplos:
# Copy the file to a safe location (like a mounted NFS volume)
archive_command = 'cp %p /mnt/nfs/%f'

# Not overwriting files is a good practice
archive_command = 'test ! -f /mnt/nfs/%f && cp %p /mnt/nfs/%f'

# Copy to S3 bucket
archive_command = 's3cmd put %p s3://BUCKET/path/%f'

# Copy to Google Cloud bucket
archive_command = 'gsutil cp %p gs://BUCKET/path/%f'

# An external script
archive_command = '/opt/scripts/archive_wal %p'

Existem 2 outras opções também, que devem ser definidas:
# this must be "on" to enable WAL archiving
archive_mode = on

# has to be "replica" (default) or "logical" for WAL archiving
wal_level = replica

Compressão WAL


Você pode compactar os arquivos WAL antes de copiá-los em um local de armazenamento seguro/de longo prazo. No entanto, existe uma opção chamada wal_compression . Ativar isso fará com que o PostgreSQL comprima os registros WAL individuais dentro dos arquivos WAL. Os próprios arquivos WAL terão o mesmo tamanho (normalmente 16 MB), mas conterão uma sequência de registros compactados em vez de registros simples.

Arquivamento Contínuo


O arquivamento WAL também é chamado de arquivamento contínuo e está em vigor,backup incremental .

Antes de iniciar este processo de backup incremental, é necessário um backup completo. Isso estabelece uma linha de base sobre a qual os arquivos WAL podem ser restaurados incrementalmente. Um backup completo pode ser feito por:
  • encerrando o processo do servidor Postgres e copiando o diretório de dados do cluster (enquanto preserva as permissões) ou
  • usando o pg_basebackup em um servidor Postgres em execução.

Recuperação pontual (PITR)


PITR refere-se à capacidade do PostgreSQL de iniciar a partir da restauração de um backup completo e, em seguida, buscar e aplicar progressivamente arquivos WAL arquivados até um timestamp especificado.

Para fazer isso, temos que criar um arquivo chamado “recovery.conf” no diretório de dados do cluster restaurado e iniciar um servidor Postgres para esse diretório de dados. O arquivo recovery.conf contém o timestamp de destino e se parece com isso:
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

O restore_command especifica como buscar um arquivo WAL requerido pelo PostgreSQL. É o inverso de archive_command. O recovery_target_time especifica o tempo até quando precisamos das alterações.

Quando um processo do servidor PostgreSQL inicia e descobre um arquivo recovery.conf arquivo no diretório de dados, ele inicia em um modo especial chamado “modo de recuperação”. Quando no modo de recuperação, as conexões do cliente são recusadas. O Postgres busca os arquivos WAL e os aplica até que o destino de recuperação (neste caso, muda até o timestamp especificado) seja alcançado. Quando o objetivo é alcançado, o servidor por padrão pausa a reprodução do WAL (outras ações são possíveis). Neste ponto, você deve examinar o estado da restauração e, se tudo estiver ok, despause para sair do modo de recuperação e continuar a operação normal.

Juntando tudo


Tudo isso foi um monte de teoria e texto, vamos experimentar para ver como tudo funciona na prática.

Primeiro vamos inicializar um novo cluster:
/tmp/demo$ pg_ctl -D clus1 initdb
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory clus1 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/lib/postgresql/10/bin/pg_ctl -D clus1 -l logfile start

Também criaremos um diretório que servirá como nosso local de armazenamento seguro. Vamos chamar isso de “arquivo”.
/tmp/demo$ mkdir archive
/tmp/demo$ ls -l
total 8
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:02 clus1

Precisamos definir as configurações de arquivo que discutimos anteriormente, antes que possamos iniciar o servidor. Então, vamos adicionar o seguinte ao final de clus1/postgres.conf :
port = 6000
wal_level = logical
archive_mode = on
archive_command = 'cp %p /tmp/demo/archive/%f'
archive_timeout = 60

Nosso comando archive simplesmente copia o arquivo WAL para o diretório de archive que criamos anteriormente.

Também adicionamos o archive_timeout contexto. Normalmente, um arquivo WAL é criado somente quando há registros WAL suficientes para preencher um arquivo WAL de 16 MB. Isso significa que, para servidores com poucas gravações, talvez seja necessário esperar muito tempo para que um arquivo WAL seja criado. A configuração archive_timeout diz ao Postgres que deve crie um arquivo WAL a cada tantos segundos, independentemente de estar cheio ou não.

Aqui definimos isso para 60 (segundos), mas isso é apenas para a demonstração! Você normalmente nunca quer mantê-lo tão baixo.

Vamos também fazer uma cópia de “clus1”. Isso é o equivalente a um backup completo.
/tmp/demo$ cp -Rp clus1 clus2
/tmp/demo$ ls -l
total 12
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus1
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus2

Agora podemos iniciar o cluster:
/tmp/demo$ pg_ctl -D clus1 -l log1 start
waiting for server to start.... done
server started

Vamos adicionar alguns dados.
/tmp/demo$ psql -h /var/run/postgresql -p 6000 postgres
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

postgres=# create database demo;
CREATE DATABASE
postgres=# \c demo
You are now connected to database "demo" as user "postgres".
demo=# create table tbl1 (col1 int);
CREATE TABLE
demo=# insert into tbl1 (col1) select generate_series(1, 10000);
INSERT 0 10000
demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# select now();
              now
-------------------------------
 2019-06-04 14:05:05.657871+00
(1 row)

demo=# \q

Observe que a hora agora é 14:05. Vamos verificar se nosso comando archive está funcionando:
/tmp/demo$ ls -l archive/
total 16384
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001

Sim, temos um único arquivo. Nossa última alteração foi às 14:05, vamos aguardar alguns minutos e depois fazer mais algumas alterações.
/tmp/demo$ psql -h /var/run/postgresql -p 6000 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select now();
              now
-------------------------------
 2019-06-04 14:16:06.093859+00
(1 row)

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# insert into tbl1 (col1) select generate_series(1, 100);
INSERT 0 100
demo=# select count(*) from tbl1;
 count
-------
 10100
(1 row)

demo=# \q

Então agora adicionamos mais 100 linhas, às 14:16. Vamos parar o servidor:
/tmp/demo$ pg_ctl -D clus1 stop
waiting for server to shut down.... done
server stopped
/tmp/demo$

e verifique nosso arquivo novamente:
/tmp/demo$ ls -l archive/
total 65536
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Jun  4 14:05 000000010000000000000002
-rw------- 1 postgres postgres 16777216 Jun  4 14:09 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Jun  4 14:16 000000010000000000000004

Parece bom. Agora vamos tentar fazer uma recuperação PITR de clus2 até o horário14:10.

Primeiro vamos editar o postgres.conf do clus2 e adicionar estas linhas no final:
port = 6001
archive_mode = off

Para reproduzir os arquivos WAL, temos que colocar o servidor PostgreSQL para clus2 (que ainda não iniciamos) em modo de recuperação. Para fazer isso, crie o arquivo chamado “recovery.conf” no clus2:
/tmp/demo$ cat clus2/recovery.conf
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

Este contém o restore_command que faz o oposto doarchive_command anterior , ou seja, copiando o arquivo solicitado do diretório de arquivamento para o diretório pg_wal.

Também definimos o recovery_target_time às 14h10.

Agora começamos clus2:
/tmp/demo$ pg_ctl -D clus2 -l log2 start
waiting for server to start.... done
server started

Para ver o que aconteceu, vamos examinar o arquivo de log:
/tmp/demo$ cat log2
2019-06-04 14:19:10.862 UTC [10513] LOG:  listening on IPv4 address "127.0.0.1", port 6001
2019-06-04 14:19:10.864 UTC [10513] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.6001"
2019-06-04 14:19:10.883 UTC [10514] LOG:  database system was shut down at 2019-06-04 14:02:31 UTC
2019-06-04 14:19:10.883 UTC [10514] LOG:  starting point-in-time recovery to 2019-06-04 14:10:00+00
2019-06-04 14:19:10.903 UTC [10514] LOG:  restored log file "000000010000000000000001" from archive
2019-06-04 14:19:10.930 UTC [10514] LOG:  consistent recovery state reached at 0/16383E8
2019-06-04 14:19:10.930 UTC [10514] LOG:  redo starts at 0/16383E8
2019-06-04 14:19:10.931 UTC [10513] LOG:  database system is ready to accept read only connections
2019-06-04 14:19:11.037 UTC [10514] LOG:  restored log file "000000010000000000000002" from archive
2019-06-04 14:19:11.079 UTC [10514] LOG:  restored log file "000000010000000000000003" from archive
2019-06-04 14:19:11.122 UTC [10514] LOG:  restored log file "000000010000000000000004" from archive
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery stopping before commit of transaction 559, time 2019-06-04 14:16:24.875517+00
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery has paused
2019-06-04 14:19:11.141 UTC [10514] HINT:  Execute pg_wal_replay_resume() to continue.

A recuperação foi rápida (na vida real, pode levar horas ou dias) e o log informa que parou antes de uma determinada transação (que tem um timestamp de> 14:10). Ele também diz que a recuperação está pausada e deve ser continuada manualmente.

Vamos examinar os dados:
/tmp/demo$ psql -h /var/run/postgresql -p 6001 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

Vemos que existem apenas 10.000 linhas. Às 14h16, adicionamos mais 100, que não apareceram na tabela.

Isso parece bom, então vamos retomar:
demo=# select pg_wal_replay_resume();
 pg_wal_replay_resume
----------------------

(1 row)

O arquivo de log agora informa que a recuperação foi concluída e as operações normais foram restauradas:
2019-06-04 14:20:26.219 UTC [10514] LOG:  redo done at 0/4002160
2019-06-04 14:20:26.219 UTC [10514] LOG:  last completed transaction was at log time 2019-06-04 14:05:28.813325+00
cp: cannot stat '/tmp/demo/archive/00000002.history': No such file or directory
2019-06-04 14:20:26.228 UTC [10514] LOG:  selected new timeline ID: 2
2019-06-04 14:20:26.272 UTC [10514] LOG:  archive recovery complete
cp: cannot stat '/tmp/demo/archive/00000001.history': No such file or directory
2019-06-04 14:20:26.388 UTC [10513] LOG:  database system is ready to accept connections

E recuperamos com sucesso o cluster até um tempo especificado!

Leitura complementar


Aqui estão alguns pontos de partida para descobrir mais sobre arquivamento WAL, modo de recuperação e PITR:
  • Documentos:configuração de recuperação
  • Documentos:arquivamento contínuo e PITR
  • Capítulo 9 do livro “The Internals of PostgreSQL”
  • Ferramentas:WAL-E,WAL-G, Barman