Archive for the Cluster Category

Se você precisa balancear a carga em seu webserver e não tem (ou não pode usar) um hardware dedicado para isso, segue alguns exemplos práticos:

Apache httpd:

NameVirtualhost *:80
<VirtualHost *:80>
    ServerName everlinux-homolog.com
    ServerAlias 200.24.12.34 10.10.23.53 10.10.23.56
    ServerAdmin suporte@everlinux.com
    ErrorLog "|/usr/sbin/rotatelogs /var/log/httpd/error_log.%Y%m%d 86400 -180"
    CustomLog "|/usr/sbin/rotatelogs /var/log/httpd/access_log.%Y%m%d 86400 -180" combined
 
        <Proxy balancer://everhttp>
          BalancerMember http://10.10.23.53:80/ ping=10
          BalancerMember http://10.10.23.56:80/ ping=10
        </Proxy>
 
ProxyPreserveHost on
ProxyPass / balancer://everhttp/
ProxyPassReverse /oii balancer://everhttp/
 
</VirtualHost>

Nginx

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  50;
 
      upstream everbalance {
         ip_hash;
         server 10.10.23.53 max_fails=3 fail_timeout=30s;
         server 10.10.23.56 max_fails=3 fail_timeout=30s;
         }
 
    server {
         listen  202.34.52.24:80;
         server_name  everlinux-homolog.com;
         location /
           {
            access_log   /var/log/nginx/hdig.log;
            proxy_pass   http://everbalance;
            proxy_set_header Host $host;
           }
         }
}

As linhas “ProxyPreserveHost on” (apache) e “proxy_set_header Host $host;” (nginx) são importantes caso sua aplicação trabalhe com o nome do domínio da URL para montar alguma coisa dinamicamente. Conteúdo estático geralmente não é necessário estas variáveis.

Neste exemplo eu tenho um cluster em produção com a LUN compartilhada de 500 GB via GFS. Pretendo dobrar sua capacidade sem parada no sistema.

1-) Adicionar um “Mapped Raw LUN” no ESX, em Compatibility Mode “Physical”.
A “SCSI Controller” também precisa ser “Physical”, e o disco RAW precisa estar nesta controller dedicada

Ex:
Hard Disk 1 = SCSI Controller 0 = SCSI (0:0)
Hard Disk 2 = SCSI Controller 1 = SCSI (1:0)
Hard Disk 2 = SCSI Controller 1 = SCSI (1:1)

2-) Adicionar a LUN no Linux:

[root@cluster-02 ~]# cat /proc/scsi/scsi 
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: VMware   Model: Virtual disk     Rev: 1.0 
  Type:   Direct-Access                    ANSI SCSI revision: 02
Host: scsi1 Channel: 00 Id: 00 Lun: 00
  Vendor: IBM      Model: 1815      FAStT  Rev: 0914
  Type:   Direct-Access                    ANSI SCSI revision: 05
 
[root@cluster-02 ~]# echo "scsi add-single-device 1 0 1 0" > /proc/scsi/scsi
 
[root@cluster-02 ~]# cat /proc/scsi/scsi 
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: VMware   Model: Virtual disk     Rev: 1.0 
  Type:   Direct-Access                    ANSI SCSI revision: 02
Host: scsi1 Channel: 00 Id: 00 Lun: 00
  Vendor: IBM      Model: 1815      FAStT  Rev: 0914
  Type:   Direct-Access                    ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 01 Lun: 00
  Vendor: IBM      Model: 1815      FAStT  Rev: 0914
  Type:   Direct-Access                    ANSI SCSI revision: 05

Sendo: Host – Channel – ID – Lun
(um reboot também funcionaria :-) )

3-) Configurar o Cluster de LVM

3a-) Criando um Logical Volume

# fdisk /dev/sdc (usar ID 8e = Linux LVM)
# partprobe (em todas as maquinas do cluster)
# lvmconf --enable-cluster
# pvcreate /dev/sdb1
# vgcreate -Ay -cy pre_homolog /dev/sdb1
# lvcreate -L 499G -n hotsites pre_homolog

ou

3b-) Aumentando um já existente

[root@cluster-01 ~]# pvs
  PV         VG          Fmt  Attr PSize   PFree
  /dev/sdb1  pre_homolog lvm2 a-   499.99G 1016.00M
  /dev/sdc1              lvm2 --   499.99G  499.99G
 
