Back To Basis : Torque & MAUI

Rapide tip pour sauver ce qui me reste de mémoire avec la mise en place et l'exploitation d'un cluster de calcul via Torque et MAUI.

Fonctionnement

Un cluster de calcul est composé de noeuds de calcul, plus ou moins riches en ressources, et à plus ou moins charger. Typiquement, ici, j'ai un cluster composé de 2 ensembles :
  • les noeuds de calcul 24/24 7/7
  • les noeuds de calcul cumulant 2 rôles et qui sont principalement des postes de travail
Pour info, je ne détaille pas l'installation ni du cluster en lui-même (réplication d'un noeud sur tous les autres, voir le tip sur SystemImager) ni celle des installations de Torque ni MAUI, qui sont triviales. Je n'attaquerais que la partie configuration. Le fonctionnement d'un cluster de calcul sous Torque / MAUI est le suivant. Les utilisateurs soumettent des travaux (on appellera ça des batchs) au master. Ce master a pour tâche d'enregistrer ces travaux dans une queue et de les soumettre à n noeuds en fonctions des ressources disponibles et demandées par le travail en question. Pour cela, il existe sur chacun des noeuds de calcul un daemon, pbs_mom, qui est chargé de la communication entre le master et le noeud. Pourquoi pbs_mom ? Et bien parce qu'avant de s'appeler Torque, l'outil portait le doux nom de PBS. Le master quant à lui fait tourner principalement 2 daemons : MAUI, l'ordonnanceur, et pbs_server, qui est notre serveur TORQUE. De plus, il gère toute une collection (enfin ça dépend de vous) de queue avec -de préférence- des priorités et des contraintes différentes.

Ces contraintes sont notamment liées au temps d'exécution qui est borné, et selon votre bon plaisir, le mien en tout cas, à un maximum de soumission et de jobs en cours d'exécution.

Comment faire ? Il suffit de continuer à lire :)

Configuration

Maui

En réalité, MAUI n'a pas besoin, sauf cas particulier -du genre allouer telle ressources entre telle heure et telle heure à tel utilisateur- de configuration spécifique. Tout ce qu'il y a à savoir se trouve sous /var/spool/maui/maui.cfg, je vous ai même rajouté ce cas particulier dont je vous parlais :
$ cat /var/spool/maui/maui.cfg | grep -v "#"

SERVERHOST            master
ADMIN1                root

RMCFG[base] TYPE=PBS
AMCFG[bank]  TYPE=NONE

RMPOLLINTERVAL        00:00:30
SERVERPORT            50001
SERVERMODE            NORMAL

LOGDIR                /var/log/maui
LOGFILE               maui.log
LOGFILEMAXSIZE        1000000000
LOGLEVEL              3

QUEUETIMEWEIGHT       1

BACKFILLPOLICY        FIRSTFIT
RESERVATIONPOLICY     CURRENTHIGHEST
NODEALLOCATIONPOLICY  LASTAVAILABLE

SRCFG[prioritaire]          PERIOD=DAY
SRCFG[prioritaire]          STARTTIME=3:00:00
SRCFG[prioritaire]          ENDTIME=11:45:00
SRCFG[prioritaire]          HOSTLIST=ktux-w1,ktux-w2
SRCFG[prioritaire]          USERLIST=kuser

Torque

Par défaut, l'installation de Torque / PBS vous a crée un petit fichier de conf, destiné à paramétrer notamment le démarrage des services. Il nous indique également où est le home de Torque, c'est-à-dire où il range ses petites affaires. Ici, c'est sous /var/spool/pbs.
$ cat /etc/pbs.conf
#!/bin/sh
# init of some var needed bi pbs service
# config: /etc/pbs.conf

pbs_home=/var/spool/pbs
pbs_exec=/usr
# set 1 to start the service
start_server=1
start_sched=0
start_mom=0

/var/spool/pbs

