sexta-feira, 22 de fevereiro de 2013

PostgreSQL - Replicando PostgreSQL em 15 passos com Gabriel Prestes


Migração banco de dados:


1 - Criar estrutura de archives na instância de origem:
[root@sebaorig /]# mkdir -p data/archive_log
[root@sebaorig /]# chown -R postgres. data/archive_log/


2 - Ativando archive na instância de origem:
[root@sebaorig /]# grep archive /var/lib/pgsql/data/postgresql.conf
archive_mode = on # allows archiving to be done
archive_command = 'rsync -arv %p /data/archive_log/%f' # command to use to archive a logfile segment
archive_timeout = 0 # force a logfile segment switch after this
[root@sebaorig /]# service postgresql restart
Stopping postgresql service: [ OK ]
Starting postgresql service: [ OK ]


3 - Testando a gravação de archives:
[root@sebaorig /]# psql -U postgres
psql (8.4.5)
Type "help" for help.


postgres=# SELECT pg_switch_xlog();
pg_switch_xlog
----------------
61F/AF92C180
(1 row)


postgres=# \q


[root@sebaorig /]# ls -la /data/archive_log/
total 16412
drwxr-xr-x 2 postgres postgres 4096 Oct 18 20:24 .
drwxr-xr-x 3 root root 4096 Oct 18 20:20 ..
-rw------- 1 postgres postgres 16777216 Oct 18 20:24 000000010000061F000000AF


4 - Colocando a instância de origem para backup:
[root@sebaorig /]# psql -U postgres
psql (8.4.5)
Type "help" for help.


postgres=# SELECT pg_start_backup('Cordeiro de Deus perdoai os pecados do mundo');
pg_start_backup
-----------------
61F/B0000020
(1 row)
postgres=# \q


5 - Replicando a instância para o servidor de destino:
[root@sebaorig pgsql]# rsync -avog --delete-after data/ -e ssh root@sebadest:/var/lib/pgsql/data


6 - Criando estrutura de archives no servidor de destino:
[root@sebadest pgsql]# mkdir -p /data/archive_log
[root@sebadest pgsql]# chown -R postgres. /data/archive_log

7 - Parando o backup na instância de origem:
[root@sebaorig archive_log]# psql -U postgres
psql (8.4.5)
Type "help" for help.


postgres=# SELECT pg_stop_backup();
pg_stop_backup
----------------
61F/B0000088
(1 row)


postgres=# \q


8 - Replicando archives para o servidor de destino:
[root@sebaorig pgsql]# rsync -avog --delete-after /data/archive_log/* -e ssh root@sebadest:/data/archive_log


9 - Limpando a instância de destino:
[root@sebadest data]# rm postmaster.pid


10 - Criando recovery.conf na instância de destino e limpando pg_xlog:
[root@sebadest data]# vim recovery.conf


Insira o seguinte conteúdo:


# -------------------------------
# PostgreSQL recovery config file
# -------------------------------
#
# Edit this file to provide the parameters that PostgreSQL
# needs to perform an archive recovery of a database.
#
# If "recovery.conf" is present in the PostgreSQL data directory, it is
# read on postmaster startup. After successful recovery, it is renamed
# to "recovery.done" to ensure that we do not accidentally re-enter
# archive recovery mode.
#
# This file consists of lines of the form:
#
# name = 'value'
#
# (The quotes around the value are NOT optional, but the "=" is.)
#
# Comments are introduced with '#'.
#
# The complete list of option names and allowed values can be found
# in the PostgreSQL documentation. The commented-out settings shown below
# are example values.
#
#---------------------------------------------------------------------------
# REQUIRED PARAMETERS
#---------------------------------------------------------------------------
#
# restore_command
#
# specifies the shell command that is executed to copy log files
# back from archival storage. The command string may contain %f,
# which is replaced by the name of the desired log file, and %p,
# which is replaced by the absolute path to copy the log file to.
#
# It is important that the command return nonzero exit status on failure.
# The command *will* be asked for log files that are not present in the
# archive; it must return nonzero when so asked.
#
# NOTE that the basename of %p will be different from %f; do not
# expect them to be interchangeable.
#
restore_command = 'cp /data/archive_log/%f %p'
#
#
#---------------------------------------------------------------------------
# OPTIONAL PARAMETERS
#---------------------------------------------------------------------------
#
# recovery_end_command
#
# specifies an optional shell command to execute at completion of recovery.
# This can be useful for cleaning up after the restore_command.
#
#recovery_end_command = ''
#
#
# By default, recovery will rollforward to the end of the WAL log.
# If you want to stop rollforward before that point, you
# must set a recovery target.
#
# You may set a recovery target either by transactionId, or
# by timestamp. Recovery may either include or exclude the
# transaction(s) with the recovery target value (ie, stop either
# just after or just before the given target, respectively).
#
#recovery_target_time = '2004-07-14 22:39:00 EST'
#
#recovery_target_xid = '1100842'
#
#recovery_target_inclusive = 'true' # 'true' or 'false'
#
#
# If you want to recover into a timeline other than the "main line" shown in
# pg_control, specify the timeline number here, or write 'latest' to get
# the latest branch for which there's a history file.
#
#recovery_target_timeline = '33' # number or 'latest'
#
#
#---------------------------------------------------------------------------


