DiarioNet

A vista de sua janela pode ser a liberdade

Archive for the ‘Open-Source’ Category

Cluster Beowulf

leave a comment »

Guilherme Petrocchi – petrocchi@linusbera.com.br
José Luiz Costa Neto – zeluiz@linusbera.com.br

Definição

Um cluster, ou aglomerado de computadores, é formado por um conjunto de computadores que utiliza-se de um tipo especial de sistema operacional classificado como sistema distribuído.
É construído muitas vezes a partir de computadores convencionais (personal computers), sendo que estes vários computadores são ligados em rede e comunicam-se através do sistema de forma que trabalham como se fosse uma única máquina de grande porte. Há diversos tipos de cluster. Um tipo famoso é o cluster da classe Beowulf, constituído por diversos nós escravos gerenciados por um só computador.

História

A idéia inicial que conduz ao cluster foi desenvolvida na década de 1960 pela IBM como uma forma de interligar grandes mainframes, visando obter uma solução comercialmente viável de paralelismo.
Nesta época o sistema HASP (Houston Automatic Spooling Priority) da IBM e seu sucessor, JES (Job Entry System) proviam uma maneira de distribuir tarefas nos mainframes interligados. A IBM ainda hoje (2001) suporta o cluster de mainframes através do Parallel Sysplex System, que permite ao hardware, sistema operacional, middleware e software de gerenciamento do sistema prover uma melhora dramática na performance e custo ao permitir que usuários de grandes mainframes continuem utilizando suas aplicações existentes.
Entretanto o cluster ganhou força até que três tendências convergiram nos anos 1980: microprocessadores de alta performance, redes de alta velocidade, e ferramentas padronizadas para computação distribuída de alto desempenho. Uma quarta tendência possível é a crescente necessidade de poder de processamento para aplicações científicas e comerciais unida ao alto custo e a baixa acessibilidade dos tradicionais supercomputadores.
No final de 1993, Donald Becker e Thomas Sterling iniciaram um esboço de um sistema de processamento distribuído construído a partir de hardware convencional como uma medida de combate aos custos dos supercomputadores. No início de 1994, trabalhando no CESDIS, com o patrocínio do projecto HTPCC/ESS, criaram o primeiro cluster desse tipo, o projeto Beowulf.
O protótipo inicial era um cluster de 16 processadores DX4 ligados por dois canais Ethernet acoplados (Ethernet bonding). A máquina foi um sucesso instantâneo e esta idéia rapidamente se espalhou pelos meios acadêmicos, pela NASA e por outras comunidades de pesquisa.

Montagem física do Cluster

Para a confecção do cluster nós escolhemos utilizar quatro máquinas sendo 1 master e 3 slaves, para isso foram definidos os seguintes hardwares para as máquinas:
Master
Athlon XP 2800 +, 1024 MB de RAM, HD 40 GB, PCI LAN Realtek pci 10/100
Slave1
Pentium II 350 Mhz, 192 MB de RAM, HD 6,2 GB, PCI LAN Realtek pci 10/100
Slave2
Pentium D 4 3,06 Ghz, 1024 MB de RAM, HD 80 GB, PCI LAN Realtek pci 10/100
Slave3
Athlon XP 1100+, 1024 MB de RAM, HD 80 GB, PCI LAN Realtek pci 10/100

Configurações básicas e principal

Durante a configuração e instalação do sistema operacional das máquinas que iriam compor o cluster fora utilizado a distribuição Linux Fedora Core 4, kernel 2.4.6, depois desse ponto começamos a configurar alguns arquivos de grande importância.
O primeiro passo foi configurar a rede nas máquinas do cluster, que estavam dispostas em uma topologia estrela utilizando de uma rede Ethernet 100 Mbits/s, ligadas com cabo UTP categoria 5 padrão 568A, ligadas a um switch 100/100 de oito portas. Segue abaixo a configuração das máquinas.
Master
IP: 99.99.99.40/255.255.255.0
Slave1
IP: 99.99.99.41/255.255.255.0
Slave2
IP: 99.99.99.42/255.255.255.0
Slave3
IP: 99.99.99.43/255.255.255.0
Além de arquivos do tipo hosts que funcionam como servidor de DNS para comunicação entre as máquinas.
/etc/hosts

Master master.linusbera
Slave1 slave1.linusbera
Slave2 slave2.linusbera
Slave3 slave3.linusbera

/etc/hosts.equiv (arquivo que define a confiança entre as máquinas)

Master
Slave
Slave1
Slave2
Slave3

/home/.rhosts

.rhosts
Master
Slave1
Slave2
Slave3

/root/.rhosts

.rhosts
Master
Slave1
Slave2
Slave3

/etc/securetty (arquivo indicado para comunicação entre as máquinas sem a necessidade de senha)

rsh
ssh
rlogin

Configuração servidor de tempo (NTPD)

A configuração do servidor de tempo tem função vital no cluster, já que na estrutura do cluster entre as máquinas não pode existir uma diferença de sincronismo maior que vinte minutos, fazendo assim a configuração de um servidor de tempo vital para o funcionamento do cluster, segue abaixo as configurações utilizadas:
Master:
/etc/ntp.conf

