Monday, February 20, 2017

Replicação: o que mudou

A mais de 6 anos atrás, eu escrevi o artigo Hot Standby e Streaming Replication que descreve uma das funcionalidades mais aguardadas na época: replicação nativa. De lá para cá houveram diversas melhorias nessa funcionalidade que a tornaram sólida para diversas arquiteturas de sistemas. Irei atualizar os passos descritos no post antigo (que por sinal ainda são válidos) com opções que melhoraram a implantação da replicação no PostgreSQL.
A versão 9.0 implementou a replicação nativa baseada no envio de registros (streaming replication). Um protocolo foi definido para o envio de registros do WAL do servidor principal para o servidor secundário. O servidor secundário tem a capacidade de aceitar consultas somente leitura (hot standby). Em resumo, foi adicionado suporte a um servidor principal e vários servidores secundários (aceitando ou não consultas).
Da versão 9.1 a 9.6 houveram várias melhorias que tornaram essa solução mais sólida e robusta a cada versão. Destaco o suporte a: replicação síncrona (9.1), replicação em cascata (9.2), possibilidade de seguir nova linha do tempo (9.3), slots de replicação (9.4), replicação com atraso (9.4), resincronizar servidor principal antigo com pg_rewind (9.5), múltiplos servidores síncronos ao mesmo tempo (9.6).
A Timbira contribui com duas funcionalidades nessa evolução: função pg_xlog_location_diff (calcular diferença entre posições do WAL -- útil para descobrir o lag de replicação) e recovery_min_apply_delay (atrasar a aplicação do WAL no servidor secundário -- útil para recuperar de desastres tais como remover um banco de dados em produção).
O cenário que utilizaremos é o mesmo do artigo anterior cuja ilustração está na figura abaixo.


O cenário

  • 2 servidores PostgreSQL: um servidor principal (aceita leitura e modificação de dados) e um servidor secundário (aceita ou não consultas somente leitura). Estes servidores devem ser preferencialmente (quase) idênticos pois a replicação é "binária", sendo incompatível em arquiteturas e/ou sistemas operacionais distintos. (Em soluções de alta disponibilidade, utilizar um servidor secundário muito inferior ao servidor principal pode ser inaceitável para negócio. Certifique-se que o servidor secundário tenha capacidade de substituir o servidor principal.);
  • versão do PostgreSQL: a mesma versão em ambos servidores. Com mesma versão quero dizer que os dois primeiros números devem ser iguais (por exemplo, 9.1.3 e 9.1.24, 9.3.10 e 9.3.15, 9.6.2 e 9.6.2). Se for usar versões corretivas diferentes (9.3.10 x 9.3.15), mesmo que momentâneo para alguma atualização, é recomendado manter os servidores secundários com versões corretivas mais recentes para evitar que alguma incompatibilidade (causada por um bug) seja replicada e não consiga ser aplicada em uma versão corretiva anterior;
  • rede: a replicação utiliza o protocolo do PostgreSQL e, portanto, todo o tráfego será através da porta do serviço (padrão é 5432). Certifique-se que o servidor secundário consiga acessar o servidor principal a partir da porta do serviço. Se utilizarmos o pg_basebackup para montar o servidor secundário, não há necessidade de configuração especial (ele transmite os dados do agrupamento através do próprio protocolo do PostgreSQL); no entanto, a utilização de outro método de cópia (ssh, rsync, etc) demandará ajuste no acesso para a(s) porta(s) utilizada(s);
  • acesso: o acesso root não é obrigatório se o local do diretório de dados do servidor secundário estiver com as devidas permissões para o usuário do serviço do PostgreSQL (comumente usuário postgres). A partir da versão 9.1, o usuário que replica os dados precisa ter a permissão REPLICATION ou ser superusuário; na 9.0, o usuário deve ser superusuário;
  • endereço de rede: para o servidor principal e o servidor secundário usaremos 10.1.1.1 e 10.1.1.2, respectivamente;
  • diretório de dados: para o servidor principal usaremos /bd/primario e o servidor secundário usaremos /bd/secundario;
  • usuário do serviço: o usuário do sistema operacional em ambos os servidores será o postgres.

No servidor principal


Começamos alterando a configuração do postgres (/bd/primario/postgresql.conf) no servidor principal:

listen_addresses = '*'
wal_level = replica               # hot_standby até 9.5
max_wal_senders = 3
max_replication_slots = 3    # parâmetro a partir da 9.4

O parâmetro listen_addresses permite que o servidor principal escute todos os endereços da rede (o pg_hba.conf faz restrição por endereço). O parâmetro wal_level determina a quantidade de informação vai para WAL (replica permitirá arquivamento do WAL e replicação). O parâmetro max_wal_senders indica o número máximo de servidores secundários ou aplicações para backup base (tais como pg_basebackup e pg_receivexlog). O parâmetro max_replication_slots especifica o número máximo de slots de replicação permitidos.

É possível prevenir a reciclagem do WAL (que ainda é útil para algum servidor secundário) utilizando o parâmetro wal_keep_segments ou arquivando o WAL com o parâmetro archive_command. O parâmetro wal_keep_segments especifica um número mínimo de arquivos de log de transação a serem mantidos no pg_xlog caso algum servidor secundário necessite obtê-los via replicação. O parâmetro archive_command especifica um comando utilizado para copiar o arquivo de log de transação (que foi recentemente preenchido) para algum local acessível pelos servidores secundários. Contudo, esses métodos podem reter mais arquivos do que o necessário enquanto o slot de replicação visa reter somente o WAL necessário para algum servidor secundário. Uma desvantagem do slot de replicação é que ele não limita a quantidade de arquivos do WAL armazenados no diretório pg_xlog. Isso quer dizer que se algum servidor secundário for desligado e o DBA esquecer de remover o slot de replicação dele, o pg_xlog vai crescer indefinidamente.

As modificações no arquivo /bd/primario/postgresql.conf necessitam de um reinício do serviço.

