HOWTO: Fazendo alta-disponibilidade do PostgreSQL

De Wiki Hackstore

Configurando as partições com o DRBD

Aqui vamos usar o drbd 0.7.x, que vem no stage4 já. Todo o trabalho é feito no primeiro servidor e depois replicado para o segundo.

Primeiro particione o HD do servidor de acordo com o padrão definido na rotina de instalação. Este particionamento deve ser replicado exatamente no outro servidor. Dica: use o sfdisk com gravação para a saida padrão e leitura na entrada padrão.

/etc/drbd.conf:

global {
       usage-count yes;
}

common {
       protocol C;

       disk {
               on-io-error detach;
       }

       startup {
               wfc-timeout 30;
               degr-wfc-timeout 60;
       }

       syncer {
               rate 70M;
       }
}

resource postgres1 {
       on psql0-1 {
               device /dev/drbd0;
               disk /dev/sda2;
               meta-disk internal;
               address 172.16.0.17:7781;
       }
       on psql0-2 {
               device /dev/drbd0;
               disk /dev/sda2;
               meta-disk internal;
               address 173.16.0.18:7781;
       }
}

resource postgres1xlog {
       on psql0-1 {
               device /dev/drbd1;
               disk /dev/sdb1;
               meta-disk internal;
               address 172.16.0.17:7782;
       }
       on psql0-2 {
               device /dev/drbd1;
               disk /dev/sdb1;
               meta-disk internal;
               address 173.16.0.18:7782;
       }
}

resource postgres2 {
       on psql0-1 {
               device /dev/drbd2;
               disk /dev/sdb2;
               meta-disk internal;
               address 172.16.0.17:7783;
       }
       on psql0-2 {
               device /dev/drbd2;
               disk /dev/sdb2;
               meta-disk internal;
               address 173.16.0.18:7783;
       }
}

resource postgres2xlog {
       on psql0-1 {
               device /dev/drbd3;
               disk /dev/sda1;
               meta-disk internal;
               address 172.16.0.17:7784;
       }
       on psql0-2 {
               device /dev/drbd3;
               disk /dev/sda1;
               meta-disk internal;
               address 173.16.0.18:7784;
       }
}

Para ativar o DRBD:

rc-update add drbd default
/etc/init.d/drbd start

Agora, no primeiro dê o comando abaixo. Este comando apaga tudo do HD do segundo servidor! Nas duas partições!

drbdadm -- --overwrite-data-of-peer primary all

O segundo servidor vai começar a sincronizar os discos já. O melhor seria esperar mas já é possível montar os diretórios e fazer as configurações do PostgreSQL neles no servidor principal já.

Configurando os dois PostgreSQL antes do Heartbeat

O passo aqui é o seguinte. Para fazer os dois PostgreSQL funcionar antes do Heartbeat ser configurado é necessário adicionar os IPs que o heartbeat vai assumir manualmente, fazer a configuração do PostgreSQL, testar tudo e desconfigurar o IP. Tudo isso no primeiro servidor. Todas as configurações aqui são replicadas automaticamente.

Formate as partições e monte-as:

mkfs.ext3 /dev/drbd0
mkfs.ext2 /dev/drbd1
mkfs.ext3 /dev/drbd2
mkfs.ext2 /dev/drbd3
mkdir /var/lib/postgresql
mkdir /var/lib/postgresql2
mount /dev/drbd0 /var/lib/postgresql
mount /dev/drbd2 /var/lib/postgresql2
mkdir /var/lib/postgresql/data
mkdir /var/lib/postgresql2/data
mkdir /var/lib/postgresql/pg_xlog
mkdir /var/lib/postgresql2/pg_xlog
mount /dev/drbd1 /var/lib/postgresql/pg_xlog
mount /dev/drbd3 /var/lib/postgresql2/pg_xlog
rm -rf /var/lib/postgresql/pg_xlog/* /var/lib/postgresql2/pg_xlog/*
chown postgres:postgres /var/lib/postgresql* -R

Agora é a hora de inicializar o diretório do PostgreSQL:

su postgres
/usr/bin/initdb --pgdata /var/lib/postgresql/data --xlogdir /var/lib/postgresql/pg_xlog
/usr/bin/initdb --pgdata /var/lib/postgresql2/data --xlogdir /var/lib/postgresql2/pg_xlog
exit # Sair do su

Edite o postgresql.conf de cada diretorio data, alterando as seguintes configurações:

listen_addresses = '<IP>'
max_connections = 300
max_prepared_transactions = 300
vacuum_cost_delay = 100
vacuum_cost_limit = 200
fsync = on
wal_sync_method = fdatasync
full_page_writes = on
wal_buffers = 256kB
commit_delay = 20000
commit_siblings = 3
constraint_exclusion = on
log_destination = 'syslog'
syslog_facility = 'LOCAL0'
syslog_ident = 'postgres'
autovacuum = on
autovacuum_naptime = 20min
datestyle = 'iso, ymd'
client_encoding = UTF8
deadlock_timeout = 20s
synchronous_commit = off
checkpoint_segments = 8
checkpoint_timeout = 5min
checkpoint_warning = 30s

No /var/lib/postgresql2/data/postgresql.conf, mude unix_socket_directory para /var/tmp.

Edite o pg_hba.conf de cada diretorio data, adicionando as seguintes configurações:

host    all         all         10.0.0.0/16           trust

Para criar o segundo serviço init.d do postgresql:

ln -s /etc/init.d/postgresql /etc/init.d/postgresql2

Em ambos os servidores, copie o arquivo /etc/conf.d/postgresql para /etc/conf.d/postgresql2 mudando nele apenas o PGDATA para /var/lib/postgresql2/data.

Inicialize os dois IPs manualmente:

ip addr add dev eth0 local 10.0.2.1/16 scope global
ip addr add dev eth0 local 10.0.2.2/16 scope global

Inicialize ambos postgresql, teste se está tudo OK.

Depois é só desconfigurar os IPs adicionados acima:

ip addr delete dev eth0 local 10.0.2.1/16
ip addr delete dev eth0 local 10.0.2.2/16

Configurando o Heartbeat

Referência: http://linux-ha.org/GettingStartedRevisedV2

Configure o /etc/ha.d/ha.cf como:

logfacility local7
udpport 694
keepalive 1
deadtime 20
warntime 10
initdead 80
bcast eth1
node load0-1 load0-2
crm yes
auto_failback on

Agora configure o /etc/ha.d/authkeys como:

# Automatically generated authkeys file
auth 1
1 sha1 <CHAVE SECRETA>

Onde <CHAVE SECRETA> deve ser gerada com o comando

dd if=/dev/urandom count=4 2>/dev/null | openssl dgst -sha1

Logo após é necessário mudar o modo de permissão do arquivo:

chmod 600 /etc/ha.d/authkeys

Agora grave o conteúdo abaixo em /var/lib/heartbeat/crm/cib.xml no primeiro servidor apenas:

<?xml version="1.0" ?>
<cib>
       <configuration>
               <crm_config>
                       <cluster_property_set id="cib-bootstrap-options">
                               <attributes>
                                       <nvpair id="default_resource_stickiness" name="default_resource_stickiness" value="50"/>
                                       <nvpair id="short_resource_names" name="short_resource_names" value="TRUE"/>
                                       <nvpair id="symmetric_cluster" name="symmetric_cluster" value="TRUE"/>
                                       <nvpair id="is_managed_default" name="is_managed_default" value="TRUE"/>
                                       <nvpair id="pe-input-series-max" name="pe-input-series-max" value="-1"/>
                               </attributes>
                       </cluster_property_set>
               </crm_config>
               <nodes/>
               <resources>
                       <group id="grp_Postgres1">
                               <primitive id="Postgres1-DRBD"  class="heartbeat" type="drbddisk" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbe6">
                                               <attributes>
                                                       <nvpair id="Postgres1-DRBD-drbd_resource" name="1" value="postgres"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres1-Mnt"  class="ocf" type="Filesystem" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbe7">
                                               <attributes>
                                                       <nvpair id="Postgres1-Mnt-device" name="device" value="/dev/drbd0"/>
                                                       <nvpair id="Postgres1-Mnt-directory" name="directory" value="/var/lib/postgresql"/>
                                                       <nvpair id="Postgres1-Mnt-fstype" name="ftype" value="ext3"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres1-IPaddr"  class="ocf" type="IPaddr" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbe8">
                                               <attributes>
                                                       <nvpair id="Postgres1-IPaddr-ip" name="ip" value="10.0.2.1"/>
                                                       <nvpair id="Postgres1-IPaddr-netmask" name="netmask" value="16"/>
                                                       <nvpair id="Postgres1-IPaddr-nic" name="nic" value="eth0:0"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres1-postgres" class="lsb" type="postgresql" provider="heartbeat" is_managed="true"/>
                       </group>
                       <group id="grp_Postgres2">
                               <primitive id="Postgres2-DRBD"  class="heartbeat" type="drbddisk" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbe9">
                                               <attributes>
                                                       <nvpair id="Postgres2-DRBD-drbd_resource" name="1" value="postgres2"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres2-Mnt"  class="ocf" type="Filesystem" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbea">
                                               <attributes>
                                                       <nvpair id="Postgres2-Mnt-device" name="device" value="/dev/drbd1"/>
                                                       <nvpair id="Postgres2-Mnt-directory" name="directory" value="/var/lib/postgresql2"/>
                                                       <nvpair id="Postgres2-Mnt-fstype" name="ftype" value="ext3"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres2-IPaddr"  class="ocf" type="IPaddr" provider="heartbeat" is_managed="true">
                                       <instance_attributes id="a4578eef-5566-4d9a-ab2a-c2c4aef7cbeb">
                                               <attributes>
                                                       <nvpair id="Postgres2-IPaddr-ip" name="ip" value="10.0.2.2"/>
                                                       <nvpair id="Postgres2-IPaddr-netmask" name="netmask" value="16"/>
                                                       <nvpair id="Postgres2-IPaddr-nic" name="nic" value="eth0:1"/>
                                               </attributes>
                                       </instance_attributes>
                               </primitive>
                               <primitive id="Postgres2-postgres" class="lsb" type="postgresql2" provider="heartbeat" is_managed="true"/>
                       </group>
               </resources>
               <constraints>
                       <rsc_location id="grp_Postgres1-on-load0-1" rsc="grp_Postgres1">
                               <rule id="rule1-grp_Postgres1" score="100">
                                       <expression attribute="#uname" operation="eq" value="load0-1" id="a763d576-13c8-4701-8802-de175e8af2a3"/>
                               </rule>
                       </rsc_location>
                       <rsc_location id="grp_Postgres2-on-load0-2" rsc="grp_Postgres2">
                               <rule id="rule1-grp_Postgres2" score="100">
                                       <expression attribute="#uname" operation="eq" value="load0-2" id="a763d576-13c8-4701-8802-de175e8af2a4"/>
                               </rule>
                       </rsc_location>
               </constraints>
       </configuration>
       <status/>
</cib>

Agora é necessário colocar o owner correto neste arquivo:

chown cluster:cluster /var/lib/heartbeat/crm/cib.xml

A configuração do Heartbeat no primeiro servidor está pronta. Para iniciar o heartbeat e fazer com que ele sempre e inicie, execute os comandos abaixo primeiro servidor:

rc-update add heartbeat default
/etc/init.d/heartbeat start

No segundo servidor, basta copiar os arquivos /etc/ha.d/ha.cf e /etc/ha.d/authkeys, mantendo as permissões, e executar os comandos acima para iniciar o heartbeat. A versão mais atual do arquivo cib.xml será copiada ao segundo servidor pelo próprio heartbeat.