The Lost Papers - The CEREBELLUM Files (II)


============================================


THE CEREBELLUM FILES (II)


============================================

MPICH nace como una de esas variantes basadas en el estándar MPI en sistemas de computación distribuída. Por lo tanto, lo que hemos de tener claro es que se trata de una implementación del interfaz de paso de mensajes pero con ciertas peculiaridades. Otra de las bondades, entre tantas que le caracterizan, es que nos referimos a software libre y aparte disponible para otras plataformas. Algo que se ha de recalcar desde un principio es que el clúster ha de contar con un entorno de trabajo lo más homogéneo posible.

Dado que los apartados referidos a la configuración básica como son la gestión de usuarios, configuración de SSH o la instalación y configuración de NFS son puntos comunes me he tomado la libertad de copiar y pegar parte de la entrada anterior salvo pequeñas modificaciones de los equipos tomados como referencia que muestran la coexistencia de OpenMPI y MPICH en el mismo sistema. Otra de las razones es bastante obvia, el incluírlo todo en un manual. Lo cual creo conveniente debido a que la persona que monta su primer clúster lo que menos desea es andar cambiando de pestañas. Llamémosle un "all in one".

Comenzamos con la configuración:

1. Creación de usuarios.

De optar por la opción de hacerlo mediante intérprete de comandos debemos llevar a cabo ciertos pasos para crearlo.

[root@NEPTUNO ~]# useradd -d /home/beowulf -m -s /bin/bash beowulf

Lo que hacemos al pasar estas opciones al crear el usuario es indicar con '-d' que el directorio personal sea '/home/beowulf/', la opción '-m' indica la creación del mismo si no existe y con el parámetro '-s' indicamos que el shell o intérprete de comandos (como deseemos llamarle) sea bash. Al añadir el usuario beowulf también se crea el grupo primario con el mismo nombre; por lo tanto si necesitamos que otro sea el principal de trabajo utilizaremos la opción '-g' quedando de la siguente forma:

[root@NEPTUNO ~]# useradd -g cluster -d /home/beowulf -m -s /bin/bash beowulf

A continuación modificaremos la contraseña por defecto para el usuario que acabamos de crear:

[root@NEPTUNO ~]# passwd beowulf

En algunas ocasiones tras la creación del usuario al realizar login por primera vez podemos obtener algún tipo de mensaje de error debido a que los permisos del directorio personal no son los correctos. Una de las soluciones es cambiar de forma recursiva el usuario el cual es propietario de dicho directorio y el grupo al que pertenece. En este ejemplo cambiamos los permisos para el usuario beowulf y para el grupo primario con el mismo nombre.

[root@NEPTUNO ~]# chown -R beowulf:beowulf /home/beowulf/

Como nota aclaratoria decir que para tener una configuración homogénea se recomienda que tanto el usuario, el directorio personal, el UID y el directorio de trabajo compartido a través de NFS sean los mismos en todas las máquinas.

2. Asociando nombres de host a direcciones IP.

Una de esas antíguas costumbres que he tenido desde mis primeros pasos usando GNU/Linux a partir de aquel remoto año 2001 fué la de siempre asignar un nombre de host a una dirección IP tanto dentro como fuera de la red local cada vez que se realiza una instalación nueva, lo cual ayuda a hacer más rápido el acceso. Para ello editaremos el fichero /etc/hosts lo cual no merece una reseña especial con respecto a la configuración debido a su sencillez.

# ip-address hostname
127.0.0.1 localhost
::1 localhost

192.168.43.1 router
192.168.43.2 routerwifi
192.168.43.3 cronos
192.168.43.4 vulcano
192.168.43.5 orion
192.168.43.6 nemesis
192.168.43.7 apolo
192.168.43.8 neptuno
192.168.43.9 titan
192.168.43.10 hermes
192.168.43.21 azor-aprs
192.168.43.22 azor-digi
192.168.43.23 azor-sdr
192.168.0.132 zeus
192.168.0.131 galaxy

3. Configuración de la autenticación a tarvés de SSH.