postgres@principal:~$ pg_ctl restart -D /bd/primario
esperando o servidor desligar.....feito
servidor está parado
servidor está iniciando

A replicação usará uma conexão do postgres. E para realizar essa conexão utilizaremos uma role específica para replicação. A versão 9.0 exigia um superusuário para tal mas a partir da 9.1 essa role pode ter simplesmente a permissão REPLICATION.

postgres@principal:~$ psql
psql (9.6.2)
Digite "help" para ajuda.

postgres=# CREATE ROLE replicacao REPLICATION LOGIN;
CREATE ROLE
postgres=# \q

Dependendo de sua política de segurança, você precisará definir uma senha para a role replicacao. A senha poderá ser informada na string de conexão no arquivo /bd/secundario/recovery.conf ou preferencialmente em um arquivo de senhas (~postgres/.pgpass ou %APPDATA%\postgresql\pgpass.conf no Windows) no servidor secundário.
postgres@principal:~$ psql
psql (9.6.2)
Digite "help" para ajuda.

postgres=# \password replicacao
Digite nova senha:
Digite-a novamente:
postgres=# \q

Precisamos ajustar o acesso no servidor principal. Isso porque a conexão é feita do servidor secundário para o servidor principal. O arquivo /bd/primario/pg_hba.conf controla esse acesso. Os acessos de replicação são identificados utlizando replication com nome do banco de dados (se você tiver um banco chamado replication, ele deve estar entre aspas duplas). Se você decidir utilizar autenticação por senha, o método de autenticação pode ser md5.

host    replication    replicacao    10.1.1.2/32    md5

A adição de uma nova regra de autenticação exige um reload do serviço.

postgres@principal:~$ pg_ctl reload -D /bd/primario
servidor foi sinalizado

No servidor secundário


O próximo passo é obter uma cópia base (base backup) para montar o servidor secundário. A cópia base é uma cópia de todo agrupamento de dados (PGDATA) incluindo os diretórios de todas as tablespaces. Ilustraremos três maneiras de realizar essa cópia dependendo da disponibilidade do serviço.

1. Servidor principal parado