[root@sebadest data]# rm -f pg_xlog/*
[root@sebadest data]# rm -f pg_xlog/archive_status*

11 - Inicie a instância no servidor de destino:
[root@sebadest data]# /etc/init.d/postgresql start
Starting postgresql service: [ OK ]

12 - Retire a instância de destino e origem do archive mode:
[root@sebadest data]# grep archive postgresql.conf
archive_mode = off # allows archiving to be done
#archive_command = 'rsync -arv %p /data/archive_log/%f' # command to use to archive a logfile segment
#archive_timeout = 0 # force a logfile segment switch after this


[root@sebadest data]# service postgresql restart
Stopping postgresql service: [ OK ]
Starting postgresql service: [ OK ]

13 - Teste os ajustes do item 12:
[root@sebaorig pgsql]# psql -U postgres
psql (8.4.5)
Type "help" for help.


postgres=# SELECT pg_start_backup('Cordeiro de Deus perdoai os pecados do mundo');
ERRO: arquivamento do WAL não está ativo
HINT: archive_mode deve ser habilitado ao iniciar o servidor.


14 - Valide a instância replicada no servidor de destino:
[root@sebadest data]# psql -U postgres
psql (8.4.13)
Type "help" for help.


postgres=# \l
List of databases
Name | Owner | Encoding | Collation | Ctype | Access privileges
----------------------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
: postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
: postgres=CTc/postgres
(3 rows)


15 - Seja feliz, mas verifique no log da instância qual o ponto de consistência atingido do banco.  

segunda-feira, 18 de fevereiro de 2013

JBoss EAP 6 - Primeiros contatos



   Depois de trabalhar bastante com JBoss EAP 5.x por um tempo considerável, tive uma oportunidade impar de começar os trabalhos com o EAP 6, e melhor, migrar uma aplicação que vinha do 5.x, ou seja, utilizava frameworks antigos com relação ao do contêiner do 6.

   As principais mudanças que observei são:

1 - Possibilidade de gerenciamento de configurações do profile por domínio;
2 - Implementação do conceito de módulos, o que reduz o uso de memória da JVM;
3 - Alteração da interface de gerenciamento(console) e JBossCLI;
4 - Simplificação dos XMLs;
5 - HornetQ para mensageiria.

   Sei que existem mais alterações, entretanto para a ação de migração da aplicação em JSF que precisava foram os pontos mais observados.

   O que vale a pena citar do caminho da migração:

   Não utilizei bibliotecas do contêiner internas na aplicação, dupliquei a versão das mesmas no contêiner no diretório 'modules' e apenas na referência do 'jboss-deployment-structure.xml' excluí a versão 'main' e utilizei a do slot criado.     Bibliotecas de uso comum das aplicações que foram desenvolvidas pelo cliente coloquei como módulo também, para isso foi necessário alterar sua visibilidade.

   Todas as alterações relevantes foram executadas no XML 'domain', facilitando e muito o gerenciamento.

   Por boa prática utilizei o CLI para adicionar bibliotecas e DataSources, que agora são carregados como módulos também.

   Quanto a configuração do ModCluster, nenhuma novidade aparente, mas pude observar um melhor funcionamento do JGroups para comunicação entre os nodos do cluster. Outro item que deve ser levado em conta na configuração do cluster é o Infinispan, que gerencia o cache das aplicações.

   O bom deste primeiro contato "a quente" com o 6 foi ter que mexer bastante mesmo nele para fazer tudo funcionar 100%, e isso me agregou muito.     O que pude levar em resumo foi que a administração do JBoss melhorou muito, com a atualização dos frameworks muitos problemas foram solucionados.

    Nota 10 para o novo Enterprise.