[root@cluster-01 ~]# vgextend pre_homolog /dev/sdc1
  Volume group "pre_homolog" successfully extended
 
[root@cluster-01 ~]# vgs
  VG          #PV #LV #SN Attr   VSize   VFree  
  pre_homolog   2   1   0 wz--nc 999.98G 500.98G
 
[root@cluster-01 ~]# pvs
  PV         VG          Fmt  Attr PSize   PFree
  /dev/sdb1  pre_homolog lvm2 a-   499.99G 1016.00M
  /dev/sdc1  pre_homolog lvm2 a-   499.99G  499.99G
 
[root@cluster-01 ~]# lvextend -Ay -l+128252 /dev/pre_homolog/hotsites
  Extending logical volume hotsites to 999.98 GB
  Logical volume hotsites successfully resized
 
[root@cluster-01 ~]# lvs
  LV       VG          Attr   LSize   Origin Snap%  Move Log Copy%  Convert
  hotsites pre_homolog -wi-ao 999.98G
 
[root@cluster-01 ~]# vgs
  VG          #PV #LV #SN Attr   VSize   VFree
  pre_homolog   2   1   0 wz--nc 999.98G    0
 
[root@cluster-01 ~]# pvs
  PV         VG          Fmt  Attr PSize   PFree
  /dev/sdb1  pre_homolog lvm2 a-   499.99G    0
  /dev/sdc1  pre_homolog lvm2 a-   499.99G    0

4-) Aumentar o GFS

Com o /gfs montado, usando o gfs_grow

[root@cluster-01 ~]# gfs_grow -v /gfs
FS: Mount Point: /gfs
FS: Device: /dev/mapper/pre_homolog-hotsites
FS: Options: rw,hostdata=jid=0:id=131073:first=0
FS: Size: 130809855
RGRP: Current Resource Group List:
RI: Addr 130744354, RgLen 5, Start 130744359, DataLen 65496, BmapLen 16374
RI: Addr 130678852, RgLen 5, Start 130678857, DataLen 65496, BmapLen 16374
RI: Addr 130613350, RgLen 5, Start 130613355, DataLen 65496, BmapLen 16374
...
...
RI: Addr 261895985, RgLen 15, Start 261896000, DataLen 243904, BmapLen 60976
RGRP: 539 Resource groups in total
Preparing to write new FS information...
Done.

Antes:

[root@cluster-02 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             6.9G  1.8G  4.7G  28% /
tmpfs                 1.9G     0  1.9G   0% /dev/shm
/dev/mapper/pre_homolog-hotsites
                      493G   12G  482G   3% /gfs

Depois:

[root@cluster-02 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             6.9G  1.8G  4.7G  28% /
tmpfs                 1.9G     0  1.9G   0% /dev/shm
/dev/mapper/pre_homolog-hotsites
                      994G   12G  983G   2% /gfs

Teste_ESX_GFS_Ever

Já escrevemos bastante sobre Virtualização usando Xen e Cluster aqui no Blog.

Desta vez, para começar bem 2009 eu irei apenas citar alguns testes que fiz usando VMware ESX com GFS, em um Storage compartilhado, usando tecnologia Red Hat 5.2 x86_64 com um Fence_VMWare Tech Preview do RHEL 5.3 beta.

O Problema

Eu já o utilizava o GFS com Xen ou até mesmo com DRBD em Muti-Master, porém o grande problema é que não existia um fence para vmware que funcionasse a contento.

O fence_vmware, escrito em perl parou no tempo em Agosto de 2007 e fora que a VMware Perl API necessária não compila em 64 bits.

A Red Hat pretende lançar agora no RHEL 5.3 um fence_vmware re-escrito em Python, porém ele ainda não trabalha com Cluster, pois conecta-se direto na máquina física, e não no VMCenter.

A Solução

A solução é utilizar o vmware_fence_vi, também da Red Hat que está em fase de desenvolvimento atualmente, que conecta no Virtual Center e não na máquina física que pode estar morta :)

Segue o /etc/cluster/cluster.conf utilizado nos testes:

Configuração do Cluster

<cluster alias="Cluster_GFS" config_version="10" name="Cluster_GFS">
	<fence_daemon clean_start="0" post_fail_delay="0" post_join_delay="3"/>
<cman>
    <multicast addr="224.0.0.1" interface="eth1"/>
</cman>
	<clusternodes>
		<clusternode name="cluster-01-node-01" nodeid="1" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
	           <fence>
        	        <method name="single">
                	        <device name="node-01"/>
	                </method>
	           </fence>
                </clusternode>
                <clusternode name="cluster-01-node-02" nodeid="2" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
                   <fence>
                        <method name="single">
                                <device name="node-02"/>
                        </method>
                   </fence>
                </clusternode>
                <clusternode name="cluster-01-node-03" nodeid="3" votes="1">
			<multicast addr="224.0.0.1" interface="eth1"/>
                   <fence>
                        <method name="single">
                                <device name="node-03"/>
                        </method>
                   </fence>
                </clusternode>
	</clusternodes>
	<fencedevices>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-01" passwd="xxxxx" port="Cluster_01_Node_01"/>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-02" passwd="xxxxx" port="Cluster_01_Node_02"/>
		<fencedevice agent="fence_vmware_vi" ipaddr="10.107.113.2" login="user" name="node-03" passwd="xxxxx" port="Cluster_01_Node_03"/>
	</fencedevices>
</cluster>

Notas:

1-) Troque parênteses por sinal de maior/ menor (maldito wordpress!) :(

2-) O IP 10.107.113.2 é o IP do Virtual Center. Ele sempre sabe onde a máquina virtual se encontra, mesmo que ela for migrada para outro host físico.