server 127.0.0.1 prefer
fudge 127.0.0.1 stratum 0
driftfile /etc/ntp/drift
authenticate no

Slaves:
/etc/ntp.conf

server 99.99.99.40
driftfile /etc/ntp/drift
authenticate no

Servidor de NFS

Este serviço serve para fazer o espelhamento das pastas definidas entre as máquina do cluster, fazendo um sincronismo entre as pastas afim de que todas contenham os mesmo arquivos.
Master:
/etc/exports

/usr/local *(rw,no_root_squash)

Slaves:
Acrescentar ao final do arquivo /etc/fstab a seguinte linha:

99.99.99.40:/usr/local   /usr/local   nfs   exec,dev,suid,rw   1   1

Protocolos de comunicação

Para comunicação entre as máquinas foram utilizados os pacotes de RSH, RLOGIN e SSH.

Programação Paralela (MPI, MPICH)

O MPI (Message Passing Interface) é constituído por um padrão de troca de mensagens com sintaxe definida, mas preservando características exclusivas de cada arquitetura, inclusive para arquiteturas de memória compartilhada.
O principal objetivo do MPI é otimizar a comunicação e aumentar o desempenho computacional das máquinas, não possuindo dessa forma gerenciamento dinâmico de processos e processadores.
Embora exista a restrição citada acima, os programas escritos em MPI tendem a serem mais eficientes pelo fato de não haver overhead na carga de processos em tempo de execução.

Funcionamento do MPICH

O MPI funciona da seguinte forma: cada máquina (node) recebe uma copia do código fonte e um nome. Cada node começa a executar o programa a partir da primeira linha de comando utilizando as seguintes diretrizes:

  • Executar todas as linhas de comando não nomeadas;
  • Executar as linhas de comando nomeadas com o mesmo nome do node;
  • Não executar as linhas de comando com o nome de outro node.

Para que o programa siga essas diretrizes, o que é feito é a inclusão de vários comandos if, com a seguinte estrutura:
"Se eu sou o nodo tal, faço isso… Se não faço aquilo…". (FONTE: Pitanga, 2004)
A grande dificuldade que esse sistema acarreta é a necessidade de manter os diversos processos de troca de informações em sincronismo, para que uma máquina não perca muito tempo aguardando que as outras máquinas enviem informações.

Instalando o MPI/MPICH

Salvar o arquivo mpich.tar.gz na pasta /usr/local. Execute as seguinte linha de comando:
# tar -zxvf mpich.tar.gz
# cd /usr/local/mpich-1.2.7
# ./configure –prefix=/usr/local
# make
# make install

Testando aplicação em MPI

# cd /usr/local/examples
Código em C:
O código fonte utilizado em nossa aplicação foi o cpi.c, que calcula o valor aproximado de Pi. O mesmo é incluso no pacote mpich.tar.gz, localizado em #usr/local/mpich-1.2.7/examples/basic.

#include "mpi.h"
#include <stdio.h>
#include <math.h>
double f( double );
double f( double a )
{
    return (4.0 / (1.0 + a*a));
}
int main( int argc, char *argv[])
{
    int done = 0, n, myid, numprocs, i;
    double PI25DT = 3.141592653589793238462643;
    double mypi, pi, h, sum, x;
    double startwtime = 0.0, endwtime;
    int  namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    MPI_Get_processor_name(processor_name,&namelen);
    fprintf(stderr,"Process %d on %s\n",
       myid, processor_name);
    n = 0;
    while (!done)
    {
        if (myid == 0)
        {
/*
            printf("Enter the number of intervals: (0 quits) ");
            scanf("%d",&n);
*/
       if (n==0) n=100; else n=0;
       startwtime = MPI_Wtime();
        }
        MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
        if (n == 0)
            done = 1;
        else
        {
            h   = 1.0 / (double) n;
            sum = 0.0;
            for (i = myid + 1; i <= n; i += numprocs)
            {
                x = h * ((double)i – 0.5);
                sum += f(x);
            }
            mypi = h * sum;
            MPI_Reduce(&mypi, π, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
            if (myid == 0)
       {
                printf("pi is approximately %.16f, Error is %.16f\n",
                       pi, fabs(pi – PI25DT));
      endwtime = MPI_Wtime();
      printf("wall clock time = %f\n",
             endwtime-startwtime);          
       }
        }
    }
    MPI_Finalize();
    return 0;
}

Compilando código em mpi C:
# mpicc cpi.c -o cpi
Executando o código, observando que o atributo do comando "-np" indica o número de processos que serão distribuídos no cluster.
# mpirun -np 4 cpi
pi is approximately 3.1416009869231254, Error is 0.0000083333333323
wall clock time = 0.000238

Monitoramento cluster

Para monitorar o cluster foi utilizado uma ferramenta chamada bWatch, para instalar esta ferramenta faça:
Copie o arquivo bWatch.tar.gz para a pasta /usr/local. Execute os comandos:
# tar -zxvf bWatch.tar.gz
# cd bWatch-1.1.0
# make bWatch
# bWatch.tcl

Local do texto original: http://vivaolinux.com.br/artigos/verArtigo.php?codigo=7661&pagina=1

Written by xvr2k3rds

30 janeiro, 2008 at 1:32 am