lundi 26 octobre 2009

Cluster Tricks: cycle reboot

Au LACAL, nous avons récemment reçu notre nouveau cluster équipé d'Infiniband, qu'il a fallu mettre en place. Pour des raisons de convenance, rien n'est installé sur les disques des noeuds (qui servent uniquement au swap et au stockage temporaire), et le boot se fait via le réseau.

Problème 1: le BIOS est idiot - si le netboot échoue, la séquence de boot continue, puis s'arrête. Autrement dit, si un noeud tente de booter alors que le serveur est indisponible, il ne réessaie pas, il s'arrête. Ce qui serait absolument sans conséquence, s'il n'y avait le:

Problème 2: suite a un glitch administratif, nos noeuds ne sont pas équipés d'IPMI. Impossible donc de les redémarrer à distance.

Solution sympathique: puisque le disque local n'est pas utilisé pour booter, installons-y un système qui va redémarrer la machine. Il ne reste alors plus qu'a ajouter le disque à la fin de la séquence de boot, et le redémarrage sera automatique. Mais comment ?

Pour une opération aussi simple qu'un reboot, inutile de charger un système complet. On sait que, pour booter sur un disque, le BIOS vérifie d'abord la validité de la table de partitions, puis charge et exécute le code situé dans le MBR, soit le premier secteur du disque. Le code est exécuté en mode réel.

Jetons un coup d'oeil rapide dans la documentation de Linux. Elle nous apprend l'existence d'une technique primitive de redémarrage, utilisée en dernier ressort: le Triple-Fault.

Wikipedia contient une page à ce propos, et mentionne son utilisation par Linux. La technique consiste en "installer une table de vecteurs d'interruption vide, puis déclencher une interruption". Quelques recherches sur google indiquent que ceci se fait via l'instruction x86 LIDT. L'argument contient a la fois un pointeur vers la base de la table, et sa longeur; une valeur constante de 0 fonctionne pour créer une table vide.

Je crée donc un fichier reboot.asm:

lidt [0]
int 3

Que j'assemble simplement avec nasm:

max@node ~$ nasm reboot.asm
max@node ~$ hexdump reboot
0000000 010f 001e cd00 0003
0000007

Merveilleux. reste à écrire ce fragment dans le MBR de mon disque:

max@node ~ $ sudo dd if=reboot count=1 conv=notrunc of=/dev/sda

Presto !

jeudi 1 octobre 2009

Cluster Tricks: copie en masse

Dans un cluster, la vitesse des disques ou du réseau peut être un facteur limitant critique pour la performance. Considérons le scénario suivant, qui a été rencontré en pratique au Lacal:
  1. Une première phase de calcul est lancée sur chaque noeud, et produit plusieurs GB de données par noeud (stockées dans l'espace de travail sur le disque local)
  2. Une deuxième phase de calcul est lancée, et elle a besoin de toutes les données précalculées sur tous les autres noeuds.
Les disques sont assez gros pour acueillir chacun une copie du dataset intermédiaire complet (quelques centaines de GB). Mais comment les distribuer efficacement ?

Evidemment, un bête SCP ferait l'affaire, mais il serait impensable de le lancer a la main entre les différentes machines suivant un ordonnancement précis (ou alors, trop emmerdant, et pas assez réutilisable).

Un bête scp de toutes les machines vers un noeud "principal", puis de ce noeud vers les autres, ferait aussi l'affaire. Mais terriblement lent.

Au moment ou je suis intervenu sur le problème, la copie sur un noeud maître avait déja été faite, mais le scp séquenciel était hors de question (trop lent).

Une première solution intéressante s'est révélée en Bittorrent. Les outils pour cela sont disponible dans portage (nous avons utilisé BitTornado, qui est un peu plus pratique que le client original "mainline" tout en étant très similaire d'utilisation). Une fois le hash initial accompli sur le noeud maitre (ce qui prend toutefois beaucoup de temps), la copie s'est faite relativement efficacement.

Mais on est encore très en dessous du maximum théorique, ce qui m'a amené a découvrir la solution idéale pour le job: uftp (http://www.tcnj.edu/~bush/uftp.html), un système ftp-like over udp, supportant le multicast.

Avec le multicast, chaque noeud peut envoyer un seul paquet de données au switch, le paquet sera répété sur toutes les interfaces (ou seulement sur les interfaces utiles si le switch gère le Multicast Snooping, ce qui n'était pas notre cas), et chaque machine pourra réceptionner le paquet simultanément, ce qui génère un gain très appréciable de vitesse (dans notre cas, vitesse de copie globale d'environ 400MB/s, au lieu des 6MB/s offerts par scp, et des 150MB/s offerts par bittorrent.)

L'utilisation est très simple, même si manquant un peu de flexibilité. Le recepteur est un daemon tournant sur chaque machine, qui stockera tous les fichiers reçus dans un répertoire public sur le disque local. L'émetteur est un client lancé par un utilisateur, qui prendra simplement un nom de fichier en argument.

Evidemment, ce système est totalement abusable et n'intègre absolument aucune sécurité. et ne doit être employé qu'a l'intérieur d'un réseau de confiance. L'ebuild est disponible ici (https://xolus.net/~max/uftp-ebuild.tar.gz) en attendant qu'elle fasse son chemin dans Sunrise.