Manual

do

Maker

.

com

Replicação Master-to-Master com MySQL + HA com heartbeat

Replicação Master-to-Master com MySQL + HA com heartbeat

Essa solução é muito bem aplicada em ambientes que necessitem alta disponibilidade para serviço web e banco de dados.
Se sua necessidade é baseada em MySQL a partir da versão 5.5, leia esse outro post sobre a replicação com MySQL 5.5 e faça a parte do HA com heartbeat a partir deste próprio.

O ambiente é montado por 2 servidores X (indiferente do hardware utilizado). O Software é basicamente um LAMP + heartbeat rodando em Debian e o tempo de configuração deve ser de uns 10 minutos.

Existem diversos artigos na internet de ambas soluções aplicadas aqui, porém decidi escrever um artigo sobre o assunto para que eu mesmo possa utilizado na posteridade, quando não me lembrar mais do procedimento.

Primeiros passos

Além da instalação do sistema LAMP (Linux, Apache, PHP, MySQL) e heartbeat será necessário separar 3 IPs fixos, sendo 1 para cada servidor e 1 para utilização de IP virtual. O IP virtual é o IP que será divulgado; as solicitações vindas dos peers remotos terão como destino o IP virtual. Desse modo, a máquina que estiver disponível como master responderá às solicitações. Caso essa máquina se torne indisponível, a outra assumirá automaticamente o IP virtual e passará a responder as solicitações.

No exemplo, utilizarei os IPs 172.0.0.200, 172.0.0.201 e virtual 172.0.0.202. Todas as requisições devem ir para 172.0.0.202.

A base de dados se comunica por background, diretamente pelos seus respectivos IPs. Qualquer operação que seja feita em uma, imediatamente é replicada para a outra e vice-versa. É possível adicionar slaves também para possuir um backup extra, mas não fará parte deste artigo.

Os servidores envolvidos serão nomeados aqui (e preferencialmente utilize a mesma denominação em seu ambiente) como node01 e node02.

Configurando o heartbeat

Os arquivos de configuração do serviço heartbeat ficam em /etc/ha.d. Alguns arquivos não existem, mas basta criá-los com o respectivo conteúdo.

/etc/ha.d/authkeys

Seu conteúdo:

auth 2  

2 sha1 test-ha

/etc/ha.d/haresources

Nesse arquivo especifica-se o nome do servidor master seguido do IP virtual e do script de reload das variáveis de ambiente de trabalho necessárias de se recarregar. Esse script pode ter qualquer nome e deve ficar em /etc/init.d/ como um serviço. Seu conteúdo será explanado mais adiante.
node01 172.0.0.202 reload_environment.sh

/etc/ha.d/ha.cf

Esse arquivo contém as pré-definições do funcionamento do heartbeat.

#arquivo de debug  

debugfile /var/log/ha-debug  

#arquivo de log  

logfile /var/log/ha-log  

#nivel de log  

logfacility local0  

#tempo de tolerância  

keepalive 2  

#tempo para considerar como morto  

deadtime 10  

#tempo de warning  

warntime 10  

#diretiva utilizada em tempo de inicialização do heartbeat  

initdead 30  

#...  

udpport 694  

#unicast respectivo ao host oposto; 201 no node01, 200 no node02  

ucast eth0 172.0.0.201  

# O auto_failback retoma como master automaticamente quando se encontra em condições de fazê-lo. Deixá-lo como  

#off fará com que retorne somente se o host que assumir como master se perca.  

auto_failback off  

# node nodename ... -- must match uname -n  

node node01 node02  

#um host para ping. No caso, o gateway da rede de exemplo.  

ping 172.0.0.254

Opcional

respawn root /usr/lib/heartbeat/ipfail  
apiauth ipfail gid=root uid=root  
apiauth default gid=root  
apiauth cl\_status gid=root

/etc/hostname

O nome curto deve aparecer como node01 ou node02. Constate isso com hostname -s.

/etc/hosts

