O objetivo desse post é implementar o londiste, que é uma ferramenta de replicação assincrona do tipo master/slave e faz parte do pacote de ferramentas SkyTools.
Pontos a validar dessa solução:
O ambiente de testes é composto por 2 servidores linux conforme abaixo:
Master | Slave | |
---|---|---|
Hostname | pg-master | pg-slave |
SO | CEntOS 6.5 | CEntOS 6.5 |
PostgreSQL | 9.3.4 | 9.3.4 |
Skytools | 3.1.5 | 3.1.5 |
IP | 192.168.152.149 | 192.168.152.150 |
Processo necessário em ambos os servidores.
cd /tmp
wget -c http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm
yum localinstall pgdg-centos93-9.3-1.noarch.rpm
yum install postgresql93-server postgresql93-contrib
service postgresql-9.3 initdb
chkconfig postgresql-9.3 on
Executar apenas no servidor master:
iptables -I INPUT -p tcp --dport 5432 -s 192.168.152.149 -j ACCEPT
service iptables save
Nesse lab não foi necessário parar ou ajustar o SELinux.
listen_addresses = '*'
Por questão de conveniência, libere acesso a todos os bancos dos servidores citados:
host all postgres 192.168.152.149/32 trust
host all postgres 192.168.152.150/32 trust
Agora inicie o postgresql:
service postgresql-9.3 start
O Londiste é uma ferramenta escrita em python, que utiliza o PgQ para o gerenciamento de eventos.
O PgQ que é um sistema de filas escrito em PL/pgSQL. Ele é divido em 3 principais funcionalidades:
Quanto à replicação do londiste, a mesma é controlada pelos nós (nodes), que são classicados como:
Na prática, cada configuração do nó é um job para processar as filas do PgQ. Para manter as filas atualizadas, um daemon chamado de worker é executado. Varios workers podem ser executados simulâneamente.
O daemon do PgQ, diferente do worker, precisa ter acesso a todos os bancos, para procupar pelos jobs e manter as filas e é por isso que sua string de conexão é parcial (parâmetro base_connstr
). Seu acesso padrão é realizado ao banco template1
.
Recomendo que o daemon do PgQ seja executado do servidor que for o nó root (master) mas nada impede de o mesmo ficar em um servidor isolado.
É importante lembrar que a solução do Londiste é implementada através de triggers nas tabelas replicadas e isso gera 2 ações necessárias: obrigatoriedade de mesma estrutura de tabelas/colunas e criação de constraints tipo PK e FK nos objetos replicados.
yum install skytools-93 skytools-93-modules
Talvez seja necessário reiniciar o postgresql nesse ponto.
Crie a estrutura de dados em ambos os servidores:
psql -U postgres -f schema_londiste.sql
-- criação do banco de dados
CREATE DATABASE teste_replica;
\c teste_replica
-- estrutura de dados
CREATE TABLE pessoa (
id SERIAL PRIMARY KEY,
nome TEXT NOT NULL,
data_nascimento DATE NOT NULL,
ultima_visita TIMESTAMP NOT NULL DEFAULT now(),
foto BYTEA,
biografia TEXT
);
-- funções de apoio
CREATE OR REPLACE FUNCTION bytea_import(p_path text, p_result out bytea)
LANGUAGE plpgsql as $$
DECLARE
l_oid oid;
r record;
BEGIN
p_result := '';
select lo_import(p_path) into l_oid;
for r in ( select data
from pg_largeobject
where loid = l_oid
order by pageno ) loop
p_result = p_result || r.data;
end loop;
perform lo_unlink(l_oid);
END;
$$;
Crie os diretórios necessários:
mkdir {/etc,/var/log,/var/run}/londiste
Crie o arquivo /etc/londiste/teste_replica_root.ini
, com o conteúdo abaixo:
[londiste3]
job_name = teste_replica_root
db = dbname=teste_replica host=192.168.152.149 user=postgres
queue_name = q_teste_replica
logfile = /var/log/londiste/teste_replica_root.log
pidfile = /var/run/londiste/teste_replica_root.pid
Quanto aos parâmetros utilizados:
Propriedade | Descrição | Sugestão de valores |
---|---|---|
job_name | Nome do Job a ser executado | [NOME_BANCO]_[TIPO_NODE] |
db | Connection String com detalhes de conexão do banco replicado | host=[PGHOST] port=[PGPORT] dbname=[NOME_BANCO] user=[PGUSER] |
queue_name | Nome da fila | q_[NOME_BANCO] |
logfile | Caminho completo do arquivo de log | /var/log/londiste/[NOME_BANCO]_[TIPO_NODE].log |
pidfile | Caminho completo do arquivo pid do worker | /var/run/londiste/[NOME_BANCO]_[TIPO_NODE].pid |
Caso seja necessário um arquivo de exemplo para ajudar a criar as configurações do job, utilize o comando
londiste3 \-\-ini
para gerar um arquivo de exemplo sanar as possíveis dúvidas ou ver as configurações disponíveis.
Após o ajuste das configurações é necessário criar o nó do londiste dentro do banco a ser replicado, assim, execute o comando abaixo:
londiste3 /etc/londiste/teste_replica_root.ini create-root node1 "dbname=teste_replica host=192.168.152.149 user=postgres"
Inicie o daemon para o nó criado:
londiste3 -d /etc/londiste/teste_replica_root.ini worker
É importante lembrar que para cada novo job é necessário criar um novo arquivo de configuração e a inicialização do job no banco replicado, conforme detalhado acima.
Crie o arquivo /etc/londiste/pgqd.ini
, com o conteúdo abaixo:
[pgqd]
base_connstr = host=192.168.152.149 user=postgres
logfile = /var/log/londiste/pgqd.log
pidfile = /var/run/londiste/pgqd.pid
Caso seja necessário um arquivo de exemplo para ajudar a criar as configurações do daemon, utilize o comando
pgqd \-\-ini
para gerar um arquivo de exemplo sanar as possíveis dúvidas ou ver as configurações disponíveis.
Inicie o daemon do PgQ:
pgqd /etc/londiste/pgqd.ini -d
Crie o arquivo /etc/londiste/teste_replica_leaf.ini
, com o conteúdo abaixo:
[londiste3]
job_name = teste_replica_leaf
db = dbname=teste_replica host=192.168.152.150 user=postgres
queue_name = q_teste_replica
logfile = /var/log/londiste/teste_replica_leaf.log
pidfile = /var/run/londiste/teste_replica_leaf.pid
Crie o nó do londiste:
londiste3 /etc/londiste/teste_replica_leaf.ini create-leaf node2 "dbname=teste_replica host=192.168.152.150 user=postgres" --provider="dbname=teste_replica host=192.168.152.149 user=postgres"
Inicie o worker:
londiste3 -d /etc/londiste/teste_replica_leaf.ini worker
Note que não é necessário que as tabelas tenham os mesmos dados para iniciar a replicação, apenas a mesma estrutura.
Copiando os arquivos necessários para o servidor:
scp /Users/seba/Desktop/28337_1323532011934_4739236_n.jpg root@192.168.152.149:/tmp
Ajustando as permissões:
chown postgres:postgres /tmp/28337_1323532011934_4739236_n.jpg
Execute a carga inicial:
psql -U postgres -d teste_replica -f carga_inicial_londiste.sql
\c teste_replica
-- carga de dados
INSERT INTO pessoa (nome, data_nascimento, foto, biografia)
WITH config AS (
SELECT
1000 AS max_size
)
SELECT
'Pessoa ' || new_id::text as nome,
('1987-04-16'::DATE + (round(CAST (random()*config.max_size AS NUMERIC),0)::TEXT || ' days')::INTERVAL)::DATE as data_nascimento,
bytea_import('/tmp/28337_1323532011934_4739236_n.jpg') as foto,
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis tristique quam erat, in pellentesque diam feugiat in. In hac habitasse platea dictumst. Mauris malesuada faucibus diam, in tristique arcu dapibus at. Phasellus commodo nulla et orci adipiscing, quis iaculis turpis tincidunt. Proin placerat nisl non molestie porttitor. Curabitur scelerisque libero in lorem consequat consectetur ac a massa. Cras volutpat est ac lacinia ultricies. Donec quis faucibus ligula. Morbi luctus cursus lacus, a fermentum odio dignissim non. Mauris a tellus adipiscing, sodales magna sed, vehicula justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Etiam eu augue nec lectus tristique bibendum vitae nec elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.' as biografia
FROM
config,
generate_series(1,config.max_size) as new_id;
londiste3 /etc/londiste/teste_replica_root.ini add-table pessoa
londiste3 /etc/londiste/teste_replica_leaf.ini add-table pessoa
Apartir desse ponto, em alguns segundos, ambos os bancos têm os mesmos registros na tabela pessoa, veja:
[root@pg-slave ~]# psql -U postgres -d teste_replica -c 'SELECT COUNT(1) FROM pessoa;' -h 192.168.152.149
count
-------
1000
(1 row)
[root@pg-slave ~]# psql -U postgres -d teste_replica -c 'SELECT COUNT(1) FROM pessoa;' -h 192.168.152.150
count
-------
1000
(1 row)
Também, não é possível fazer alterações nos registros do servidor slave:
[root@pg-slave ~]# psql -U postgres -d teste_replica -h 192.168.152.150
psql (9.3.4)
Type "help" for help.
teste_replica=# delete from pessoa;
ERROR: Table 'public.pessoa' to queue 'q_teste_replica': change not allowed (D)
Daqui pra frente, qualquer alteração será replicada (desde que a estrutura da tabela seja a mesma).
Referências: