Par Alex Vrenios mailto:Alex.Vrenios@motorola.com
La mobilité logicielle peut signifier différentes choses suivant les personnes. Par exemple, l'informatique mobile est souvent assimilée à l'accès au courrier électronique sur un ordinateur portable, la migration de processus se rapporte à la redistribution automatique de la charge d'un réseau de stations, et un agent mobile décrit un processus en cours d'exécution, collectant les données avant de rapatrier un résultat complet sur un site destinataire. Le premier exemple est une extension du modèle client/serveur décrit depuis les années 1980, alors que les autres exemples, illustrant de la migration autonome de processus à travers un réseau de machines, sont des sujets de recherche pointus [1].
Les systèmes en grappes sont des ordinateurs parallèles, réseaux de stations qui présentent au client l'interface d'accès d'un unique serveur. De nombreux processus peuvent s'exécuter sur une grappe, parmi lesquels certains peuvent s'auto-dupliquer afin de répondre à un accroissement soudain du débit de requêtes des clients. Un système d'exploitation de grappes doit pouvoir inciter un ou plusieurs de ces processus à migrer vers d'autres n{\oe}uds du réseau, équilibrant ainsi la charge totale de la grappe.
Les agents autonomes sont de simples processus dont la plus efficace des descriptions est l'illustration. Considérons que vous vouliez assembler les composants les moins chers afin de construire votre ordinateur de rêves. Imaginez devoir appeler ou visiter tous les fournisseurs afin de comparer les prix des cartes mères, des disques, et des lecteurs de CD-Roms, etc. Maintenant, imaginez envoyer sur le web un agent logiciel intelligent qui se chargerait d'examiner tous les sites afin d'en rapporter la liste de tous les composants les moins chers, avec prix et URLs. Si vous lui confiez votre numéro de carte bancaire, tous ces composants pourraient arriver directement devant votre porte ! Voici l'idée.
Le tout premier problème à résoudre pour mettre en {\oe}uvre le système de migration est de définir la façon dont un processus dupliqué sera lancé à partir d'un processus actif. Ce n'est pas un simple fork distant car le nouveau processus doit pouvoir repartir au début de son exécution. Ce n'est pas un simple rsh car le code exécutable du processus n'existe par forcément sur le n{\oe}ud distant. Quelles sont les techniques à utiliser ? Quelles sont les modifications à apporter au système de fichiers distant pour permettre la prise en compte d'une requête d'exécution d'une copie du processus actif ? Examinons ces questions qui définissent le clonage de processus.
L'approche consiste à développer un nouveau service et d'y associer une interface via une fonction. Le processus appèle cette fonction en précisant le nom de la machine distante. La fonction effectue la liaison via le démon d'interconnexion inetd sur un port prédéterminé de la machine distante afin de déclencher le service de clonage.
Les vieux systèmes Unix lançaient des démons pour chaque service à disposition des autres machines. Quand vous utilisiez telnet, par exemple, un démon dédié au telnet, nommé telnetd, attendait une connexion sur le port 23 de la machine distante. (Le port 23 est toujours utilisé par telnet. C'est un des nombreux ports pré-définis énumérés dans /etc/services). De par le nombre croissant de ces démons en attente de connexion, la mémoire virtuelle disponible et le nombre de processus utilisateurs devinrent limités.
Le super-démon résolvit ces problèmes en attendant une connexion sur un quelconque des ports parmi toute une liste pré-définie, et en lançant automatiquement le serveur associé au service effectivement accédé. Il suffit maintenant d'ajouter une ligne à deux fichiers pour enregistrer un nouveau service. Seul le super-utilisateur peux éditer ces fichiers et ré-initialiser inetd afin de relire ces fichiers [2].
Gardez à l'esprit que lorsque vous autorisez un processus d'une machine distante à lancer une copie de lui-même sur votre machine, vous acceptez un risque important que ce nouveau processus soit hostile. Toutes les machines de mon réseau étant sous mon contrôle, je ne suis pas concerné par ce risque. Ce problème ne sera plus discuté par la suite.
Le service doit être déclaré dans /etc/services. Ajoutez l'entrée comme suit :
clone 5050/tcp # automatically starts cloned
où clone est le nom du service, 5050 est le port pré-défini, et tcp est le protocole de transport. Nous avons choisi le port 5050 parce-qu'il est plus grand que le nombre de ports dédiés au système et qu'il était libre. (La connotation fifty-fifty de 50-50 le rendra plus facilement mémorisable).
Le service de clônage doit être défini dans /etc/inetd.conf comme suit :
clone stream tcp nowait root /user/bin/cloned clone
où clone est le nom du service précisé dans /etc/services. (Se reporter aux pages man d'inetd.conf pour la description des autres paramètres [2].) Notons que inetd ne prendra pas en compte ce nouveau service qu'au prochain reboot, ou lorsque vous lancerez une commande pour forcer la relecture de ce fichier de configuration. Pour cela, exécutez en tant que super-utilisateur la commande suivante
killall -HUP inetd
Votre programme fait appel à la fonction clone() avec le nom de la machine sur laquelle doit être exécutée la nouvelle copie du processus. La fonction clone() détermine le nom du processus actif en sélectionnant son propre pid dans le résultat d'une commande ps. Puis elle détermine le chemin vers l'exécutable avec la commande which.
Quand clone() se connecte sur le port 5050, inetd accepte la connexion et construit les liaisons nécessaires pour associer l'entrée standard du processus cloné au flux d'arrivée sur le port et sa sortie standard sur le flux de sortie. Le processus cloné est lancé à partir de inetd via les appels système fork() et execl() [3].
Quand le clone prend la main sur la machine distante, il lit le nom de l'exécutable qui lui est envoyé en premier. Le code exécutable reçu ensuite est écrit dans l'espace /tmp sous le même nom.
L'application locale appelle clone() avec le nom de la machine distante. La fonction clone() se connecte au port du service de clonage, provoquant le lancement du clone sur la machine distante. Elle envoie ensuite une copie de l'exécutable vers la machine distante via le même port. La copie est déposée dans /tmp par le démon de clonage puis activée par un fork() et un execl().
Ce qui arrive ensuite est du ressort de l'application. Vous avez la possibilité d'établir une nouvelle connexion avec votre clone distant et de laisser ainsi les deux copies activées. Vous pouvez aussi mettre fin au processus local et effectuer ainsi de la migration d'agent. Vous pouvez même recopier sur une tierce machine une nouvelle version du processus à partir de la copie distante et obtenir ainsi une ribambelle de clones en réseau.
Le comportement final sera déterminé par votre application, mais le premier pas est d'arriver à rendre un processus actif sur une machine distante. Un programme misc/test.c et le démon de clonage, misc/cloned.c ainsi que sa fonction d'interface, misc/clone.c sont inclus dans cet article. Tout est écrit en C et testé avec la distribution Linux RedHat version 4.2.
Copyright 1999, Alex Vrenios. Paru dans le numéro 51 de la Linux Gazette de Mars 2000.
Traduction française de Dominique Lazure.