Se o servidor puder ficar parado durante a cópia, podemos fazer:
postgres@principal:~$ pg_ctl stop -D /bd/primario
esperando o servidor desligar.....feito
servidor está parado
postgres@principal:~$ rsync -av --exclude postgresql.auto.conf.tmp --exclude postmaster.pid --exclude postmaster.opts --exclude pg_stat_tmp/* --exclude pg_replslot/* --exclude pg_dynshmem/* --exclude pg_notify/* --exclude pg_serial/* --exclude pg_snapshots/* --exclude pg_subtrans/* --exclude pg_xlog/* --exclude pg_log/* /bd/primario/ postgres@10.1.1.2:/bd/secundario
sending incremental file list
./
PG_VERSION
pg_ident.conf
postgresql.auto.conf
.
.
.
pg_tblspc/
pg_twophase/
pg_xlog/

sent 364,684,662 bytes  received 96,744 bytes  9,234,972.30 bytes/sec
total size is 364,298,395  speedup is 1.00
postgres@principal:~$ pg_ctl start -D /bd/primario
servidor está iniciando

No comando rsync não esqueça da barra ao final do nome do diretório. Ele vai indicar que copiaremos somente o conteúdo de /bd/primario e não o diretório primario. Alguns arquivos e/ou diretórios excluídos (--exclude) podem não existir na sua versão, ignore-os. Os diretórios pg_stat_tmp e pg_log podem ser configurados pelo DBA, certifique-se que eles não foram alterados para outros valores.

2. Servidor principal em atividade


Caso você queira fazer a cópia base com o servidor em atividade, precisamos executar alguns passos além da cópia. O slot de replicação foi implementado na versão 9.4. Em versões anteriores, ignore o primeiro comando e utilize o arquivamento ou o parâmetro wal_keep_segments conforme explicado acima.
postgres=# SELECT * FROM pg_create_physical_replication_slot('secundario', true);
 slot_name   | xlog_position
-------------------+---------------------
 secundario  | 0/99005D50
(1 registro)

postgres=# SELECT pg_start_backup('replica', true);
 pg_start_backup
--------------------------
 0/9A000060
(1 registro)

postgres=# \q
postgres@principal:~$ rsync -av --exclude postgresql.auto.conf.tmp --exclude postmaster.pid --exclude postmaster.opts --exclude pg_stat_tmp/* --exclude pg_replslot/* --exclude pg_dynshmem/* --exclude pg_notify/* --exclude pg_serial/* --exclude pg_snapshots/* --exclude pg_subtrans/* --exclude pg_xlog/* --exclude pg_log/* /bd/primario/ postgres@10.1.1.2:/bd/secundario
sending incremental file list
./
PG_VERSION
backup_label
pg_ident.conf
.
.
.
pg_twophase/
pg_xlog/

sent 364,626,339 bytes  received 96,728 bytes  145,889,226.80 bytes/sec
total size is 364,240,052  speedup is 1.00
postgres@principal:~$ psql
psql (9.6.2)
Digite "help" para ajuda.

euler=# SELECT pg_stop_backup();
NOTA:  pg_stop_backup concluído, todos os segmentos do WAL foram arquivados
 pg_stop_backup
-------------------------
 0/9BDD1B38
(1 registro)

euler=# \q

Criamos um slot de replicação (com a função pg_create_physical_replication_slot) para limitar a reciclagem do WAL porque o servidor secundário precisará dele. O segundo parâmetro da função é importante porque a reserva é feita imediatamente ao invés de fazer somente na primeira conexão (sem a reserva imediata, uma cópia base que demora algumas horas poderia remover WAL necessário para montar a réplica). Em versões anteriores, faça arquivamento ou utilize o parâmetro wal_keep_segments.

A função pg_start_backup prepara o servidor principal para iniciar uma cópia base. Após a sua execução podemos fazer a cópia mesmo que arquivos estejam sendo criados (tabelas/índices novos) e/ou excluídos. A cópia base exclui alguns arquivos que podem ser diferentes no servidor secundário (como postgresql.conf e pg_hba.conf) ou que não são necessários (vide parâmetros --exclude no comando rsync). Executamos a função pg_stop_backup para indicar o fim da cópia.

3. pg_basebackup


O comando pg_basebackup automatiza a geração de cópias base com servidores postgres em atividade. A cópia base é feita utilizando uma conexão do postgres e utiliza o protocolo de replicação. As configurações feitas no servidor principal e o usuário criado são os pré-requisitos para executar o pg_basebackup. O pg_basebackup deve ser executado a partir do servidor secundário.

postgres@secundario:~$ pg_basebackup --format=plain --xlog-method=stream --checkpoint=fast --progress -D /bd/secundario -R -v -h 10.1.1.1 -p 5432 -U replicacao
ponto de início do log de transação: 0/16001FD8 na linha do tempo 1
pg_basebackup: iniciando receptor do WAL em segundo plano
98860/98860 kB (100%), 1/1 tablespace                                        
transaction log end point: 0/16076238
pg_basebackup: esperando processo em segundo plano terminar o envio ...
pg_basebackup: cópia base completa

No exemplo acima, utilizamos o formato plain, que mantém o mesmo layout dos arquivos e diretórios do servidor principal. Se tiver tablespaces, elas vão para o mesmo caminho absoluto definido do servidor principal (certifique-se que os caminhos existam antes de executar o pg_basebackup). O parâmetro --xlog-method especifica que o pg_basebackup irá incluir todos os arquivos de log de transação necessários. O valor stream indica que irá copiar o WAL em paralelo com a cópia base, necessitando para isso de uma conexão extra com o servidor principal (o outro valor é fetch mas só copia o WAL ao final da cópia base, necessitando que não haja reciclagem do WAL -- vide wal_keep_segments). O parâmetro --checkpoint controla se o CHECKPOINT será espalhado (spread) ou rápido (fast) -- a opção fast pode causar um pico de IO; use-a somente em horários de baixa carga. A opção -D especifica o diretório que o agrupamento de dados do servidor secundário será armazenado. A opção -R gera o arquivo recovery.conf (com as opções informadas pelo pg_basebackup) no diretório de saída (-D) para facilitar a montagem do servidor secundário. As opções -h (host), -p (porta) e -U (usuário) são relativas a conexão com servidor principal.

Iniciando a réplica


No servidor secundário, o próximo passo é criar o arquivo /bd/secundario/recovery.conf. A presença desse arquivo indica para o postgres que ele deve iniciar em modo de recuperação (a replicação é uma recuperação contínua).
standby_mode = 'on'
primary_conninfo = 'host=10.1.1.1 port=5432 user=replicacao'
O parâmetro standby_mode garante que o servidor secundário ficará em recuperação contínua indefinidamente. Para replicação por fluxo, é necessário informar o parâmetro primary_conninfo especificando como se conectar no servidor principal.

Se o servidor secundário ficar muito atrasado em relação ao servidor principal, a conexão de replicação pode ser interrompida porque o arquivo de log de transação que contém o registro a ser replicado, já foi reciclado no servidor principal. É uma cenário que pode ocorrer ao realizar cargas de dados e/ou manutenções. As soluções, conforme detalhamos acima, são: wal_keep_segments, arquivamento ou slots. Para wal_keep_segments, basta ajustá-lo no servidor principal. O arquivamento deve ser feito no servidor principal e o local de armazenamento deve ser acessível pelo servidor secundário.

No servidor principal, crie o diretório /bd/archives com permissão de escrita para usuário postgres e edite o arquivo /bd/primario/postgresql.conf:
archive_mode = on
archive_command = 'cp %p /bd/archives/%f'

Um reinício do postgres no servidor principal é necessário para que o arquivamento seja ativado.

E no servidor secundário, edite arquivo /bd/secundario/recovery.conf:
restore_command = 'scp postgres@10.1.1.1:/bd/archives/%f %p'
Nesse caso (scp), use um par de chaves para acesso via ssh sem solicitar senha.

Por fim, se optar por utilizar slots (versão >= 9.4), crie o slot com a função pg_create_physical_replication_slot conforme detalhado acima e adicione o seguinte parâmetro no arquivo /bd/secundario/recovery.conf:
primary_slot_name = 'secundario'

O nome do slot é aquele que você informou no primeiro parâmetro da função. Para obter os slots, utilize a seguinte consulta:
postgres=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
 slot_name   | slot_type | active | restart_lsn
-------------------+--------------+---------+--------------------
 secundario  | physical  | f         | 0/1A272848
(1 registro)

Mais alguns ajustes no arquivo /bd/secundario/postgresql.conf.
hot_standby = on
hot_standby_feedback = on

O parâmetro hot_standby permitirá consultas somente leitura no servidor secundário. O parâmetro hot_standby_feedback faz com que o servidor secundário envie informações ao servidor principal para impedir o cancelamento de consultas no servidor secundário. A desvantagem é o inchaço de tabelas no servidor principal porque algumas consultas longas no servidor secundário ainda utilizam registros que já foram removidos no servidor principal e não podem ser limpados porque provocariam o cancelamento da consulta no servidor secundário.

Se o objetivo do servidor secundário é alta disponibilidade, é preferível não ajustar hot_standby_feedback e manter os valores de max_standby_archive_delay e max_standby_streaming_delay baixos, assim o servidor secundário não ficará tão distante do servidor principal por causa de atrasos provocados por consultas longas.

Todavia, se o objetivo do servidor secundário é executar consultas longas habilite hot_standby_feedback e/ou defina os valores de max_standby_archive_delay e max_standby_streaming_delay altos ou mesmo -1 (infinito). Tenha em mente que manter um atraso grande fará com que outras conexões não vejam mudanças recentes no servidor principal (porque elas ainda não foram aplicadas).

O último passo é iniciar o serviço no servidor secundário:
postgres@secundario:~$ pg_ctl start -D /bd/secundario
postgres@secundario:~$ cat postgresql-2017-02-20_213649.log
LOG:  sistema de banco de dados foi interrompido; última execução em 2017-02-20 21:28:06 BRT
LOG:  entrando no modo em espera
LOG:  redo inicia em 0/1B000028
LOG:  estado de recuperação consistente alcançado em 0/1B0000F8
LOG:  sistema de banco de dados está pronto para aceitar conexões somente leitura
LOG:  iniciado fluxo de WAL do principal em 0/1C000000 na linha do tempo 1

Para monitorar a replicação, consulte a visão pg_stat_replication no servidor principal:
postgres=# SELECT *, pg_xlog_location_diff(sent_location, replay_location) AS lag_replay FROM pg_stat_replication;
-[ RECORD 1 ]----+------------------------------------------------
pid                      | 18943
usesysid             | 16384
usename             | replicacao
application_name | walreceiver
client_addr          |
client_hostname  |
client_port           | -1
backend_start     | 2017-02-20 21:36:49.788049-03
backend_xmin     |
state                   | streaming
sent_location      | 0/1FE534C0
write_location     | 0/1FE534C0
flush_location     | 0/1FE4F4F0
replay_location   | 0/1FE4F4F0
sync_priority       | 0
sync_state          | async
lag_replay           | 16336
Lembre-se de remover o slot (se estiver utilizando), após desativar algum servidor secundário. Um slot sem uso retém arquivos de log de transação indefinidamente (podendo encher a sua partição rapidamente se o espaço for reduzido). Para remover o slot, execute:
postgres=# SELECT pg_drop_replication_slot('secundario');
 pg_drop_replication_slot
-------------------------------------

(1 registro)

Thursday, February 2, 2017

Backup Físico x Lógico

O cenário de cópia de segurança (backup) mais recorrente é realizar a cópia uma vez ao dia com o pg_dump. Toda vez que veja esse cenário lembro do artigo do Telles cujo título é Dump não é backup!. Quando informo que não é a melhor estratégia de cópia de segurança a adotar muitos ainda questionam. Neste artigo discutirei sobre as vantagens e desvantagens dos métodos de realização de cópia de segurança no PostgreSQL.

Começamos dizendo que o PostgreSQL utiliza dois métodos para realização de cópia de segurança: cópia física e cópia lógica. Na cópia física, realizamos a cópia dos arquivos pertinentes ao funcionamento do PostgreSQL (todos os datafiles, arquivos de log de transação, arquivos de controle) exceto arquivos de log e aqueles que podem ser gerados novamente (por exemplo, estatísticas e free space map). Na cópia lógica, geramos instruções SQL que serão capazes de reconstruir determinado banco de dados.

As características da cópia física são:

  • online ou offline: a cópia pode ser feito com o serviço em execução;
  • completa: não há seleção de bancos de dados. Todos bancos do agrupamento (cluster) devem ser copiados;
  • incremental: a partir da cópia (a qual chamaremos de cópia base) podemos aplicar as mudanças (logs de transação) para chegar a qualquer ponto no tempo (PITR);
  • mesmo hardware e sistema operacional: por utilizar um formato dependente de plataforma, não dá para pegar uma instalação no Windows e restaurar no AIX;
  • versão do PostgreSQL: a cada nova versão, mudanças no catálogo impedem que o PostgreSQL seja compatível com agrupamento (cluster) de uma outra versão, isso quer dizer que iniciar o serviço de um agrupamento (cluster) criado na 9.3 com os binários da 9.6 não vai funcionar.
As características da cópia lógica são:
  • online: o serviço precisa estar em execução para executarmos a cópia de segurança;
  • seletiva: você pode escolher o banco de dados a ser copiado (inclusive pode optar por excluir alguns objetos ou dados de tabelas);
  • compatível: pode haver compatibilidade entre versões utilizadas para cópia e restauração (algumas instruções podem se tornar obsoletas em versões novas ou não existirem em versões antigas). Além disso, podemos restaurar em plataformas (hardware e sistema operacional) diversas ou até mesmo em SGBDs que utilizam a linguagem SQL (provavelmente com algumas correções nas instruções).
Há vantagens e desvantagens no uso de ambos os métodos de cópia de segurança. Vamos analisar alguns pontos importantes acerca de cópias de segurança:
  • perda de dados: na cópia lógica, e no pior caso (considerando um cenário de cópia de segurança 1 vez ao dia), podemos ter perda de 24 horas de dados porque não há cópia incremental. Na cópia física, a perda de dados é menor já que há cópia das mudanças (logs de transação) ao longo do dia (existem técnicas para ter perda zero ou próximo disso);
  • uso de recursos: em ambos os casos haverá uso intenso de I/O durante a cópia, o que pode tornar a operação lenta nesse período. No entanto, na cópia física, somente a cópia base (primeira cópia) é lenta pois precisa copiar tudo; as cópias subsequentes podem copiar somente aqueles arquivos que mudaram;
  • eficiência: na cópia lógica, deve-se copiar tudo; não há possibilidade de copiar somente o incremento (a janela de perda de dados aumenta até que façamos outra cópia lógica). Além disso, se uma cópia lógica falha ou é interrompida durante a execução, não há a possibilidade de reinício a partir daquele ponto. Na cópia física, fazemos a cópia base e a partir daquele ponto copiamos somente os incrementos (minimizando a perda ao longo do tempo). Podemos retomar do ponto onde paramos, evitando uma nova cópia base;
  • inflexível: na cópia lógica é possível selecionar quais objetos farão parte da cópia de segurança (a restauração também pode ser seletiva). Na cópia física, não há possibilidade de selecionar determinados bancos de dados ou mesmo objetos a serem restaurados; deve-se restaurar tudo e depois proceder com a exclusão daquilo que não é de interesse.
  • tamanho: para cópia lógica, quanto maior o cluster mais horas levará para copiar as instruções SQL. Essa lentidão pode ocasionar problemas operacionais (por exemplo, inchaço de datafiles e bloqueio de DDLs). Na cópia física, a cópia base pode demorar mas não vai ocasionar problemas operacionais (exceto alta taxa de I/O). Em um agrupamento (cluster) que tenha tamanho na casa das centenas de gigabytes, a cópia física tende a ser mais rápida do que a cópia lógica (não há necessidade de ler dados e formatá-los em um instrução SQL);
  • objetos globais: na cópia lógica, informações globais (tais como roles e tablespaces) não são copiadas. É necessário utilizar o pg_dumpall para copiar tais informações. São informações que podem ser importantes para o negócio e, portanto, precisam ser copiadas também. Na cópia física, como todos os datafiles são copiadas as informações são mantidas idênticas na cópia de segurança.
Voltando ao cenário exposto no primeiro parágrafo: cópia de segurança feita uma vez por dia (geralmente na madrugada) utilizando o pg_dump. Os seguintes problemas foram detectados:
  • perda de dados pode ser inaceitável para negócio. Perder um dia de trabalho pode ocasionar sérios problemas operacionais na empresa;
  • você terá acesso aos dados em um determinado ponto no tempo: o momento que iniciou a cópia lógica. Isso quer dizer que se a cópia demorou 14 horas e após o término o serviço apresentou problemas, a cópia de segurança estará defasada em 14 horas!
  • a falha de uma cópia de segurança pode forçar a execução da rotina durante o expediente que, por sua vez, pode ocasionar muita lentidão ao acessar os dados;
  • fazer cópia lógica em um agrupamento (cluster) com mais de 1 TB pode demorar dezenas de horas (sim, dias). Trocando em miúdos, lentidão por alguns dias;
  • objetos globais são importantes (por exemplo, propriedades e senhas de roles). Certifique-se que faça a cópia deles ao realizar a cópia lógica.
Se você estivesse fazendo a cópia física:
  • a perda de dados seria de algumas transações ou mesmo perda (próximo de) zero. Seria uma perda máxima controlada pelo DBA;
  • com uma cópia base de 01/01/2016 e todos os logs de transação do ano de 2016 seria possível restaurar o estado do banco a qualquer ponto no tempo no ano de 2016. Isso quer dizer que se alguém removeu um registro em 07/08/2016 é possível que eu restaure o estado do banco de dados antes da remoção e recupere os dados excluídos;
  • os servidores de homologação e testes podem ser gerados (automaticamente) a partir de uma cópia física de x dias atrás;
  • caso a cópia base esteja inconsistente, você poderá utilizar uma anterior desde que tenha os logs de transação a partir daquela cópia base anterior;
  • a cópia base pode demorar dias mas, uma vez feita, você pode optar por fazer cópias incrementais nela para agilizar a cópia física. Como os incrementos são copiados ao longo do dia, eu não preciso me preocupar com o tempo gasto para copiá-los.
Isso quer dizer que preciso mudar o método de cópia de segurança adotando a cópia física ao invés da cópia lógica? Não. Ambos fazem parte da estratégia de cópia de segurança. Contudo, há cenários que uma cópia lógica se encaixa:
  • extrair dados de uma tabela no mês passado não importando a data/hora exata para recuperação;
  • extrair dados de algumas tabelas para dar carga em outro SGBD;
  • recuperar um banco de dados cuja cópia de segurança é da versão 7.0.
Geralmente, utilizamos a cópia física para recuperação de desastres e a cópia lógica para retenção por um longo período.

Até a versão 7.4, a cópia física não era tão difundida porque não era possível fazê-la online. Além disso, ela não era incremental. A partir da versão 8.0, foram implementados os conceitos de arquivamento de logs de transação e PITR (Point In Time Recovery). Na versão 8.2, houveram inúmeras melhorias para cópia física incluindo adição de um parâmetro (archive_timeout) para controlar o tempo de perda máximo (RPO, Recovery Point Objective).  Na versão 9.1, o pg_basebackup foi implementado para facilitar a execução de cópias base (utilizando o próprio protocolo do postgres) antes disso um programa ou script seguindo os passos da cópia base deve ser utilizado. Na versão 9.2, o pg_receivexlog foi implementado (ele usa streaming) para ser uma alternativa ao arquivamento e manter uma perda menor ainda (na versão 9.5 é possível configurá-lo síncrono, tornando a perda zero).

Antes que alguém pergunte, há outras soluções de cópia física como o pgBarman e pgBackRest que não fazem parte do PostgreSQL mas que são mantidos por membros da comunidade. Contudo, isso é assunto para um outro artigo ...

Thursday, May 12, 2016

PostgreSQL 9.6: estamos quase lá

Hoje foi anunciado o lançamento da primeira versão beta do PostgreSQL 9.6. Versão beta significa que estamos quase lá. O que está faltando? Testes, testes e mais testes. É o momento de corrigir alguns bugs, ajustar a documentação, identificar e corrigir regressões de performance, identificar e corrigir portabilidade (se bem que a BuildFarm tem uma boa cobertura de arquiteturas) e escrever as notas de lançamento definitivas.

O PGDG sempre almeja uma nova versão com uma quantidade mínima de bugs. É por esse motivo que precisamos de testes das funcionalidades novas e também das existentes. O período em beta vai depender da quantidade de correções que forem aparecendo. Não deixem de reportar erros para comunidade.

As principais funcionalidades da versão 9.6 são:

  • buscas sequenciais, junções e agregações em paralelo;
  • suporte a clusters que escalam em leitura utilizando múltiplos servidores secundários síncronos;
  • busca textual por frases;
  • postgres_fdw poderá executar ordenações, junções, UPDATEs e DELETEs no servidor remoto;
  • diminuição do impacto do autovacuum em tabelas grandes.
Algumas melhorias / funcionalidades que também merecem destaque são:
  • informação sobre espera de bloqueios no pg_stat_activity;
  • visão pg_stat_progress_vacuum: progresso do VACUUM;
  • função pg_blocking_pids(): informa PIDs que estão bloqueando um PID específico;
  • no parâmetro wal_level, os valores archive e hot_standby foram substituídos por replica;
  • término de sessões idle in transaction após algum tempo;
  • forçar término de conexões se o postmaster terminar;
  • suporte a múltiplos servidores secundários síncronos (somente um era suportado);
  • ALTER TABLE foo ADD COLUMN IF NOT EXISTS bar integer;
  • redução de bloqueios em ALTER TABLE ao alterar parâmetros do autovacuum e fillfactor;
  • uso do sistema de privilégios para gerenciar acesso a funções do sistema;
  • reservar roles que começam com pg_ (roles do sistema a partir dessa versão);
  • no psql, o comando \crosstabview é útil para resultado de consultas de agregação em duas dimensões (ex. quantidade vendida por filial / mês);
  • no psql, o comando \gexec faz uma consulta e envia o seu resultado como uma nova consulta (útil para consultas que montam consultas);
  • interface genérica para escrita de registros no WAL (suporte a novos métodos de acesso -- CREATE ACCESS METHOD);
  • suporte a mensagens do WAL genéricas para decodificação lógica;
  • módulo bloom: método de acesso baseado no filtro bloom utilizando a nova interface para criação de métodos de acesso.

Como todas as outras versões, as melhorias no PostgreSQL envolvem mudanças de grande quantidade de código. É fundamental a sua participação nesse processo de testes para se certificar que você pode migrar com segurança para 9.6 ou mesmo que aquele novo projeto será beneficiado com alguma funcionalidade nova. Leia as notas de lançamento para saber as novidades mas também as incompatibilidades. Faça o download do beta1 e teste-o. Reporte insucessos e sucessos (se quiser destacar melhorias no seu ambiente). Há pacotes disponíveis para WindowsRed Hat (seus derivados) e Debian (seus derivados).

A qualidade do PostgreSQL depende muito dos testes de seus usuários. Bons testes!

Thursday, July 2, 2015

Anúncio do PostgreSQL 9.5 alfa

O Grupo de Desenvolvimento Global do PostgreSQL anunciou uma versão alfa do PostgreSQL 9.5 hoje. Essa versão contém uma prévia do conjunto de funcionalidades que estarão disponíveis na versão final da 9.5. Vale ressaltar que alguns detalhes podem mudar antes do lançamento da versão final, no entanto, novas funcionalidades não serão adicionadas. Se você quiser preparar o seu sistema para 9.5, essa é a hora de começar a testar. Copie, teste e relate erros que você encontrar.

Algumas das principais funcionalidades disponíveis na versão alfa são:

  • índice BRIN que é um tipo de índice compacto para tabelas muito grandes;
  • melhorias em velocidade de operações de ordenação e hash em memória;
  • gerenciamento automatizado do tamanho do log de transação;
  • INSERT ON CONFLICT UPDATE (também conhecido como UPSERT);
  • operações analíticas com GROUPING SETS, CUBE e ROLLUP;
  • suporte a segurança a nível de registros (RLS);
  • mais funções e operadores para manipulação do tipo JSONB;
  • nova ferramenta pg_rewind e outras melhorias de alta disponibilidade para replicação;
  • múltiplas melhorias no Foreign Data Wrapper, incluindo IMPORT FOREIGN SCHEMA;
  • melhorias de escalabilidade em sistemas com múltiplos cores e grande quantidade de memória.

Essas novas funcionalidades expandem as capacidades do PostgreSQL introduzindo nova sintaxe, APIs e interfaces de gerenciamento. É claro que há inúmeras funcionalidades detalhadas nas notas de lançamento, algumas delas podem ser bem legais para você. Teste todas aquelas que puder.

Como toda nova versão do PostgreSQL, as melhorias incluem uma grande quantidade de código. Nós precisamos de vocês para testar essa versão alfa com as suas cargas e ferramentas de teste no intuito de descobrir bugs e regressões antes que a versão 9.5.0 seja lançada. Além de testar as novas funcionalidades, considere avaliar:

  • As melhorias na ordenação e performance em geral realmente melhoraram a performance na sua aplicação?
  • As mudanças no código fizeram com que o PostgreSQL não funcionasse na sua plataforma?
  • Nós fizemos mudanças no log de transação incluindo compressão. Transferência em caso de falha (failover) e recuperação de desastre ainda funcionam como esperado?
  • As mudanças na precedência de operadores mudaram os resultados nas suas consultas?
  • O RLS funciona corretamente mantendo os seus dados seguros?

Como essa é uma versão alfa, mudanças no comportamento do banco de dados, detalhes de funcionalidades e APIs ainda podem ocorrer. Seus comentários e testes ajudarão a determinar os ajustes finais das novas funcionalidades, assim, teste quando puder. A qualidade do teste dos usuários ajuda a determinar quando faremos a lançamento da nova versão.

A previsão para o lançamento do primeiro beta é agosto/2015, e periodicamente versões beta adicionais serão lançadas até a versão final ainda em 2015. Informações adicionais e sugestões de como testar pode ser obtidas na página Testando Alfa.

A documentação completa e as notas de lançamento da nova versão estão disponíveis. Veja também O Que Há de Novo para detalhes de algumas funcionalidades.

PS> esta é uma tradução livre do anúncio da 9.5 alfa.

Sunday, June 14, 2015

Atualizações importantes

O PostgreSQL Development Group lançou uma atualização para todas as versões suportadas (9.4.4, 9.3.9, 9.2.13, 9.1.18 e 9.0.22) na sexta-feira (22/06). Em menos de 2 meses foram lançadas 3 versões corretivas para cada uma das versões. Em particular, as atualizações nas versões 9.3 e 9.4 introduziram bugs em algumas de suas correções; esse foi o motivo para o lançamento tão rápido de versões corretivas.

Algumas versões corretivas tentaram corrigir problemas no sistema multixact. É fato que a maioria dos usuários não vão chegar a manifestar o bug mas se isso acontecer, você pode ter corrompimento de dados irrecuperável. Não espera saber se alguma de suas aplicações vai produzir tal bug, atualize a versão o quanto antes.

Além do problema no sistema multixact (que coleciona bugs a várias versões), uma correção inexata introduziu um problema na 9.4.2 e 9.3.7 ao realizar um fsync em todo diretório de dados após uma queda. Infelizmente isso conduz a um erro se houver arquivos que não podem ser escritos pelo usuário postgres (por exemplo, arquivo de certificado SSL); a consequência é que o servidor não sobe.

Um outro problema é com o pg_upgrade. O bug pode se manifestar mesmo em versões que não contém o bug mas que foram atualizadas a partir de uma versão problemática. A consequência do bug é disparar um autovacuum em todas as tabelas. Você pode evitar o bug, fazendo um VACUUM manual antes de atualizar para uma versão mais nova.

Se você ainda não atualizou as versões suportadas, o que você está esperando? Esse aviso é urgente principalmente para aqueles que possuem versão 9.4 e 9.3.

Friday, May 16, 2014

Estamos quase lá... 9.4 beta 1

Ontem (15/05) foi anunciado o lançamento da primeira versão beta do PostgreSQL 9.4. Uma versão beta do PostgreSQL é quase a versão final. Ainda falta aparar algumas arestas... Daqui a alguns meses, a porteira se fecha (ou melhor dizendo, se abre). Se você se interessar por algumas das novas funcionalidades, agora é a hora de começar a descobrir as suas potencialidades. Se você já estiver planejando uma mudança de versão, esta é a hora de descobrir o que mudou (e se for o caso, adequar suas aplicações) ou mesmo reportar alguma regressão de performance de alguma consulta.

As principais funcionalidades são:
  • JSONB: um novo tipo de dados para armazenar JSON. Espere aí... o Postgres já tem um tipo JSON? Sim, mas este novo tipo usa um formato de armazenamento que é performático e ainda vem com suporte a indexação e contém vários operadores e funções;
  • Replicação: uma nova API para decodificação e transformação das mudanças ocorridas no banco de dados. Trocando em miúdos, uma API que permite a construção de um plugin para replicação lógica. Espera-se que algumas das soluções de replicação que utilizam comandos passem a adotar essa API por ser mais performática e não precisar de objetos adicionais (ex.: gatilhos). Eu fiz o plugin wal2jon (monta objetos JSON com dados das mudanças realizadas) para demonstrar as funcionalidades da API e também ouvi rumores que o Slony-I passará a utilizar tal API;
  • Visão Materializada: o REFRESH não mais bloqueia as leituras;
  • ALTER SYSTEM: um novo comando SQL que permite alterar o postgresql.conf. Os desenvolvedores de aplicativos que precisam alterar parâmetros em dezenas, centenas ou mesmo milhares de servidores vão adorar esta facilidade;
  • background worker: uma nova API que permite ter processos filho do processo principal. Podemos registrar, iniciar e parar esses processos. Com isso, poderemos escrever um agendador ou alguma rotina de consolidação periódica que trabalha "anexado" ao serviço do postgres.
Algumas melhorias que também merecem destaque são:
  • acelerar buscas e redução do tamanho de índices GIN;
  • melhorar performance de funções de agregação;
  • melhorar escalabilidade de escrita;
  • diminuir nível de bloqueio em alguns comandos ALTER TABLE;
  • novo parâmetro autovacuum_work_mem para controlar memória utilizada por um processo do autovacuum (antigamente era utilizado o maintenance_work_mem);
  • os parâmetros work_mem, maintenance_work_mem e effective_cache_size sofreram aumento em seus valores padrão;
  • atrasar replicação (foi uma das funcionalidades que o Fabrizio tirou do forno);
  • EXPLAIN ANALYZE apresenta tempo gasto para planejamento da consulta;
  • ALTER TABLESPACE ... MOVE move objetos de uma tablespace para outra;
  • opção --analyze-in-stages do vacuumdb executa ANALYZE em três estágios com diferentes configurações para produzir estatísticas úteis rapidamente (útil para colocar o banco rapidamente em produção);
  • pg_basebackup permite realocar o diretório do pg_xlog;
  • pg_basebackup permite controlar a taxa de transferência do cópia física;
  • aplicativo pg_prewarm carrega dados de tabelas na cache do postgres (shared buffers);
  • pg_stat_statements passa a armazenar consultas em um arquivo reduzindo a limitação do tamanho das consultas e permitindo um número maior de consultas únicas.
A cada versão há inúmeras mudanças internas, portanto, é de fundamental importância que você nos ajude a ter a versão 9.4 (quase) sem bugs. Leia as notas de lançamento para saber das novidades e, principalmente, das incompatibilidades. Faça o download do beta 1 e teste-o no seu ambiente. Reporte os sucessos e os insucessos. Quanto mais erros conseguirmos corrigir durante o beta melhor será a primeira versão da série 9.4. Já existe até pacotes para Debian e derivados disponíveis.

Bons testes!

Monday, September 9, 2013

O que esperar da versão 9.3

A aproximadamente 4 meses atrás eu anunciei a primeira versão beta da versão 9.3. De lá para cá, a versão foi polida para que a primeira versão (9.3.0) chegasse ao mercado com o mínimo de bugs possível. Hoje foi o dia do laçamento desse tão esperada versão. Confira o kit de impressa (*) sobre as funcionalidades mais esperadas dessa nova versão.

Eu gostaria de ressaltar aqui algumas funcionalidades que vão turbinar o desenvolvimento de novas aplicações e/ou facilitar a vida dos DBAs:

1) junções laterais: é uma funcionalidade do padrão SQL que permite que uma subconsulta prefixada com LATERAL possa referenciar colunas de tabelas que estão a esquerda da subconsulta. No exemplo abaixo, m.departamento só pode ser utilizado graças ao LATERAL.

euler=# SELECT nome,salario, media_salario FROM instrutor AS m, LATERAL(SELECT avg(salario) AS media_salario FROM instrutor n WHERE m.departamento = n.departamento) x;
  nome  | salario | media_salario
--------+---------+---------------
 euler  | 5023.58 |       3842.04
 joao   | 1058.21 |       1308.21
 maria  | 1558.21 |       1308.21
 jose   | 3758.82 |       3842.04
 marcos | 2743.72 |       3842.04
(5 registros)
2) adaptadores de dados externos graváveis: a funcionalidade conhecida como FDW (abreviação de Foreign Data Wrappers) está presente no Postgres desde a versão 9.1. No entanto, tabelas externas não podiam receber modificações (eram somente leitura). Nesta versão foi implementado a escrita e também um novo módulo (postgres_fdw) que vem para substituir o bom e velho dblink. Vale ressaltar que o postgres_fdw em relação ao dblink, possui mais funcionalidades, é mais robusto e transparente além de possuir sintaxe compatível com padrão SQL. Esta funcionalidade vem para facilitar de uma vez por todas o trabalho com bases de dados federadas, ou seja, o desenvolvedor não precisa se preocupar com API de acesso aos seus n SGBDS, basta que ele se conecte ao Postgres que o mesmo fará o acesso aos dados externos para você.

3) memória compartilhada: é comum que novatos no Postgres se deparem com aquele erro clássico "could not create shared memory segment" (principalmente no Linux cuja quantidade de memória compartilhada padrão por usuário é muito baixa -- cerca de 32MB) que aparece quando se tenta aumentar o número de conexões ou o parâmetro shared_buffers. Com uma nova implementação, raramente você precisará fazer o ajuste dos parâmetros do kernel (SHMMAX, SHMALL).

4) gatilhos de eventos: era comum a queixa sobre gatilhos em comandos DDL (CREATE, ALTER, DROP). Principalmente por aqueles interessados em replicação por comandos. A partir de agora, eventos poderão ser diparados ao executar DDLs. Veja um exemplo abaixo:

euler=# CREATE OR REPLACE FUNCTION mensagem() RETURNS event_trigger AS $$
euler$# BEGIN
euler$#     RAISE NOTICE 'msg: % %', tg_event, tg_tag;
euler$# END;
euler$# $$ LANGUAGE plpgsql;
CREATE FUNCTION
euler=# CREATE EVENT TRIGGER mensagem ON ddl_command_start EXECUTE PROCEDURE mensagem();
CREATE EVENT TRIGGER
euler=# create table foo (a int);
NOTA:  msg: ddl_command_start CREATE TABLE
CREATE TABLE
euler=# drop table foo;
NOTA:  msg: ddl_command_start DROP TABLE
DROP TABLE
5) bloqueios: um novo parâmetro (lock_timeout) permite especificar quanto tempo uma sessão esperará por um bloqueio (lock) antes de cancelar o comando. Uma outra funcionalidade importante para concorrência, é permitir que verificações de chave estrangeira não sejam bloqueadas por comandos UPDATE que não atualizam a chave primária da tabela referenciada (não é necessário configurar nada para que isso ocorra).

6) monitoramento: o arquivo contendo as estatísticas do Postgres foi dividido para reduzir a quantidade de I/O em agrupamentos de banco de dados que possuem milhares de objetos. Foi adicionado uma nova opção (só pode ser definida ao criar o agrupamento e não pode ser desabilitada) para fazer a verificação de páginas de dados (também conhecido como checksum); a ideia é detectar rapidamente falha de discos ou hardware com problemas (memória, controladora, etc).

7) replicação: uma das funcionalidades mais esperadas nesta área é a habilidade em detectar mudança de linha do tempo e seguí-la. Explico, se você possui 3 servidores (A, B e C) com o cenário no qual A envia dados para B e B envia dados para C (A -> B -> C). Se ocorrer uma falha em A e você tiver que promover B a servidor principal, você não precisará refazer o servidor C. Isso diminui a complexidade em ambientes de alta disponibilidade.

8) visões: visões materializadas. Isso mesmo! A tão esperada funcionalidade foi implementada com algumas limitações (não suporta atualizações automáticas e as atualizações descartam todos os dados ao invés de atualizações incrementais). Apesar das limitações, a funcionalidade é bastante útil em vários cenários de data warehouse. Melhorias virão nas próximas versões.

9) JSON: o suporte a esse tipo de dado foi incluída na versão 9.2 com promessa de melhorias nas versões subsequentes. Algumas das melhorias já vieram na 9.3 com a adição de várias funções e operadores para facilitar a manipulação de dados nesse formato.

10) psql: duas funcionalidades chamaram a minha atenção. A primeira delas é o novo comando \watch que torna possível a execução do último comando a cada n segundos (útil para algum monitoramento). A segunda é a saída formatada em LaTeX utilizando o pacote longtable (os meus relatórios esperavam ansiosamente por esta funcionalidade :-).

11) pg_dump: o pg_restore já suportava o paralelismo desde a versão 8.4; esta foi a vez do pg_dump. Pela falta de um mecanismo para exportar a snapshot (para que todos os processos de trabalho possam "enxergar" os mesmos dados) e um formato (de diretório) que pudesse armazenar objetos individuais (vários arquivos), o pg_dump tinha que ser executado por somente um processo. Como no pg_restore, você poderá especificar a opção --jobs para distribuir a carga do pg_dump entre vários processos auxiliares e realizar cópias de segurança em um tempo menor.

12) processos de trabalho: conhecido como background workers, permitirá o desenvolvimento de processsos auxiliares (que são processos filho do postgres). Isso quer dizer que podemos desenvolver um agendador, manipulador de requisições e quaisquer outras tarefas auxiliares ao PostgreSQL. A ideia ter algo integrado ao SGBD.

(*) se alguém da impressa estiver interessado em produzir algum texto ou mesmo pedir orientação/revisão sobre o lançamento da 9.3, entre em contato comigo (que sou o contato regional).