Não experimentei resolver os nomes de outra maneira, então deixo a recomendação de incluir os IPs reais dos hosts no arquivo de hosts:

172.0.0.200 node01  

172.0.0.201 node02

/etc/network/interfaces

Configure apenas os IPs reais em ambos os hosts. Por exemplo:

iface eth0 inet static  

address 172.0.0.200  

netmask 255.255.255.0  

network 172.0.0.0  

broadcast 172.0.0.255  

gateway 172.0.0.254

/etc/apache2/ports.conf

Nesse arquivo deve-se especificar o IP virtual, tal como abaixo:

NameVirtualHost 172.0.0.202:80  

Listen 80
# SSL name based virtual hosts are not yet supported, therefore no  
# NameVirtualHost statement here  
Listen 443

/etc/init.d/reload_environment.sh

Se preferir, renomeie o arquivo a contento, lembrando que se alterado, não esqueça de mudar o nome também no arquivo haresources.

O conteúdo desse arquivo é para exemplo. No caso, estou fazendo HA para o Asterisk:

#! /bin/sh  

# /etc/init.d/reload_environment.sh  

#

# Some things that run always  
touch /var/lock/reload\_environment.sh

# Carry out specific functions when asked to by the system  
case "$1" in  
start)  
#para o asterisk  
/usr/sbin/asterisk -rx "restart now"  
#matar o script XXX  
$(which kill) -9 $(ps ax|egrep 'XXX.py'|egrep -v 'grep'|awk '{print $1}') 2>/dev/null  
exit 0  
;;  
stop)  
echo "Nothing to do"  
;;  
\*)  
echo "Usage: /etc/init.d/blah {start|stop}"  
exit 1  
;;  
esac




exit 0

Adeque-o para sua necessidade.

Iniciando o HeartBeat

Feitas essas configurações, o serviço pode ser iniciado:
/etc/init.d/heartbeat start

Se tiver algum erro, verifique suas configurações, os logs e finalmente faça uma busca no google. Se tudo estiver perdido, escreva o problema nos comentários e "se" realmente for algo que julgar válido, escrevo a resposta.

Em alguns momentos o IP virtual deverá subir na interface eth0 (que foi a utilizada nesse exemplo) do node01. Isso representa o sucesso da operação.

Se desejar fazer um teste com o HA, insira em /var/www um arquivo html com o nome do host. Com ambos os hosts em um mesmo switch, a partir de um client acesse o IP virtual e veja o nome de host que aparece; faça refresh a vontade. Enquanto isso, peça a alguém que remova o cabo do node que estiver sendo exibido durante seus refresh. O IP virtual subirá no outro node.

No arquivo ha.cf você poderá então mudar o tempo de vida conforme desejado, para mais ou para menos, mas tudo dependerá da aplicação que pretende rodar em seu ambiente. Fatores como qualidade de rede física e lógica também podem influenciar.

Configurando o MySQL para Master-to-Master

O MySQL é impressionante por sua facilidade de configuração. Além de estar toda concentrada no arquivo /etc/mysql/my.cnf, não é necessário instalar nenhum pacote adicional para a tarefa. Não estou certo de que posso ser claro na explicação dos parâmetros, mas seguramente é uma configuração funcional. Seu conteúdo:

#padrao  

[client]  

port = 3306  

socket = /var/run/mysqld/mysqld.sock