He aquí uno de los puntos más importantes a tener en cuenta con la configuración de nuestro pequeño clúster. La creación e importación de una clave pública SSH (Secure Shell) cuya función será el acceso remoto del usuario que hemos creado en todas las máquinas, tanto el nodo maestro como el resto de nodos esclavos, sin necesidad de contraseña.

Para ello, como no, hemos de tener OpenSSH instalado y convenientemente configurado. Sobre todo si queremos correr remotamente aplicaciones gráficas a través de X11 Forwarding (ssh -XY). Eso ya será bajo el criterio acerca de las políticas de seguridad que deseemos implantar y el gusto de cada uno. Pero en otros tipos de clúster es necesario deactivar dicha opción debido a que no podrían arrancar los nodos, tanto maestro como esclavos, debido a la cantidad de errores que nos proporcionaría en la salida.

Para crear e importar la clave podemos realizar una conexión 'loopback' desde un terminal o acceder directamente a través de una consola virtual (TTY) haciendo login con los datos correspondientes.

En el ejemplo que sigue crearemos una clave pública de 2048 bit utilizando el algoritmo RSA. Un dato a tener en cuenta para que todo funcione correctamente es que cuando en el proceso se nos requiera de introducir una contraseña no indiquemos ninguna.

[beowulf@NEPTUNO ~]$ ssh-keygen -t rsa -b 2048

A continuación procedemos a copiar la claves generadas en todos los equipos entre el nodo maestro y los nodos esclavos.

[beowulf@NEPTUNO ~]$ scp .ssh/id_rsa.pub beowulf@titan:~

Continuamos importando la clave pública generada al fichero .ssh/authorized_keys.

[beowulf@TITAN ~]$ cat id_rsa.pub >> .ssh/authorized_keys

Una vez hecho esto en todos los nodos entre el maestro y los esclavos procedemos a conectarnos vía SSH entre ellos para comprobar que todo está funcionando correctamente. De no ser así y que necesitemos introducir la contraseña repetiremos la configuración importando las claves de dichos nodos afectados por la configuración errónea.

De mostrarnos algún tipo de mensaje de error con respecto a la ubicación del fichero de claves autorizadas editaremos el fichero de configuración del daemon SSH buscando las siguientes líneas y editándolo de la siguiente manera:

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile %h/.ssh/authorized_keys

4. Instalación y configuracion de NFS.

Dependiendo de la distribución GNU/Linux que utilicemos el nombre de los paquetes variará de manera significativa. En esta parte del manual se hará referencia explícita a la instalación a través de pacman en Arch Linux que es la distribución que llevo utilizando en los últimos años por ser la que más se ajusta a mis necesidades. Instalaremos los paquetes nfs-utils, nfsidmap y libnfs.

Primero antes de continuar con la instalación de NFS creamos el directorio que montaremos remotamente en los nodos esclavos y exportaremos a través del nodo maestro. En mi caso concreto el montaje se realiza en /home/beowulf/desarrollo/mpich2.

[beowulf@NEPTUNO ~]$ mkdir /home/beowulf/desarrollo/mpich2

Llegados a este punto el manual lo dividiremos en las configuraciones del lado cliente (nodos esclavos) y del servidor (nodo maestro).

. Configuración del lado servidor (Nodo maestro):

Buscamos los paquetes relacionados con NFS a través de pacman en los repositorios de Arch Linux:

[beowulf@NEPTUNO ~]$ pacman -Ss nfs
core/mkinitcpio-nfs-utils 0.3-5
ipconfig and nfsmount tools for NFS root support in mkinitcpio
core/nfs-utils 2.1.1-4 [instalado]
Support programs for Network File Systems
core/nfsidmap 0.26-1 [instalado]
Library to help mapping IDs, mainly for NFSv4
extra/gvfs-nfs 1.32.1+5+gf0d758df-1 (gnome)
Virtual filesystem implementation for GIO (NFS backend)
community/liblockfile 1.09_6-1
a library with NFS-safe locking functions
community/libnfs 2.0.0-1 [instalado]
client library for accessing NFS shares
community/perl-file-nfslock 1.27-2
NFS compatible (safe) locking utility
community/unionfs-fuse 2.0-1
A user space unionfs implementation