Ce répertoire contient notamment les logs, mais aussi les données relatives aux queues et aux jobs
$ ll /var/spool/pbs/
total 112
drwxr-xr-x  2 root root  4096 2011-06-06 02:40 aux/
drwx------  2 root root  4096 2011-06-06 02:40 checkpoint/
drwxr-xr-x  2 root root  4096 2011-06-06 00:00 mom_logs/
drwxr-xr-x  3 root root  4096 2011-06-06 09:20 mom_priv/
-rw-r--r--  1 root root 56261 2011-06-06 12:46 nodes
-rwxr-xr-x  1 root root  2317 2011-06-06 02:41 pbs_config.sample*
-rw-r--r--  1 root root    26 2011-06-06 02:40 pbs_environment
drwxr-xr-x  2 root root  4096 2011-06-06 09:40 sched_logs/
drwxr-xr-x  3 root root  4096 2011-06-06 10:33 sched_priv/
drwxr-xr-x  2 root root  4096 2011-06-06 00:00 server_logs/
-rwxr-xr-x  1 root root    13 2011-06-06 16:39 server_name*
drwxr-xr-x 12 root root  4096 2011-06-06 15:10 server_priv/
drwxrwxrwt  2 root pbs   4096 2011-06-06 12:30 spool/
drwxrwxrwt  2 root pbs   4096 2011-06-06 02:40 undelivered/
Principalement, ce qui nous intéressera sera situé sous server_priv :
$ ll /var/spool/pbs/server_priv/
total 328
drwxr-xr-x 2 root root  12288 2011-06-06 05:00 accounting/
drwxr-xr-x 2 root root   4096 2011-06-06 02:40 acl_groups/
drwxr-xr-x 2 root root   4096 2011-06-06 02:40 acl_hosts/
drwxr-xr-x 2 root root   4096 2011-06-06 10:40 acl_svr/
drwxr-xr-x 2 root root   4096 2011-06-06 10:23 acl_users/
drwxr-xr-x 2 root root   4096 2011-06-06 02:40 arrays/
drwxr-xr-x 2 root root   4096 2011-06-06 02:40 disallowed_types/
drwxr-xr-x 2 root root   4096 2011-06-06 02:40 hostlist/
drwxr-xr-x 2 root root 274432 2011-06-06 10:52 jobs/
-rw-r--r-- 1 root root   1058 2011-06-06 15:10 nodes
drwxr-xr-x 2 root root   4096 2011-06-06 06:55 queues/
-rw------- 1 root root   1351 2011-06-06 10:52 serverdb
-rw------- 1 root root      5 2011-06-06 09:41 server.lock
-rw------- 1 root root      0 2011-06-06 16:47 tracking
$ ll /var/spool/pbs/server_priv/queues/
total 36
-rw------- 1 root root 1319 2011-06-06 13:58 longday
-rw------- 1 root root 1321 2011-06-06 06:55 longnight
-rw------- 1 root root 1320 2011-06-06 13:58 shortday
-rw------- 1 root root 1321 2011-06-06 06:55 shortnight

$ file /var/spool/pbs/server_priv/queues/shortday
/var/spool/pbs/server_priv/queues/shortday: data
Et sous server_logs :
$ ll /var/spool/pbs/server_logs/ | head
-rw-r--r-- 1 root root 315447768 2011-06-06 00:00 20110606
Tout ça pour dire que c'est facile de retrouver une information.

Queues

Je vous parlais plus haut de queue. Une queue est exactement ce à quoi son nom fait penser : c'est une file type FIFO qui contient les travaux en attente. L'utilitaire par définition qui va s'occuper de créer et moduler nos queues comme bon nous semble répond au doux nom de qmgr. Ce qui est bien avec lui, c'est qu'il permet, juste en lançant une petite requête, de nous dumper l'essentiel des commandes nécessaires à créer et paramétrer les queues que nous nous sommes donné tant de mal à créer. Ca me permet de faire 2 manips en une : une, vous montrer comment interroger Torque, et deux, vous montrer comment créer une queue :)
$ qmgr -c "print queue @master"
#
# Create queues and set their attributes.
#
#
# Create and define queue longday
#
create queue longday
set queue longday queue_type = Execution
set queue longday Priority = 4
set queue longday max_user_queuable = 30
set queue longday from_route_only = False
set queue longday resources_default.neednodes = day
set queue longday resources_default.nodect = 1
set queue longday resources_default.nodes = 1:day
set queue longday resources_default.walltime = 100:00:00
set queue longday max_user_run = 6
set queue longday enabled = True
set queue longday started = True
#
# Create and define queue shortday
#
create queue shortday
set queue shortday queue_type = Execution
set queue shortday Priority = 2
set queue shortday max_user_queuable = 200
set queue shortday from_route_only = False
set queue shortday resources_max.walltime = 03:00:00
set queue shortday resources_default.neednodes = day
set queue shortday resources_default.nodect = 1
set queue shortday resources_default.nodes = 1:day
set queue shortday resources_default.walltime = 03:00:00
set queue shortday max_user_run = 12
set queue shortday enabled = True
set queue shortday started = True