[mysqld_safe]  
socket = /var/run/mysqld/mysqld.sock  
nice = 0  
[mysqld]  
#  
# \* Basic Settings  
#  
user = mysql  
pid-file = /var/run/mysqld/mysqld.pid  
socket = /var/run/mysqld/mysqld.sock  
port = 3306  
basedir = /usr  
datadir = /var/lib/mysql  
tmpdir = /tmp  
language = /usr/share/mysql/english  
skip-external-locking  
#  
# Instead of skip-networking the default is now to listen only on  
# localhost which is more compatible and is not less secure.  
#bind-address = 127.0.0.1  
#  
# \* Fine Tuning  
#  
key\_buffer = 16M  
max\_allowed\_packet = 16M  
thread\_stack = 128K  
thread\_cache\_size = 8  
# This replaces the startup script and checks MyISAM tables if needed  
# the first time they are touched  
myisam-recover = BACKUP  
#max\_connections = 100  
#table\_cache = 64  
#thread\_concurrency = 10  
#  
# \* Query Cache Configuration  
#  
query\_cache\_limit = 1M  
query\_cache\_size = 16M  
#  
# \* Logging and Replication  
#  
# Both location gets rotated by the cronjob.  
# Be aware that this log type is a performance killer.  
#log = /var/log/mysql/mysql.log  
#  
# Error logging goes to syslog. This is a Debian improvement :)  
#  
# Here you can see queries with especially long duration  
#log\_slow\_queries = /var/log/mysql/mysql-slow.log  
#long\_query\_time = 2  
#log-queries-not-using-indexes  
#  
# The following can be used as easy to replay backup logs or for replication.  
# note: if you are setting up a replication slave, see README.Debian about  
# other settings you may need to change.

#configuracoes para o servico  
#no node02 utilize 2 e no node01 utilize 1 no server-id  
server-id = 2  
replicate-same-server-id= 0  
auto-increment-increment= 2  
auto-increment-offset = 2  
log\_bin = /var/log/mysql/mysql-bin.log  
expire\_logs\_days = 10  
max\_binlog\_size = 500M

#bases que nao serao replicadas devem ser explicitamente ignoradas  
binlog\_ignore\_db = mysql

#bases a replicar  
binlog\_do\_db = asterisk  
replicate-do-db = asterisk

binlog\_do\_db = base\_2  
replicate-do-db = base\_2

binlog\_do\_db = base\_3  
replicate-do-db = base\_3

binlog\_do\_db = base\_n  
replicate-do-db = base\_n  
#o master para o nodeX é o outro node  
master-host = 172.0.0.201  
#sugestao: replicar com o mesmo usuario e senha para facilitar a configuracao  
master-user = replicador  
master-password = escravo  
master-connect-retry = 60

#  
# \* BerkeleyDB  
#  
# Using BerkeleyDB is now discouraged as its support will cease in 5.1.12.  
skip-bdb

[mysqldump]  
quick  
quote-names  
max\_allowed\_packet = 16M

[mysql]  
#no-auto-rehash # faster start of mysql but no tab completition

[isamchk]  
key\_buffer = 16M

#  
# \* IMPORTANT: Additional settings that can override those from this file!  
# The files must end with '.cnf', otherwise they'll be ignored.  
#  
!includedir /etc/mysql/conf.d/

Terminada a configuração do my.cnf, deve-se ainda executar a permissão para o usuário de replicação. Algo como isto funciona bem:
mysql> grant all privileges on *.* to replicador@'%' identified by 'escravo';

Pode ser necessário (porque tenho certeza de que funcionou sem, mas já tive que fazê-lo) utilizar um comando para levantar o slave:
mysql> start slave;
A partir de então, pode-se testar fazendo um insert em qualquer um dos nodes e verificando sua inserção no outro e vice-versa. Alguns problemas podem ser resolvidos a partir desses documentos:
http://dev.mysql.com/doc/refman/4.1/pt/replication-problems.html
http://dev.mysql.com/doc/refman/4.1/pt/replication-faq.html

Alguns comandos também podem auxiliar em diagnósticos e informações, como:

show slave statusG;  

show master statusG;  

show processlist;

O comando show slave statusG deverá retornar em seu primeiro campo a informação:
Slave_IO_State: Waiting for master to send event

E mais abaixo, outras duas informações essenciais:

Slave_IO_Running: Yes  

Slave_SQL_Running: Yes

Infelizmente é inviável explicar todos os parâmetros, todos os comandos diagnósticos, ações a tomar em casos de falhas etc, mas ao menos você poderá iniciar um projeto de replicação com HA a partir de um ambiente funcional e os avanços dependerão apenas de você. ;-)

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.