Una vez localizados tras la búsqueda los instalamos de la siguiente manera:

[root@NEPTUNO beowulf]# pacman -S nfs-utils nfidmap libnfs

Una vez instalados procedemos a configurar el directorio exportado a través de NFS en el nodo maestro para que pueda ser montado remotamente en los nodos esclavos. Editamos el fichero /etc/exports y añadimos la siguiente línea al final del mismo. Las direcciones IP de la red local (LAN) la cambiaremos según los rangos que utilicemos.

/home/beowulf/desarrollo/mpich2 192.168.43.0/24 (rw,no_subtree_check,async,no_root_squash)

A continuación habilitaremos los servicios y los arrancaremos a traves de systemd:

[root@NEPTUNO beowulf]# systemctl enable rpcbind nfs-server && systemctl start rpcbind nfs-server

. Configuración del lado cliente (Nodos esclavos).

Comenzamos la configuración de los nodos esclavos con la instalación de los paquetes necesarios para utilizar NFS de la misma manera que hicimos en el servidor. Salvo por pequeños matices que diferencian el proceso de configuración.

Realizamos la búsqueda en los repositorios de Arch Linux:

[beowulf@TITAN ~]$ pacman -Ss nfs
core/mkinitcpio-nfs-utils 0.3-5
ipconfig and nfsmount tools for NFS root support in mkinitcpio
core/nfs-utils 2.1.1-4 [instalado]
Support programs for Network File Systems
core/nfsidmap 0.26-1 [instalado]
Library to help mapping IDs, mainly for NFSv4
extra/gvfs-nfs 1.32.1+5+gf0d758df-1 (gnome)
Virtual filesystem implementation for GIO (NFS backend)
community/liblockfile 1.09_6-1
a library with NFS-safe locking functions
community/libnfs 2.0.0-1 [instalado]
client library for accessing NFS shares
community/perl-file-nfslock 1.27-2
NFS compatible (safe) locking utility
community/unionfs-fuse 2.0-1
A user space unionfs implementation

E instalamos el conjunto de paquetes:

[root@TITAN beowulf]# pacman -S nfs-utils nfidmap libnfs

Una vez realizado el proceso de instalación crearemos el directorio el punto de montaje a través del cual tendremos acceso al directorio exportado remotamamente a través de NFS perteneciente al nodo maestro. Recordemos que ha de ser el mismo en todos los nodos.

[beowulf@TITAN ~]$ mkdir /home/beowulf/desarrollo/mpich2

A continuación nos centraremos en la edición del fichero /etc/fstab al cual añadiremos la siguiente línea al final del mismo. Será la encargada de montar el directorio remoto en el punto que hemos creado en el paso anterior.

# NFS NEPTUNO MPICH
NEPTUNO:/home/beowulf/desarrollo/mpich2 /home/beowulf/desarrollo/mpich2 nfs4 size=8192,wsize=8192,timeo=14,intr,_netdev 0 0

Una vez guardados los cambios procedemos a montar el directorio:

[beowulf@TITAN ~]$ su
Contraseña:
[root@TITAN beowulf]# mount /home/beowulf/desarrollo/mpich2

Os habréis preguntado el porqué no he utilizado sudo y en cambio he usado la orden su para obtener privilegios de root. La respuesta es bastante sencilla, está ligada a la política de seguridad que le demos a nuestros sistemas. Por lo tanto no deseo que el usuario beowulf pueda escalar privilegios menos que sea mediante esta vía.

Para comprobar que el directorio del nodo maestro se está exportando correctamente podemos ejecutar desde cualquiera de los esclavos la siguiente orden. Deberíamos recibir una salida parecida a esta en el terminal.

