!--Tradedoubler site verification 1264796 --> El Rincon del Cluster: Cluster Beowulf + OpenMPI + NFS

Cluster Beowulf + OpenMPI + NFS

Instalación y configuración
Condiciones previas
Antes de comenzar tenemos que tener por lo menos dos maquinas con Ubuntu 9.10 instalado y conectadas en red mediante el protocolo TCP/IP, para este caso todas las maquinas tienen que ser de la misma arquitectura para poder usar el binario compilado en el nodo maestro en cada uno de los nodos esclavos, caso sontrario sera necesario compilar la aplicacion segun cada plataforma. De aca en adelante me referire a los nodos del cluster como nodo maestro o nodo esclavo segun corresponda.
Desde  el nodo maestro podrás controlar el cluster y ejecutar los programas de administracion del cluster, en los nodos esclavos se ejecutaran las aplicaciones distribuidas desde el nodo maestro.
Instalación de los paquetes básicos
En Ubuntu 9.10 es necesario instalar los siguientes paquetes openmpi-bin, openmpi-common, libopenmpi1.3, libopenmpi-dev en todos los nodos del cluster.
Esto se puede hacer como root, en Ubuntu 9.10, con:
sudo apt-get install openmpi-bin openmpi-common libopenmpi1.3 libopenmpi-dev
Los nombres pueden variar en su distribución, pero lo importante es tener en cuenta que debe tener la misma versión de Open MPI en todas las máquinas para que funcione correctamente.
Para el control y administración remoto instalaremos también en cada integrante del cluster el servidor ssh.
sudo apt-get install ssh

Acceso remoto a los nodos

Para que el maestro sea capaz de ejecutar comandos en cada uno de los nodos necesitamos que estos últimos permitan el acceso ssh sin clave para lograr esto haremos lo siguiente.
Primero vamos a generar nuestra clave publica en el nodo meastro, esta sera la que nos permitirá acceder remotamente a cada nodo sin necesidad de proveer una clave por linea de comandos. Es importante que este proceso se haga en el maestro y los nodos esclavos usando el usuario erluco o el que usted halla elegido.
erluco@master:~$ ssh-keygen
Cuando se ejecute ese comando aceptar el directorio por defecto para almacenar las claves y cuando solicita la frase de paso pulsar enter sin ingresar nada.
Tenemos ahora que copiar la llave generada a cada uno de los nodos del cluster, para ello usaremos el comando de copia remota scp.
Primero en cada nodo esclavo creamos el directorio .ssh que es donde pondremos las llaves.
erluco@nodo1:~$ mkdir .ssh
erluco@nodo1:~$ chmod 700 .ssh

Ahora procedemos a la copia.
erluco@master:~$ scp .ssh/id_rsa.pub erluco@192.168.0.101:

Accedemos ahora al nodo donde copiamos la llave y lo ubicamos en el archivo correcto.
erluco@nodo1:~$ mv id_rsa.pub .ssh/authorized_keys

Los dos pasos anteriores, es decir el proceso de copia y mover el archivo a la ubicación correcta se tiene que repetir para cada nodo del cluster.
Ya estamos en condiciones de probar si el nodo maestro es capaz de ejecutar comandos sin necesidad de proveer la clave de cada nodo. Para hacer esta prueba, desde el maestros y como usuario erluco ejecutamos el siguiente comando:
erluco@master:~$ ssh erluco@192.168.0.101 hostname
y nos dara una respuesta :
nodo1
Si responde con el nombre de la maquina remota es que funciona correctamente. Ese comando lo que hace es usar el acceso ssh para a la maquina con el hostname (nodo1)  y ejecutar en ella el comando hostname.
Ahora vamos a corregir nuestros archivos hosts para lograr la identificación de los nodos del cluster mediante el nombre. Editamos en cada componente del nodo el archivo /etc/hosts
sudo nano /etc/hosts
y agregamos las siguientes lineas al contenido preexistente

192.168.0.100   master  master
192.168.0.101   nodo1  nodo1
192.168.0.102   nodo2  nodo2

Servidor de archivos NFS

Necesitamos en cada nodo de nuestro cluster los programas distribuidos que vamos a ejecutar. Para ello vamos a instalar y configurar un servidor de archivos NFS en el nodo maestro y los clientes NFS en los nodos esclavos de manera que trabajemos únicamente en el maestro con nuestros programas y luego mediante la exportación del directorio y el montaje remoto desde los nodos podamos tener los mismos archivos en cada uno de los componentes, existen otras formas de hacer esto, por ejemplo rsync, pero para mi gusto esta me resulto mas cómoda y transparente.
En el nodo maestro:
erluco@master:~# sudo apt-get install nfs-kernel-server nfs-common portmap
Ahora a configurar un recurso compartido, es nuestro caso crearemos un nuevo directorio dentro del home de erluco al que llamaremos clusterdir.
erluco@master:~$ mkdir clusterdir
Ahora nuevamente como root vamos a exportar este directorio mediante NFS para que los nodos puedan montarlo remotamente, editamos el archivo /etc/exports
sudo nano /etc/exports
y agregamos la siguiente linea.
/home/erluco/clusterdir 192.168.0.0/24(rw,no_subtree_check,async,no_root_squash)
Luego reiniciamos el resvicio de NFS con el comando:
erluco@master:~# /etc/init.d/nfs-kernel-server restart
Ahora vamos a instalar lo necesario en cada nodo.
erluco@nodo1:~# sudo apt-get install nfs-common portmap
Una vez que termino la instalacion probaremos si el directorio compartido es accesible desde el nodo:
erluco@nodo1:~# showmount -e 192.168.0.100
y respondera
Export list for 192.168.0.100:
/home/erluco/clusterdir 192.168.0.0/24
Bien ahora vamos a montar el recurso desde linea de comando para luego agregarlo a fstab para el montado automatico cada vez que arranque el nodo. Creamos en la home de la cuenta erluco un directorio llamado clusterdir al igual que el que compartimos en el nodo maestro, este sera el directorio donde montaremos el recursos compartido mediante NFS en el maestro.
erluco@nodo1:~$ mkdir clusterdir
Ahora montamos el directorio remoto, esto lo hacemos como root:
erluco@nodo1:~# sudo mount -t nfs 192.168.0.100:/home/erluco/clusterdir /home/erluco/clusterdir
Podemos comprobar mediante el siguiente comando si todo salio como corresponde:
nodo1:~# mount
y respondera
/dev/xvda2 on / type ext3 (rw,noatime,nodiratime,errors=remount-ro)
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
udev on /dev type tmpfs (rw,mode=0755)
none on /dev/pts type devpts (rw)
192.168.0.100:/home/erluco/clusterdir on /home/erluco/clusterdir type nfs (rw,addr=192.168.0.100)
Observe que el ultimo montaje corresponde al directorio compartido por NFS.
Para automatizar el proceso de montaje del recurso exportado en cada nodo esclavo del cluster modificamos el archivo /etc/fstab
sudo nano /etc/fstab
agregando la siguiente linea:
192.168.0.100:/home/erluco/clusterdir  /home/erluco/clusterdir   nfs      rw,sync,hard,intr  0     0
Para probar en caliente si funciona correctamente procedemos primero a desmontar el recurso con el comando:
erluco@nodo1:~# umount /home/erluco/clusterdir/
Y luego le decimos como al sistema que monte los sistemas declarado en fstab:
erluco@nodo1:~# mount –a
Ya esta todo listo en el NFS para continuar.

Entorno de desarrollo

En el nodo maestro es necesario instalar las herramientas de desarrollo o por lo menos los compiladores y librerías básicas para poder compilar nuestros programas, para ello ejecutamos el siguiente comando:
erluco@master:~# apt-get install build-essential
Configuramos MPI para decirle los nodos que componen el cluster, esto se hace creando un archivo de configuración llamado .mpi_hostfile en el home del usuario erluco del nodo maestros
nano .mpi_hostfile
 con el siguiente contenido:
# Nodo maestro
localhost slots=2

# Nodos esclavos
nodo1 slots=2
nodo2 slots=1

Prueba del cluster

Antes que nada vamos a ver un programa de ejemplo que es el que utilizaremos para probar el cluster, a continuacion el codigo fuente en C++ de un programa que suma numeros primos.
nano primos.c++
y pegamos esto
# include <cstdlib>
# include <iostream>
# include <iomanip>
# include <cmath>
# include <ctime>

# include "mpi.h"

using namespace std;

int main ( int argc, char *argv[] );
int prime_number ( int n, int id, int p );
void timestamp ( );

int main ( int argc, char *argv[] )

{
  int i;
  int id;
  int master = 0;
  int n;
  int n_factor;
  int n_hi;
  int n_lo;
  int p;
  int primes;
  int primes_part;
  double wtime;

  n_lo = 1;
  n_hi = 131072;
  n_factor = 2;
  MPI::Init ( argc, argv );
  p = MPI::COMM_WORLD.Get_size (  );
  id = MPI::COMM_WORLD.Get_rank ( );

  if ( id == master )
  {
    cout << "\n";
    cout << "'Cuenta primos\n";
    cout << "  C++/MPI version\n";
    cout << "\n";
    cout << "  Programa para contar cantidad de primos para un N dado.\n";
    cout << "  Corriendo en " << p << " procesos\n";
    cout << "\n";
    cout << "         N        S          Tiempo\n";
    cout << "\n";
  }

  n = n_lo;

  while ( n <= n_hi )
  {
    if ( id == master )
    {
      wtime = MPI::Wtime ( );
    }
    MPI::COMM_WORLD.Bcast ( &n, 1, MPI::INT, master );

    primes_part = prime_number ( n, id, p );

    MPI::COMM_WORLD.Reduce ( &primes_part, &primes, 1, MPI::INT, MPI::SUM,
      master );

    if ( id == master )
    {
      wtime = MPI::Wtime ( ) - wtime;

      cout << "  " << setw(8) << n
           << "  " << setw(8) << primes
           << "  " << setw(14) << wtime << "\n";
    }
    n = n * n_factor;
  }
  MPI::Finalize ( );

  if ( id == master )
  {
    cout << "\n";
    cout << "PRIME_MPI - Procesos maestro:\n";
    cout << "  Finalizacion del calculo normal.\n";
  }

  return 0;
}

int prime_number ( int n, int id, int p )

{
  int i;
  int j;
  int prime;
  int total;

  total = 0;

  for ( i = 2 + id; i <= n; i = i + p )
  {
    prime = 1;
    for ( j = 2; j < i; j++ )
    {
      if ( ( i % j ) == 0 )
      {
        prime = 0;
        break;
      }
    }
    total = total + prime;
  }
  return total;
}

void timestamp ( )

{
# define TIME_SIZE 40

  static char time_buffer[TIME_SIZE];
  const struct tm *tm;
  size_t len;
  time_t now;

  now = time ( NULL );
  tm = localtime ( &now );

  len = strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm );

  cout << time_buffer << "\n";

  return;
# undef TIME_SIZE
}