terça-feira, 8 de janeiro de 2013

Oracle - Populando tabelas com CLOB e observando o xDB replication

   Em uma bela manhã de sol um estimado colega de trabalho, e porque não dizer amigo Sebastian Webber(http://swebber.me/blog), me pediu um apoio para agilizar um teste que ele estava fazendo com o produto da EnterpriseDB o xDB replication.

   Mas onde eu entrei nessa história? Resumindo eu precisa observar o método que fora criado no Oracle para alimentar a tabela no PostgreSQL.

   Primeira ação, tarefa simples, criar uma tabela:

Usei o usuário 'HR', e com ele executei o seguinte comando:



CREATE TABLE "HR"."TABELA_TESTE" 
   ( "ID" NUMBER(5,0) NOT NULL ENABLE, 
 "NOME" VARCHAR2(2048 BYTE), 
 "PDF" CLOB, 
 "DATA" DATE DEFAULT sysdate, 
  CONSTRAINT "TABELA_TESTE_PK" PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"  ENABLE
   ) SEGMENT CREATION IMMEDIATE 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS" 
 LOB ("PDF") STORE AS BASICFILE (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION 
  NOCACHE LOGGING 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)) ;



Agora, como popular uma tabela com CLOB? Precisamos criar uma stored procedure da seguinte forma:

CREATE OR REPLACE PROCEDURE p( p_idinit in int, p_idend in int, p_pdf in varchar2 )
AS
 BEGIN

      FOR v_LoopCounter IN p_idinit..p_idend LOOP
      INSERT INTO hr.tabela_teste
        VALUES (v_LoopCounter, NULL, p_pdf, SYSDATE);
    END LOOP;

END;
/


Agora vamos popular a tabela:

EXEC p(1,15000, rpad('*',32000,'*') );


Ao término a tabela conterá 15000 linhas, todas elas com ID correto, na coluna 'nome' será NULL, na coluna 'pdf' 32000 '*' e na coluna 'data' a data corrente.

Finalizados os testes, o que pude observar quanto ao xDB, é que a replicação utiliza triggers e tabelas auxiliares para realizar a replicação para o PostgreSQL. É possível fazer alterações na tabela durante o processo de replicação, entretanto será necessário ajustar a tabela no PostgreSQL.

Uma limitação que pude observar é que exemplo, a coluna 'ID' foi criada com a precisão 5, se alterarmos a precisão da coluna para precisão 30, por exemplo, ao inserir um volume grande de registros a inserção falhará em função da trigger ativa na mesma para o processo de replicação, resumindo, as tabelas auxiliares do xDB criadas durante o mapeamento entre as bases não é atualizado quando se altera a precisão da tabela de origem. Solução, alterar as tabelas auxiliares do xDB no Oracle para atender a necessidade.

quinta-feira, 8 de novembro de 2012

JON - Falha com Bundle

SINTOMA

Erro ao abrir a página do bundle no JON 'Failed to load bundle with the latest version data'.

PROBLEMA

Isto ocorre em função das versões excluídas das aplicações, ou seja, uma subquery retorna mais de uma linha, vide abaixo: 

 ERRO

more than one row returned by a subquery used as an expression 

 REPRODUÇÃO