[beowulf@TITAN ~]$ showmount -e neptuno
Export list for neptuno:
/home/txus/desarrollo/pvm3 192.168.43.0/24
/home/txus/desarrollo/mpich2 192.168.43.0/24
/home/txus/desarrollo/openmpi 192.168.43.0/24
/home/beowulf/desarrollo/pvm3 192.168.43.0/24
/home/beowulf/desarrollo/mpich2 192.168.43.0/24
/home/beowulf/desarrollo/openmpi 192.168.43.0/24

5. Instalación y configuración de MPICH2.

En mi caso concreto la distribución utilizada será Arch Linux aunque a la hora de la verdad la configuración general no difiere de unas a otras salvo en la estructura de directorios y el uso del gestor de paquetes.

Debido a que la instalación de MPICH2 la llevaremos a cabo a través de AUR utilizaremos yaourt:

[beowulf@NEPTUNO ~]$ yaourt -Ss mpich
aur/fftw-mpich 3.3.6-1 (2) (0,00)
A library for computing the discrete Fourier transform (DFT)
aur/hdf5-fortran-mpich 1.8.16-2 (Out of Date) (2) (0,00)
General purpose library and file format for storing scientific data
aur/mpich 3.2-1 (76) (0,00)
An improved implementation of the Message Passing Interface.
aur/mpich2 1.5-2 [installed] (3) (0,00)
An improved implementation of the Message Passing Interface (legacy
version).

Comenzamos el proceso de instalación:

[beowulf@NEPTUNO ~]$ yaourt -S mpich2
yaourt -S mpich2

Una vez terminado el proceso configuraremos el nodo maestro y los nodos esclavos:

. Fichero ~/.mpd.conf.

MPICH2 en la más básica de sus configuraciones solamente precisa dos cosas. La inclusión de una pequeña contraseña común en todos los nodos que facilite o descarte la comunicación entre ellos, por lo tanto es preciso crear el mismo en cada una de las máquinas de nuestro clúster. La ruta en la cual estará ubicado para que MPD tenga acceso a él será el directorio del usuario que hemos creado ( ~/.mpd.conf o /home/beowulf/.mpd.conf ) e incluiremos esta linea:

secretword=beowulf

A continuación cambiaremos los permisos de tal manera que solamente nuestro usuario pueda tener acceso de lectura y escritura. De todas formas la misma aplicación nos advierte de hacerlo:

[beowulf@NEPTUNO]$ chmod 600 ~/.mpd.conf

. Fichero mpd.hosts.

Este es el segundo fichero de la configuración y ejecución de las aplicaciones. Si recordamos la entrada anterior y la reseña acerca .mpi_hostfile nos encontraremos con unas pequeñas similitudes en la estructura del mismo:

[beowulf@NEPTUNO ~]$ more .mpi_hostfile
# Maestro

localhost slots=2

# Esclavos

#cronos slots=1
hermes slots=2
titan slots=2
#zeus slots=1

En su esencia trabajan de la misma manera. Deberemos indicar los host que componen el clúster y cuantos slots deseamos asignarle. Por lo tanto lo editaremos de esta manera:

[beowulf@NEPTUNO ~]$ more mpd.hosts
# Nodo maestro

NEPTUNO:2

# Nodo(s) Esclavo(s)

#CRONOS:1
HERMES slots:2
TITAN slots:2
#ZEUS:1

div align="justify">Una consideración adicional tras editar este fichero es crear un enlace simbólico que apunte hacia el directorio que estamos compartiendo a través de NFS en el nodo maestro. Es mucho más cómodo para trabajar con la aplicación, bajo mi criterio; quizá para otros usuarios puede que no sea así.

[beowulf@NEPTUNO ~]$ ln -s /home/beowulf/mpd.hosts /home/beowulf/desarrollo/mpich2/mpd.hosts

Llegados a este punto podemos considerar la configuración de los nodos terminada salvo un pequeño detalle pero ya decidirá cada uno de llevarlo a cabo o no. Se trata de las variables de entorno. Si vamos a trabajar con OpenMPI por un lado y por otro con MPICH2 sería un caos. Por contra si solamente vamos a utilizar MPICH2 se establecen en el fichero ~/.bashrc o en /etc/environment y no deberíamos hacer mucho más. Con la configuración de trabajo establecida en mis máquinas no lo veo viable.