3-) Forçamos o MultiCast pela eth1, que é uma interface dedicada para o heartbeat do Cluster. Algumas vezes o multicast tentava sair pela interface de loopback e cada máquina achava que estava sozinha no cluster :(

/etc/hosts dos servidores:

10.0.0.1 cluster-01-node-01
10.0.0.2 cluster-01-node-02
10.0.0.3 cluster-01-node-03
10.0.1.1 node-01
10.0.1.2 node-02
10.0.1.3 node-03

Script de escrita

Foi utilizado um script para escrever no storage compartilhado a cada segundo com o nome da máquina e a hora exata (minuto, segundo) da escrita.

# for i in `seq 1 1000`; do a=`echo $RANDOM | cut -c1-2`; dd if=/dev/zero of=/teste/`hostname -s`-`date +%H_%M_%S` bs=512k count=$a; sleep 1; done

Nós do Cluster

[root@cluster-01-node-02 ~]# cman_tool nodes
Node Sts Inc Joined Name
1 M 60 2009-01-06 19:46:11 cluster-01-node-01
2 M 56 2009-01-06 19:46:11 cluster-01-node-02
3 M 68 2009-01-06 19:56:35 cluster-01-node-03

Fence Device

/sbin/fence_vmware_vi - DEVEL.1229423489
 
# The Following agent has been tested on:
# VI Perl API 1.6 against:
#       VMware ESX 3.5
#       VMware ESXi 3.5 update 2
#       VMware Virtual Center 2.5
#</code>

Com a seguinte modificação na linha 13:

#sys.path.append("@FENCEAGENTSLIBDIR@")
sys.path.append("/usr/lib/fence")

Desligar máquina VIRTUAL

Teste: Desligar máquina VIRTUAL cluster-01-node-03

Resultado: GFS congelado por ~1 minuto

O que ocorreu: O fence_vmware_vi conectou no vmcenter e tirou a máquina do Cluster, liberando assim o I/O.

Desligar máquina FISICA normalmente

Teste: Desligar com reboot máquina FISICA 01 (que tinha a cluster-01-node-03)

Resultado: GFS congelado por ~2 minutos

O que ocorreu: Máquinas física iniciou o processo de reboot, a máquina virtual cluster-01-node-03 morreu e foi migrada e reiniciada em outro host físico.

PS: A máquina virtual não retornou ao seu host de origem quando a máquina física voltou

-rw-r--r-- 1 root root 44040192 Jan 6 2009 cluster-01-node-01-19_50_52
-rw-r--r-- 1 root root 15204352 Jan 6 2009 cluster-01-node-01-19_50_53
-rw-r--r-- 1 root root 10485760 Jan 6 2009 cluster-01-node-01-19_50_54
-rw-r--r-- 1 root root 41418752 Jan 6 2009 cluster-01-node-01-19_52_57
-rw-r--r-- 1 root root 17825792 Jan 6 2009 cluster-01-node-01-19_52_58
-rw-r--r-- 1 root root 23068672 Jan 6 2009 cluster-01-node-01-19_52_59
-rw-r--r-- 1 root root 6815744 Jan 6 2009 cluster-01-node-01-19_53_00
-rw-r--r-- 1 root root 49807360 Jan 6 2009 cluster-01-node-01-19_53_01
-rw-r--r-- 1 root root 10485760 Jan 6 2009 cluster-01-node-01-19_53_03

Desligar máquina FISICA brutalmente

Desligar com RESET (via RSA) máquina FISICA 02 (que tinha a cluster-01-node-03)

Resultado: GFS congelado por ~3 minutos

O que ocorreu: Máquinas física foi brutalmente desligada, a máquina virtual cluster-01-node-03 morreu e foi migrada e reiniciada em outro host físico.

O fence_vmware_vi tentou várias vezes tirar a máquina do cluster com falhas consecutivas pois a máquina não mais existia e o ESX demorou um pouco para entender o que estava acontecendo.

PS: A máquina virtual não retornou ao seu host de origem quando a máquina física voltou

-rw-r--r-- 1 root root 12058624 Jan 6 20:17 cluster-01-node-01-20_17_57
-rw-r--r-- 1 root root 11534336 Jan 6 20:17 cluster-01-node-01-20_17_58
-rw-r--r-- 1 root root 10485760 Jan 6 20:17 cluster-01-node-01-20_17_59
-rw-r--r-- 1 root root 5242880 Jan 6 20:18 cluster-01-node-01-20_18_00
-rw-r--r-- 1 root root 5767168 Jan 6 20:20 cluster-01-node-01-20_18_01
-rw-r--r-- 1 root root 6291456 Jan 6 20:21 cluster-01-node-01-20_21_00
-rw-r--r-- 1 root root 37748736 Jan 6 20:21 cluster-01-node-01-20_21_02
-rw-r--r-- 1 root root 17825792 Jan 6 20:21 cluster-01-node-01-20_21_03
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_04
-rw-r--r-- 1 root root 34603008 Jan 6 20:21 cluster-01-node-01-20_21_05
-rw-r--r-- 1 root root 5242880 Jan 6 20:21 cluster-01-node-01-20_21_06
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_07
-rw-r--r-- 1 root root 12582912 Jan 6 20:21 cluster-01-node-01-20_21_08

Trechos de logs

Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] The token was lost in the OPERATIONAL state. 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] Receive multicast socket recv buffer size (288000 bytes). 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] Transmit multicast socket send buffer size (262142 bytes). 
Jan  6 20:18:10 cluster-01-node-01 openais[2646]: [TOTEM] entering GATHER state from 2. 
 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] CLM CONFIGURATION CHANGE 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] New Configuration: 
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.1)  
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.2)  
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] Members Left: 
Jan  6 20:18:15 cluster-01-node-01 fenced[2666]: cluster-01-node-03 not a cluster member after 0 sec post_fail_delay
Jan  6 20:18:15 cluster-01-node-01 openais[2646]: [CLM  ] 	r(0) ip(10.0.0.3)  
Jan  6 20:18:15 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
 
  Please use '-h' for usagcation=HASH(0x1df33bd0)ing with the remote host.eports: vmware_helper returned Cannot power off vm Cluster_01_Node_03!