Na KB da RedHat(https://access.redhat.com/knowledge/solutions/133893) mencionam que o erro ocorre somente para a coluna 'version', mas ocorre também se existe o mesmo valor, a mesma aplicação(name), no 'version_order', exemplo abaixo: 

 rhq=# SELECT * FROM rhq_bundle_version WHERE name LIKE 'manager' AND version_order=3 ORDER BY name; 

 id | name | description | version | version_order | action | config_def_id | bundle_id 
 -------+--------------+-------------+---------+---------------+------------------------------------------------------------------------------+---------------+---------- - 
 10882 | manager | Manager | 1.0i | 3 | | 11632 | 10131 : : : : : : : : : : : : : : : Deploying Test Bundle v1.0i to ${rhq.deploy.dir}... : : : : Done deploying Test Bundle v1.0i to ${rhq.deploy.dir}. : :
12213 | manager | Manager | 1.1b | 3 | | 12963 | 10131 : : : : : : : : : : : : : : : Deploying Test Bundle v1.1b to ${rhq.deploy.dir}... : : : : Done deploying Test Bundle v1.1b to ${rhq.deploy.dir}. : :

(2 rows) 

 SOLUÇÃO: Remover ou alterar o valor de uma das version_order duplicadas para a mesma aplicação, seja via JON ou via SQL.

segunda-feira, 24 de setembro de 2012

PostgreSQL - Política de retenção para o PGBarman

Segue abaixo um agente que fiz para criar uma política de retenção dos backups do PGBarman, enquanto não existe uma oficial:

IMPORTANTE:

Ajustar a variável $opt_path para onde ficam os backups dos seus servidores, ou seja o seu 'barman_home = /backup/vtl-backups' no 'barman.conf'.

---

#!/usr/bin/perl -w

# Rotate barman agent
# Author: Gabriel Prestes(LM2)
# Date: 21/09/2012

use File::stat;
use Time::Local;

($opt_db, $opt_ret, $opt_type) = @ARGV;

if($#ARGV<2){ print "Need args!\n"; exit(1);}

$opt_path="/backup/vtl-backups/$opt_db/$opt_type";
$opt_retinsec=($opt_ret*3600)*24;
print "|RETENTION POLICY - $opt_db - $opt_ret days - $opt_type |\n";

my @ls=`\$\(which ls\) -td $opt_path/*`;

foreach(@ls){

        chomp($_);

        if(($opt_type =~ "wals") and ($_ !~ "xlog.db")){

                $mtime=stat($_)->mtime;
                $timenow = timelocal(localtime());
                $tempo=$timenow-$mtime;
                $mtimereal=localtime($mtime);

                if($tempo>=$opt_retinsec){

                        $rm=`\$\(which rm\) -rf $_`;
                        print "WALS REMOVED : $_ - $mtimereal\n";

                } else{

                        print "WALS PRESERVED : $_ - $mtimereal\n";

                }

        }

        if($opt_type =~ "base"){

                $mtime=stat($_)->mtime;
                $timenow = timelocal(localtime());
                $tempo=$timenow-$mtime;
                $mtimereal=localtime($mtime);

                if($tempo>=$opt_retinsec){

                        $rm=`\$\(which rm\) -rf $_`;
                        print "BACKUP REMOVED : $_ - $mtimereal\n";

                } else{

                        print "BACKUP PRESERVED : $_ - $mtimereal\n";

                }

        }

}

exit(0);


---

Coloque depois no /etc/cron.d/barman o seguinte conteúdo: 

# m h     dom mon dow   user     command
  0 */4    *   *   *   barman   [ -x /usr/bin/barman ] && /usr/bin/barman -q cron
  0 */4    *   *   *   barman   [ -x /usr/bin/barman ] && /usr/bin/barman backup meu_pgsql
  1 0      *   *   *   barman   /backup/resources/bin/barman-retention.pl meu_pgsql 15 wals >> /backup/log/barman.log
  1 0      *   *   *   barman   /backup/resources/bin/barman-retention.pl meu_pgsql 15 base >> /backup/log/barman.log

Onde: 

/backup/resources/bin/barman-retention.pl - é o path do agente
meu_pgsql - é o nome que configurou na entrada do barman.conf
15 - 15 dias de retenção, pode ser menos ou mais, como queira
base - tipo de limpeza, esse argumento fará limpeza de todo backup sem archives com mais de 15 dias, por exemplo.
wals - tipo de limpeza, esse argumento fará limpeza de todos os wals com mais de 15 dias, por exemplo. 

Apenas um detalhe, PG-RMan dá de laço no Barman, pois Barman não tem incremental(versão 1.0.0).