De no establecer dichas variables de entorno deberemos incluir la ruta completa cada vez que invoquemos las aplicaciones que la integran. En el caso de Arch Linux la ruta por defecto al instalar el paquete es /opt/mpich2/.

. Primeros pasos con MPICH2.

Recuerdo con satisfacción aquella primera instalación funcional que hice de este conjunto de herramientas. La satisfacción por un lado de investigar y hallar la razón por la cual no funcionaba correctamente, pero así mismo recuerdo con un poco de decepción como los manuales que seguí solamente se trataban de un copiar y pegar. Que si hemos de levantar el servicio mpd antes de hacer nada; totalmente falso. Que si ejecutamos la aplicación generada de tal manera; falso también. Vamos a ponernos manos a la obra sin extendernos demasiado.

El primer paso con el que comprobaremos que la configuración está llevada a cabo de la manera correcta es levantar los nodos. Este es el momento en el cual lo veremos claramente por lo tanto ejecutaremos la siguiente orden tras comprobar que está montado en los nodos esclavos el directorio compartido desde el nodo maestro. Para este ejemplo utilizaré dos esclavos; HERMES y TITAN. El nodo maestro es NEPTUNO

Por parte del nodo TITAN recibimos esta respuesta:

[beowulf@TITAN ~]$ df -Th

...

NEPTUNO:/home/beowulf/desarrollo/mpich2 nfs4 74G 57G 14G 82% /home/beowulf/desarrollo/mpich2

...

Del nodo esclavo HERMES recibimos la misma:

[beowulf@HERMES ~]$ df -Th

...

NEPTUNO:/home/beowulf/desarrollo/mpich2 nfs4 74G 57G 14G 82% /home/beowulf/desarrollo/mpich2

...

Tras hacer esta pequeña comprobación ya que a veces dependiendo del orden asignado por defecto de los servicios a través de systemd las entradas incluídas en el fichero /etc/fstab no se montan correctamente procedemos a levantar todos los nodos del clúster desde NEPTUNO. Le pasaremos la orden a mpd

para que levante los tres:


[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdboot -n 3
[beowulf@NEPTUNO mpich2]$

Lo que vamos a hacer a continuación es la comprobación mediante mpdtrace de que los hemos levantado correctamente sin ningún tipo de error:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdtrace
NEPTUNO
HERMES
TITAN

Ahora compilaremos un programa de muestra del cual no incluiré el código fuente sino un enlace para realizar la descarga o copiar el contenido en un nuevo fichero que crearemos en /home/beowulf/desarrollo/mpich2/. La razón por la cual llevo a cabo estos cambios es debida a que no se muestra parte del contenido del mismo una vez editado el manual. El fichero pi.c se puede descargar desde este enlace ( http://www.qsl.net/eb1agg/data/ejemplosmpi/pi.c ) y procedemos a compilarlo de la misma forma que en la entrada anterior con OpenMPI

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpicc -o pi pi.c

Observamos un pequeño número de advertencias pero sin importancia alguna. Vamos a correr la aplicación en el clúster con mpirun de dos maneras diferentes. La primera es por la que en aquellos tiempos determiné que la mayoría de manuales son de copiar y pegar, la segunda es el procedimiento que utilizo heredado de mi paso por el OpenMPI puro y duro:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpirun -np 6 ./pi
Enter the number of intervals: (0 quits)

Figura 1 - Procedimiento incorrecto.

A continuación se muestra el procedimiento que a mí me funciona:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpirun -np 6 --hostfile mpd.hosts ./pi
Enter the number of intervals: (0 quits)

Figura 2 - Procedimiento correcto.

Ahora tomaremos de nuevo como ejemplo de prueba la aplicación primos.c++ del manual anterior descargándola de este enlace ( http://www.qsl.net/eb1agg/data/ejemplosmpi/primos.c++ ) y la compilamos de la siguiente forma:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpic++ -o primos primos.c++

A continuación la ejecutamos mediante el procedimiento incorrecto. Tomando como referencia el tiempo de ejecución y la captura adjunta nos daremos cuenta de la gran diferencia:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpirun -np 6 ./primos

'Cuenta primos
C++/MPI version

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

N S Tiempo

1 0 0.0397201
2 1 0.0331821
4 2 0.0232742
8 4 0.0331943
16 6 0.056515
32 11 0.0322185
64 18 0.0423689
128 31 0.0286515
256 54 0.03088
512 97 0.0380378
1024 172 0.0378928
2048 309 0.0641522
4096 564 0.117069
8192 1028 0.327593
16384 1900 1.32094
32768 3512 4.82807
65536 6542 18.6226
131072 12251 68.8832

PRIME_MPI - Procesos maestro:
Finalizacion del calculo normal.

Figura 3 - Procedimiento incorrecto.

Ejecutando la aplicación correctamente:

[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpirun -np 6 --hostfile mpd.hosts ./primos

'Cuenta primos
C++/MPI version

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

N S Tiempo

1 0 0.0352921
2 1 0.00929046
4 2 0.00887918
8 4 0.0093565
16 6 0.00868082
32 11 0.00700736
64 18 0.00834799
128 31 0.00922775
256 54 0.00780368
512 97 0.00910139
1024 172 0.00908566
2048 309 0.0140226
4096 564 0.035609
8192 1028 0.132541
16384 1900 0.425127
32768 3512 1.66736
65536 6542 7.71463
131072 12251 24.1364

PRIME_MPI - Procesos maestro:
Finalizacion del calculo normal.

Figura 4 - Procedimiento correcto.

Para ir finalizando el único procedimiento básico que queda por comentar es desactivar los nodos. Para mostrar como sería el ciclo de activación, traceado de máquinas disponibles, ejecución de aplicaciones MPI, desactivación y nuevamente traceado. Para desactivarlos utilizaremos la orden mpdallexit:

[beowulf@NEPTUNO ~]$ ps -A |grep mpd
[beowulf@NEPTUNO ~]$ cd desarrollo/mpich2/
[beowulf@NEPTUNO mpich2]$ pwd
/home/beowulf/desarrollo/mpich2
[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdboot -n 3
[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdtrace
NEPTUNO
HERMES
TITAN
[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpirun -np 6 --hostfile mpd.hosts ./primos

'Cuenta primos
C++/MPI version

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

N S Tiempo

1 0 0.0340471
2 1 0.00597119
4 2 0.0128822
8 4 0.00814557
16 6 0.0108578
32 11 0.00724435
64 18 0.00850201
128 31 0.0105915
256 54 0.0125058
512 97 0.0108943
1024 172 0.0192242
2048 309 0.0160007
4096 564 0.0501051
8192 1028 0.153452
16384 1900 0.531934
32768 3512 1.94967
65536 6542 7.40568
131072 12251 28.0296

PRIME_MPI - Procesos maestro:
Finalizacion del calculo normal.
[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdallexit
[beowulf@NEPTUNO mpich2]$ /opt/mpich2/bin/mpdtrace
mpdtrace: cannot connect to local mpd (/tmp/mpd2.console_beowulf); possible causes:
1. no mpd is running on this host
2. an mpd is running but was started without a "console" (-n option)
In case 1, you can start an mpd on this host with:
mpd &
and you will be able to run jobs just on this host.
For more details on starting mpds on a set of hosts, see
the MPICH2 Installation Guide.
[beowulf@NEPTUNO mpich2]$

Espero que el manual sirva de ayuda sobre todo a esas personas que se han quedado estancadas en el punto referente a la ejecución de las aplicaciones compiladas y por lo tanto a la indicación del uso por parte de mpirun del fichero mpd.hosts. Quizá retomen de nuevo ese proyecto que abandonaron en su momento. Desconozco si en su versión 3 el uso es más transparente que en MPICH2.

That's all folks!