Jan  6 20:18:47 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: e 
Jan  6 20:18:47 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (44880). 
Jan  6 20:18:47 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:18:47 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
Jan  6 20:18:52 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node"
 
Jan  6 20:19:28 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: Connection timed out 
Jan  6 20:19:28 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (45600). 
Jan  6 20:19:28 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:19:28 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
 
Jan  6 20:19:33 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
  Please use '-h' tNotConnected=HASH(0x19bb0090)mote host, since it is disconnected.ware_helper returned Cannot power on vm Cluster_01_Node_03!
Jan  6 20:19:46 cluster-01-node-01 fenced[2666]: agent "fence_vmware_vi" reports: for usage 
Jan  6 20:19:46 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03" failed
Jan  6 20:19:51 cluster-01-node-01 fenced[2666]: fencing node "cluster-01-node-03"
 
Jan  6 20:20:59 cluster-01-node-01 ccsd[2636]: Attempt to close an unopened CCS descriptor (46710). 
Jan  6 20:20:59 cluster-01-node-01 ccsd[2636]: Error while processing disconnect: Invalid request descriptor 
Jan  6 20:20:59 cluster-01-node-01 fenced[2666]: fence "cluster-01-node-03.ig.com.br" success
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Trying to acquire journal lock...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Looking at journal...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Acquiring the transaction lock...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Replaying journal...
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Replayed 79 of 93 blocks
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: replays = 79, skips = 13, sames = 1
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Journal replayed in 1s
Jan  6 20:20:59 cluster-01-node-01 kernel: GFS: fsid=Cluster_GFS:gfs.0: jid=2: Done