#
# Create and define queue shortnight
#
create queue shortnight
set queue shortnight queue_type = Execution
set queue shortnight Priority = 2
set queue shortnight max_user_queuable = 400
set queue shortnight from_route_only = False
set queue shortnight resources_max.walltime = 04:00:00
set queue shortnight resources_default.neednodes = night
set queue shortnight resources_default.nodect = 1
set queue shortnight resources_default.nodes = 1:night
set queue shortnight resources_default.walltime = 04:00:00
set queue shortnight max_user_run = 70
set queue shortnight enabled = True
set queue shortnight started = False

#
# Create and define queue longnight
#
create queue longnight
set queue longnight queue_type = Execution
set queue longnight Priority = 4
set queue longnight max_user_queuable = 180
set queue longnight from_route_only = False
set queue longnight resources_default.neednodes = night
set queue longnight resources_default.nodect = 1
set queue longnight resources_default.nodes = 1:night
set queue longnight resources_default.walltime = 100:00:00
set queue longnight max_user_run = 30
set queue longnight enabled = True
set queue longnight started = False
Comme vous pouvez le voir, les priorités entre queues sont tranchées au couteau : les queues de priorité moindre seront plus prioritaire que celles ayant une valeur plus grandes. Pour modifier un de ces paramètres, il suffit de les modifier avec par exemple un :
$ qmgr -c "set queue longnight max_user_run = 20"

Noeuds de calcul

Pour rajouter des noeuds de calcul, il faut être un peu plus sournois : il faut jouer avec les propriétés du noeud. Même principe, je print, mais pour le créer, soit on passe par un qmgr -c, soit qmgr tout court, qui nous renvoie un prompt :
$ qmgr -c "print node ktux-1"

#
# Create and define node ktux-1
#
create node ktux-1
set node ktux-1 np = 2
set node ktux-1 properties = night
set node ktux-1 ntype = cluster
Ici, je dis que mon noeud ktux-1 a 2 CPUs, de type cluster et doit faire jouer uniquement les travaux en mode night. Pour un noeud de calcul 24/24, 7/7, ça donnera plus du genre : Via qmgr -c :
$ qmgr -c 'create node ktux-w1 np=4,ntype=cluster'
$ qmgr -c 'set node ktux-w1 properties=day'
Ce qui nous donne :
$ qmgr -c "print node ktux-w1"
#
# Create nodes and set their properties.
#
#
# Create and define node ktux-w1
#
create node ktux-w1
set node ktux-w1 state = free
set node ktux-w1 np = 4
set node ktux-w1 properties = day
set node ktux-w1 ntype = cluster
Au fur et à mesure que les noeuds communiqueront avec le master, tout un tas d'autres infos vont être remontées, comme l'état actuel, les jobs en cours sur ce noeud, ...
$ qmgr -c "print node ktux-w1"
#
# Create nodes and set their properties.
#
#
# Create and define node ktux-w1
#
create node ktux-w1
set node ktux-w1 state = busy
set node ktux-w1 np = 4
set node ktux-w1 properties = day
set node ktux-w1 ntype = cluster
set node ktux-w1 status = opsys=linux
set node ktux-w1 status += uname=Linux ktux-w1 2.6.31.14-server-1mnb
set node ktux-w1 status += sessions=23566 23591 23629 23680
set node ktux-w1 status += nsessions=4
set node ktux-w1status += nusers=1
set node ktux-w1 status += idletime=8968185
set node ktux-w1 status += totmem=9009420kb
set node ktux-w1 status += availmem=8458932kb
set node ktux-w1 status += physmem=8143220kb
set node ktux-w1 status += ncpus=4
set node ktux-w1 status += loadave=1.36
set node ktux-w1 status += netload=2067207052
set node ktux-w1 status += state=free
set node ktux-w1 status += jobs=65605 65606 65607 65608
set node ktux-w1 status += varattr=
set node ktux-w1 status += rectime=1307353529
En réalité, le lien entre properties et queue est fait via l'instruction resources_default.neednodes :
set queue longnight resources_default.neednodes = night
et qmgr mentionne explicitement, pour chaque noeud, à quelle queue il se rattache. Le tout est sous /var/spool/pbs/server_priv/nodes :
$ cat /var/spool/pbs/server_priv/nodes

ktux-1 np=2 night
ktux-2 np=2 night
ktux-3 np=2 night
ktux-w1 np=4 day
ktux-w2 np=4 day
Sans ces instructions, on aurait une erreur du genre :
$ qmgr -c "print node ktux-2"
qmgr obj=ktux-2 svr=default: Unknown node  MSG=cannot located specified node

Évidemment, toute modification doit être ponctuée par un restart de pbs_server pour être effective.

Job

Toute soumission de travail passe par un qsub et doit mentionner le job à faire, la queue sur laquelle on désire travailler et optionnellement si l'on souhaite être averti en allocation des ressources, run et fin du travail. En retour, on obtient un identifiant de travail.
$ qsub -q shortday -o /home/kuser/date.res -e /home/kuser/date.err -m  abe -N  date -M ktux@ktux.com  /home/kuser/date.sh
Ici, -q attend une queue spécifique, -o précède l'emplacement de l'output désiré, -e celui de l'erreur renvoyée si il y a, -m abe désigne l'instruction de mailing en cas de a(borted) b(egin) e(nd). -N donne un nom au travail, -M précise le mail en question et en dernier, le script à exécuter. A noter qu'ici, le /home de kuser est un partage NFS, qui fonctionnera quelque soit le noeud de calcul choisi. Autrement, il aurait fallu désigner un espace accessible avec les droits de kuser par le noeud de calcul en question. Sur le master, on peut alors suivre le job et son évolution :
$ qstat -u kuser

master :
Req'd  Req'd   Elap
Job ID               Username Queue    Jobname          SessID NDS   TSK Memory Time  S Time
-------------------- -------- -------- ---------------- ------ ----- --- ------ ----- - -----
656969            kuser           shortday date                --      1  --    --  00:45 Q   --
Q : le job est enqueue. R : running. Sur le client aussi, et ce en étant loggé en tant que kuser :
$ qstat
Job id                    Name             User            Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
656969              date                 kuser              0 Q shortday
Un affichage plus complet passe par un qstat -f, d'où on extrait facilement l'exec host, c'est à dire l'hôte qui a pris en charge le calcul dès que celui-ci passe en mode Running. Cet exec host peut être composé de plusieurs noeuds de calcul, en fonction des ressources nécessaires au run du travail. Lorsque l'on souhaite investiguer sur un batch qui ne s'est pas passé comme on l'attendait, deux options s'offrent à nous pour mettre le doigt sur les noeuds ayant participé à sa résolution :
  • une analyse classique de log
  • tracejob
L'analyse classique de log va vous amener à grepper votre jobID sur les logs de /var/spool/pbs/server_logs/ et à remonter jusqu'à l'attribution d'un noeud au batch. C'est sympa, mais manuellement, et sur beaucoup de batch, ça devient un peu long. Tracejob permet de parser justement un ensemble de logs et de vous retourner automatiquement tout ce qui a, de près ou de loin, participé à votre batch. La petite faiblesse étant que, par défaut, il ne prend que les logs du jour même. Tracejob est à lancer sur le master, qui sait et qui voit tout. En gros, pour aujourd'hui le lundi 06 Juin, il va chercher : /var/spool/pbs/server_priv/accounting/20110606 /var/spool/pbs/server_logs/20110606 /var/spool/pbs/mom_logs/20110606 /var/spool/pbs/sched_logs/20110606 Ca nous donne ça :
$ tracejob 656969
/var/spool/pbs/mom_logs/20110606: No matching job records located
/var/spool/pbs/sched_logs/20110606: No such file or directory

Job: 656969

06/06/2011 12:29:22  S    ready to commit job
06/06/2011 12:29:22  S    ready to commit job completed
06/06/2011 12:29:22  S    committing job
06/06/2011 12:29:22  S    enqueuing into veryshortjour, state 1 hop 1
06/06/2011 12:29:22  S    Job Queued at request of kuser@ktux-1, owner = kuser@ktux-1, job name = date, queue = shortday
06/06/2011 12:29:22  A    queue=shortday
06/06/2011 12:35:25  S    attr Resource_List modified
06/06/2011 12:35:25  S    Job Modified at request of root@master

06/06/2011 12:35:25  S    Job Run at request of root@master
06/06/2011 12:35:25  S    forking in send_job                                                                                                      06/06/2011 12:35:25  S    send_job child job pid is 30568
06/06/2011 12:35:25  S    entering post_sendmom
06/06/2011 12:35:25  S    child reported success for job after 0 seconds (dest=ktux-w1), rc=0
06/06/2011 12:35:25  S    attr Resource_List modified
06/06/2011 12:35:25  S    Job Modified at request of root@master
06/06/2011 12:35:25  S    attr session_id modified
06/06/2011 12:35:25  S    sending 'b' mail for job 656969 to kuser@ktux-1 (---)
06/06/2011 12:35:25  A    user=kuser group=kuser jobname=date queue=shortday ctime=1307356162 qtime=1307356162 etime=1307356162 start=1307356525
owner=kuser@ktux-1 exec_host=ktux-w1/0 Resource_List.neednodes=ktux-w1 Resource_List.nodect=1 Resource_List.nodes=1:day
Resource_List.walltime=00:45:00
06/06/2011 12:35:29  S    obit received
06/06/2011 12:35:29  S    obit received - updating final job usage info
06/06/2011 12:35:29  S    attr resources_used modified
06/06/2011 12:35:29  S    job exit status 0 handled
06/06/2011 12:35:29  S    sending 'e' mail for job 656969 to kuser@ktux-1 (Exit_status=0
06/06/2011 12:35:29  S    Exit_status=0 resources_used.cput=00:00:00 resources_used.mem=0kb resources_used.vmem=0kb resources_used.walltime=00:00:04
06/06/2011 12:35:29  S    on_job_exit task assigned to job
06/06/2011 12:35:29  S    req_jobobit completed
06/06/2011 12:35:29  S    JOB_SUBSTATE_EXITING
06/06/2011 12:35:29  S    JOB_SUBSTATE_STAGEOUT
06/06/2011 12:35:29  S    about to copy stdout/stderr/stageout files
06/06/2011 12:35:29  S    JOB_SUBSTATE_STAGEOUT
06/06/2011 12:35:29  S    JOB_SUBSTATE_STAGEDEL
06/06/2011 12:35:29  S    JOB_SUBSTATE_EXITED
06/06/2011 12:35:29  S    JOB_SUBSTATE_COMPLETE
06/06/2011 12:35:29  S    dequeuing from shortday, state COMPLETE
06/06/2011 12:35:29  S    removed job script
06/06/2011 12:35:29  S    removed job file
06/06/2011 12:35:29  S    freeing job
06/06/2011 12:35:29  A    user=kuser group=kuser jobname=date queue=shortday ctime=1307356162 qtime=1307356162 etime=1307356162 start=1307356525
owner=kuser@ktux-1 exec_host=ktux-w1/0 Resource_List.neednodes=1:day Resource_List.nodect=1 Resource_List.nodes=1:day
Resource_List.walltime=00:45:00 session=24524 end=1307356529 Exit_status=0 resources_used.cput=00:00:00 resources_used.mem=0kb
resources_used.vmem=0kb resources_used.walltime=00:00:04

Manipulations de jobs

Bien entendu, on peut manipuler comme bon nous semble les batches ! Pour cela, nous avons tout un éventail de commandes en q.
  • qdel : suppression du jobID
  • qrun : forçage du run du batch, avec options possibles, comme de le faire tourner sur tel et tel noeuds,...
  • qalter : modifier les attributs du job : queue, mailing, ...
  • qhold : mettre en suspens un job
  • qenable/qdisable : activer/désactiver la destination, typiquement une queue particulière
  • qstart/qstop : démarrer/arrêter les queues dans le sens où on peut soumettre, mais les jobs enqueued ne sont pas distribués
  • ...

Conclusion

En fait, monter un cluster de calcul est beaucoup plus contraignant au moment de la conception matérielle (installation, câblage, mise dans un VLAN, homogénéisation des configurations) et lors de sa maintenance quotidienne que dans la configuration. D'autant plus que le couple Torque/MAUI est vraiment opérationnel ! Que dire, maintenant que d'autres moyens, plus abstraits comme le Cloud Computing existent ? Car malgré tout, un cluster de calcul, ce n'est rien que pour parser des données. A vous de voir si celles-ci méritent un peu de temps et de moyens pour garder le tout sous contrôle ou si ce besoin de sécurité n'est pas du tout pertinent...
Vus : 2769
Publié par K-Tux : 59