Lo compilamos con el comando:
erluco@master:~/clusterdir$ mpic++ primos.c++ -o primos
Esto nos dara como resultado el binario ejecutable del programa de prueba, podremos verificar que gracias a la comparticion NFS este binaro se encuentra disponible tambien en cada uno de los nodos que hemos agregado a nuestro cluster.
Ahora lo vamos a ejecutar y verificar su funcionamiento primero solo en el nodo maestro y luego en todos los nodos del cluster.
Primero en el nodo maestro unicamente:
erluco@master:~/clusterdir$ ./primos
Ahora distribuido en todos los nodos del cluster, para ello vamos a usar la herramienta mpirun con el parametro -np 5 con el que le decimos la cantidad de procesos a ejecutar.
erluco@master:~/clusterdir$ mpirun -np 5 --hostfile ../.mpi_hostfile ./primos
o
erluco@master:~/clusterdir$ mpirun -np 5./primos
y se obtendra este resultado :
Cuenta primos
 C++/MPI version

 Programa para contar cantidad de primos para un N dado.
 Corriendo en 3 procesos

 N        S          Tiempo

 1         0         0.33965
 2         1       0.0965161
 4         2       0.0619619
 8         4        0.125543
 16         6        0.179036
 32        11        0.122198
 64        18        0.152973
 128        31        0.117323
 256        54         0.17525
 512        97        0.182207
 1024       172        0.123595
 2048       309       0.0812861
 4096       564        0.162669
 8192      1028        0.207587
 16384      1900        0.494075
 32768      3512         1.62275
 65536      6542         3.71538
 131072     12251         1.0127

PRIME_MPI - Procesos maestro:
 Finalizacion del calculo normal.


8 comentarios:

  1. me gustaria tener 4 maquinas para ver cuanto tiempo tarda en realizar el proceso super muy bueno

    ResponderEliminar
  2. como saber si el custer esta trabajando ?

    ResponderEliminar
  3. Buenas, muy buen tutorial, si quisiera hacer este mismo procedimiento pero con dos nodos para el cluster, que parámetros se cambian?

    Por ejemplo en esta parte:


    primero en el nodo maestro unicamente:
    erluco@master:~/clusterdir$ ./primos
    Ahora distribuido en todos los nodos del cluster, para ello vamos a usar la herramienta mpirun con el parametro -np 5 con el que le decimos la cantidad de procesos a ejecutar.
    erluco@master:~/clusterdir$ mpirun -np 5 --hostfile ../.mpi_hostfile ./primos

    ResponderEliminar
  4. Hay alguien aqui?

    Hice todo lo que esta aqui, tengo una PC de escritorio como Master y una Laptop como nodo1 ... en el master corre bien los numeros primos y sale lo mismo que en el artìculo.

    Lo que me falla es cuando trato de hacer funcionar el nodo1

    El archivo primos esta en /home/nodo1/clust1/primos
    El archivo .mpi_hostfile esta en /home/nodo1

    al dar el siguiente comando $ mpirun -np 5 --hostfile ../.mpi_hostfile ./primos

    me sale lo siguiente:

    nodo1@Master:~/clust1$ mpirun -np 5 --hostfile ../.mpi_hostfile ./primos
    [mpiexec@] HYDU_process_mfile_token (utils/args/args.c:296): token slots not supported at this time
    [mpiexec@] HYDU_parse_hostfile (utils/args/args.c:343): unable to process token
    [mpiexec@] mfile_fn (ui/mpich/utils.c:336): error parsing hostfile
    [mpiexec@] match_arg (utils/args/args.c:152): match handler returned error
    [mpiexec@] HYDU_parse_array (utils/args/args.c:174): argument matching returned error
    [mpiexec@] parse_args (ui/mpich/utils.c:1596): error parsing input array
    [mpiexec@] HYD_uii_mpx_get_parameters (ui/mpich/utils.c:1648): unable to parse user arguments
    [mpiexec] main (ui/mpich/mpiexec.c:153): error parsing parameters

    ResponderEliminar
  5. PC-Esritorio Pentium G3240 Dual Core 3.1 Ghz
    Laptop AMD C70 - Dual core 1.0 Ghz

    ResponderEliminar
  6. Este comentario ha sido eliminado por el autor.

    ResponderEliminar

Cluster Beowulf + OpenMPI + NFS

Instalación y configuración Condiciones previas Antes de comenzar tenemos que tener por lo menos dos maquinas con Ubuntu ...