Conclusão

Estes testes foram realizados buscando alternativas que reduzam o downtime dos serviços e/ou aplicações contidos em um servidor, chegando a manter sua disponibilidade próxima dos 99,999%.

Como você pôde perceber, esta estrutura permite chegarmos a este número, mas até o momento em que está sendo escrito este post, a versão usada ainda não está homologada, usando pacotes ainda em desenvolvimento (cman+fence_vmware).

Num futuro próximo, já devemos ter algum retorno das empresas desenvolvedoras, pois focam em uma fatia do merdado muito forte e competitiva ($$$).

Suponha um cenário com um “cluster” de máquinas atendendo um serviço qualquer, como um apache por exemplo. Poderíamos usar “n” ferramentas para manter este cluster em sincronia, porém neste artigo eu gostaria de introduzir o poder de um Software Livre 100% Nacional criado pelo Luis Furquim!

Portanto, para que todas as máquinas fiquem em sincronia, usaremos o ChironFS que é um Sistema de Arquivos Tolerante a Falhas com Replicação de Dados, no qual tive contato em Porto Alegre durante o FISL 9.0.

Você pode fazer da apresentação do mesmo aqui: ChironFS

ChironFS

O ChironFS é um Filesystem virtual que utiliza o FUSE. Funciona sincronizando dados entre dois ou mais diretórios, porém, cada um deste diretório pode ser um ponto de montagem de uma máquina remota. Desta forma, o ChironFS atua como uma camada de abstração, sincronizando, por exemplo, um Debian com ext3 local com um Red Hat usando ReiserFS remotamente, usando NFS, SSHFS ou qualquer outro sistema que trabalhe com pontos de montagem.

No Red Hat Enterprise, infelizmente não existe os pacotes para o fuse e nem para seu módulo do kernel, mas você pode busca-los nos repositórios “dag”

http://dag.wieers.com/rpm/packages/dkms-fuse/
http://dag.wieers.com/rpm/packages/fuse/

Neste caso, as 03 máquinas de front-end exportam o diretório /data/dominios via NFS para que seja possível a montagem remota destes diretórios:

# cat /etc/hosts
192.168.0.1 site-1 site-1.com.br
192.168.0.2 site-2 site-2.com.br
192.168.0.3 site-3 site-3.com.br

# cat /etc/exports
/data/sync/site-1 192.168.0.0/24(async,rw,no_root_squash)

# cat /etc/fstab
nfsd /proc/fs/nfsd nfsd auto,defaults 0 0
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs auto,defaults 0 0
site-2:/data/sync/site-2 /data/sync/site-2 nfs soft,timeo=3 0 0
site-3:/data/sync/site-3 /data/sync/site-3 nfs soft,timeo=3 0 0

Portanto:

Site-1: monta a site-2 e a site-3
Site-2: monta a site-1 e a site-3
Site-3: monta a site-1 e a site-2

O ChironFS cuidará para que a escrita feita localmente seja replicada para as outras duas máquinas, configurado desta forma pelo /etc/fstab (atenção, um uma única linha!):

chironfs#/data/sync/site-1=:/data/sync/site-2=:/data/sync/site-3 /data/dominios
fuse allow_other,ctl=/var/run/chironctl,log=/var/log/chironfs.log 0 0

O que quer dizer:

O diretório /data/sync/site-1 (local) deve ser sincronizado com o /data/sync/site-2 (NFS, mais lento) e também com o /data/sync/site-3 (NFS) cada vez que houver escrita em /data/dominios.

Quando houver leitura em /data/domínios, o ChironFS irá dar preferência ao device local, pois é o único que não apresenta os dois pontos (“:”) em sua montagem no /etc/fstab.

Portanto, toda e qualquer escrita no disco que tenha o objetivo de ser sincronizada com as demais máquinas, devem ser feitas diretamente no /data/dominios de qualquer uma das máquinas.

- Monitoramento

O ChironFS a partir da versão 1.1 já vem pronto para ser monitorado pelo Nagios, bastando para isso acrescentar em seu nrpe.cfg:

command[check_site1]=/var/run/chironctl/_data_sync_site-1/check_chironfs.sh
command[check_site2]=/var/run/chironctl/_data_sync_site-2/check_chironfs.sh
command[check_site3]=/var/run/chironctl/_data_sync_site-3/check_chironfs.sh

- Em caso de Problemas

Algumas dicas retiradas do manual oficial: Capítulo 5. Falhas das Réplicas

Toda vez que uma réplica falha, o ChironFS tenta manter seus sistemas rodando. Se a falha ocorrer durante uma operação de leitura, o ChironFS tenta ler de alguma outra réplica e, se conseguir, retorna os dados para o chamador sem gerar erro.

Se a falha ocorrer durante uma operação de escrita, o ChironFS continua tentando escrever nas outras réplicas. Se ao menos uma das réplicas escrever com sucesso, o ChironFS retorna ao chamador sem gerar erro. Mas, desta vez, além de logar o evento, ele desabilita as réplicas que tiverem falhado. Isto significa que não haverá mais leituras ou escritas de/para as réplicas que falharam.

O crontab das máquinas possui um pequeno script para gerar gravação no /data/dominios a fim de tentar detectar quando alguma máquina do “cluster” está fora do ar:

# Verificacao ChironFS
* * * * * /bin/touch /data/dominios/`hostname`; sleep 15; /bin/rm -f /data/dominios/`hostname`

Outra dica importante é “congelar” updates no kernel, pois o ChironFS depende o FUSE que tem um módulo específico para um kernel específico. Portanto, se você atualizar o kernel no RHEL, provavelmente o módulo do fuse não irá mais funcionar e conseqüentemente, o chironfs também não. Para que isso não ocorra acidentalmente:

# cat /etc/yum.conf
[main]
cachedir=/var/cache/yum
distroverpkg=redhat-release
...
exclude=kernel* fuse-kmdl*

Você tem a opção de montar um sistema de arquivos semelhante ao /proc para controlar o ChironFS, que é um sistema de arquivos de controle é composto de um diretório para cada réplica. Seus nomes são o pathname completo da réplica com as barras (“/”) mudadas para caracteres de sublinha.

Cada um deles contém dois arquivos: o primeiro é chamado “status” e contém um número “0″ nas réplicas que estiverem em bom estado ou um número “2″ se a réplica estiver desabilitada e os dados inconsistentes. Basta gravar “0″ ou “2″ neste arquivo para habilitar ou desabilitar a réplica.

Enfim, depois de detectar a falha, corrija a sua causa no servidor de réplica falhado. VOCÊ DEVE PROVER POR SUA CONTA O RESTABELECIMENTO DA CONSISTÊNCIA DOS DADOS NO SERVIDOR DE RÉPLICA QUE FALHOU. EU SUGIRO O USO DO RSYNC PARA ATUALIZAR OS DADOS. ESTE PASSO DEVE SER EFETUADO ANTES DE COLOCAR A RÉPLICA EM ESTADO HABILITADO DE NOVO, CASO CONTRÁRIO, VOCÊ IRÁ CORROMPER SEUS DADOS NAS DEMAIS RÉPLICAS.

Para restabelecer o uso da réplica após o procedimento de recuperação:

# echo 0 > /var/run/chironctl/_data_sync_site-3/status

E acompanhe as mudanças em /var/log/chironfs.log:

2008/08/04 11:35 init: version 1.1.2
2008/08/04 11:44 open+chown failed accessing /data/sync/site-3/site/htdocs/pops/index.html Input/output error
2008/08/04 11:44 disabling replica failed accessing /data/sync/site-3
2008/08/04 11:55 trusting replica /data/sync/site-3 Forced by administrator

Ou simplesmente “reinicie” o ChironFS:

# umount /var/run/chironctl /data/dominios
# mount /data/dominios

* DRBD 8.x

DBRD é a acrônimo para o nome inglês Distributed Replicated Block Device. O DRBD consiste num módulo para o kernel de Linux que, juntamente com alguns scripts, oferece um dispositivo de bloco projetado para disponibilizar dispositivos de armazenamento distribuídos, geralmente utilizado em clusters de alta disponibilidade. Isto é feito espelhando conjuntos de blocos via rede (dedicada). O DRBD funciona, portanto, como um sistema RAID baseado em rede.

Referência: http://pt.wikipedia.org/wiki/DRBD

* GFS 1.x

O “Red Hat Global File System” é um Sistema de Arquivos para Cluster, que permite que vários nós leiam e escrevam dados simultaneamente em um dispositivo compartilhado.

O GFS suporta ACL’s e atributos extendidos, diferente se seu concorrente direto, o OCFS (Oracle Cluster File System)

Vale observar que a versão 2.0 do GFS ainda é considerado “Technology Preview” e não deve ser usado em produção.

Porém, o GFS congela todo o I/O se ele perde um nó (cliente), e fica congelado até o que o nó retorne ou que o mesmo seja “fenced”.

Referência: http://www.redhat.com/gfs/
http://en.wikipedia.org/wiki/Comparison_of_file_systems

* Fence Devices

Fence é algo difícil de traduzir para a nossa língua, assim como a palavra “proxy” O Babylon sugere “grade; muro; cercar; proteger” enquanto o Google Translator sugere “vedação”.

Enfim, é algo nesse sentido: Se um nó do cluster apresenta problemas, para evitar que esse cara escreva algo no FileSystem? e acabe por corromper o mesmo, é necessário que o mesmo seja “fenceado”, ou seja, tirado da jogada. As formas comuns se se fazer isso são:

- Desligando a alimentação de energia deles;
- Desligando a porta do switch;
- Reiniciando a máquina usando DRAC/RSA/ILO (Dell, IBM e HP respectivamente);
- Manualmente;

Utilizaremos a forma menos recomendada (manual) devido a falta de infra-estrutura para utilizarmos as demais. Um script do modificado do DRBD irá tornar o fencing_manual em um fencing automatizado :-D

Referência: http://www.everlinux.com/blog/2008/04/22/redhat-enterprise-linux-51-cluster-suite/

* LVM

Usaremos LVM para garantir flexibilidade da solução:

Criar volumes LV nas duas máquinas

# pvcreate /dev/sda9
# vgcreate vol0 /dev/sda9
# lvcreate -L 105.94G -n lvm vol0

– Configurando o DRBD

Configurar o /etc/hosts para conter todas as maquinas, principalmente o hostname no IP principal e um nome para os IPs da rede de sincronismo:

127.0.0.1 localhost.localdomain localhost
10.10.10.1 hotsite-1.com.br
10.10.10.2 hotsite-2.com.br
192.168.0.3 drbd_hotsite-1 drdb_hotsite-1.com.br
192.168.0.4 drdb_hotsite-2 drdb_hotsite-2.com.br

Configurar o /etc/drbd.conf no master e slave

# DRDB Configuration
global {
        usage-count no;
}
 
resource hotsite {
        protocol C;
 
        startup {
                wfc-timeout 0;
                degr-wfc-timeout 120;
                become-primary-on both;
        }
        disk    {
                fencing resource-and-stonith;
        }
       handlers {
                outdate-peer "/sbin/obliterate";
        }
        net     {
                cram-hmac-alg sha1;
                shared-secret "senha_secreta";
                timeout 60;
                connect-int 10;
                ping-int 10;
                max-buffers 2048;
                max-epoch-size 2048;
                allow-two-primaries;
                after-sb-0pri discard-zero-changes;
                after-sb-1pri discard-secondary;
                after-sb-2pri disconnect;
                rr-conflict violently;
        }
        syncer  {
                rate 650M;
        }
 
        on hotsite-1.com.br {
                device    /dev/drbd0;
                disk      /dev/vol0/lvm;
                address   192.168.0.3:7789;
                flexible-meta-disk internal;
        }
 
 
 
        on hotsite-2.com.br {
                device    /dev/drbd0;
                disk      /dev/vol0/lvm;
                address   192.168.0.4:7789;
                flexible-meta-disk internal;
        }
}

Inicializar as partições para o drbd no master e slave

# drbdadm create-md hotsite |
# drbdadm attach hotsite | drbdadm up hotsite
# drbdadm connect hotsite |

# drbdadm -- --overwrite-data-of-peer primary hotsite
# watch -n1 cat /proc/drbd
# drbdadm primary hotsite

Obs: Caso de erro de carga de modulo inicie o drbd com “service drbd start” mesmo acusando erro, isso fará com que carregue o modulo corretamente.

Inicializar o drbd no master e slave

# service drbd start

- Configurando o cluster para o GFS

* Crie o arquivo de configuração do cluster (/etc/cluster/cluster.conf) para o gfs, em todas as maquinas:

Vou colocar ele em um arquivo separado pois o wordpress não está(va) gostando as tags do mesmo: cluster.conf

Update:

<?xml version="1.0"?>
<cluster name="hotsite" config_version="1">
 
<cman two_node="1" expected_votes="1"/>
 
<fence_daemon post_join_delay="60">
</fence_daemon>
 
<clusternodes>
<clusternode name="drdb_hotsite-1" nodeid="1">
        <fence>
                <method name="single">
                        <device name="node1" ipaddr="192.168.0.3"/>
                </method>
        </fence>
</clusternode>
<clusternode name="drdb_hotsite-2" nodeid="2">
        <fence>
                <method name="single">
                        <device name="node2" ipaddr="192.168.0.4"/>
                </method>
        </fence>
</clusternode>
</clusternodes>
 
<fencedevices>
        <fencedevice name="manual" agent="fence_manual"/>
</fencedevices>
</cluster>

Formatar a partição DRBD com GFS

# gfs_mkfs -t hotsite:gfs-00 -p lock_dlm -j 2 /dev/drbd0

Com isto ele irá iniciar o sincronismo com slave, pode ser observado executando o comando:

# watch -n 1 cat /proc/drbd

Inicie o serviços de cluster:

# service cman start

Testando

# mount -v /dev/drbd0 /data
# for i in `seq 1 10`; do a=`echo $RANDOM`; dd if=/dev/zero of=/data/$a bs=1k count=$a; sleep 1; done
# ls -ltrk /data

Forçando um reboot:
# echo 1 > /proc/sys/kernel/sysrq
# echo b > /proc/sysrq-trigger

Para forçar o sincronismo de uma máquina
(faça somente se souber o que está fazendo)
# drbdsetup /dev/drbd0 primary -o

Ordem dos scripts:

Essa deverá ser a ordem para init level 0 e 6, pois durante o reboot/ shutdown da máquina o procedimento é o seguinte:
- Desmonta a partição
- Tira a máquina do Cluster
- Para o DRBD

[root@hotsite-2 /etc/rc0.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 12 Jun 13 11:57 K80partition -> ../init.d/partition
lrwxrwxrwx 1 root root 14 Jun 13 11:47 K81cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:57 K82drbd -> ../init.d/drbd

Para os init level 3, 4 e 5 deverá ser:
- Coloca a máquina do Cluster
- Inicia o DRBD
- Monta a partição do drbd (pois o mesmo irá falhar durante a inicialização)

[root@hotsite-2 /etc/rc3.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S21cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S70drbd -> ../init.d/drbd
lrwxrwxrwx 1 root root 12 Jun 13 11:55 S91partition -> ../init.d/partition

O Script obliterate

O script Obliterate foi escrito pelo Lon Hohberger e está disponível aqui.

Eu alterei as últimas linhas pois o fence_manual precisa que o comando fence_ack_manual seja executado, senão o GFS não vai liberar o I/O do cluster enquanto o outro nó não retornar com sucesso…

#
fence_node $REMOTE
fence_ack_manual -O -e -n $REMOTE
 
if [ $? -eq 0 ]; then
	# Reference:
	# http://osdir.com/ml/linux.kernel.drbd.devel/2006-11/msg00005.html
	# 7 = node got blown away.  
	exit 7
fi
 
# Fencing failed?!
exit 1

Referência: http://sources.redhat.com/cluster/wiki/DRBD_Cookbook

Por Fábio Silva em seu blog:

“Recentemente precisei configurar um ambiente com RHEL 5.1 Cluster Suite.

Em contato com o pessoal do canal #linux-cluster no irc.freenode.net, eles me esclareceram algumas dúvidas e então consegui montar o ambiente.

Assim, resolvi criar um howto em português para que fosse disponibilizado na página do projeto de cluster da redhat, e aqui está o link para os interessados.”

http://sources.redhat.com/cluster/wiki/QuickStart-Portuguese

Este post é somente para agregar mais uns links interessantes sobre o assunto:

FAQ Sobre Fencing Devices

Replicated Failover Domain Controller and file server using LDAP

How to use GNBD to export and import devices for GFS

Teaching your cluster and storage systems to dance: An introduction to Conga

Using Red Hat GFS with Red Hat Cluster Suite

Por último, mas não menos importante, um “txt” tosco, mas nem por isso com menas informações do que os demais: cluster2-arch.txt. Lá existe uma seção muito esclarecedora sobre “Fencing: What, When, Why”.