Parallel und verteilt: Yabu im Netzwerk

3 Parallel und verteilt: Yabu im Netzwerk

» » » » » »

Yabu ist parallelisierbar, d.h. bei entsprechender Konfiguration kann Yabu versuchen, verschiedene Ziele gleichzeitig zu erreichen. Das geht natürlich nur für Ziele, die nicht voneinander abhängen, letzteres kommt aber häufig vor. Wird zum Beispiel ein Programm aus 5 Objektdateien erzeugt, dann sind die 5 Objekte in der Regel unabhängig voneinander und können parallel kompiliert werden. Auf einem Mehrprozessorsystem oder einem Verbund aus mehreren Rechnern kann man so die Kompilierzeiten eines Projektes verkürzen.

Ein zweiter Aspekt der Parallelisierung sind Multi-Platform-Projekte, die gleichzeitig auf verschiedenen Plattformen oder für unterschiedliche Laufzeitumgebungen kompiliert werden müssen. Mit Hilfe von Prototyp-Regeln, Konfigurationen und konfigurationsabhängigen Variablen lassen sich solche Projekte effizient in einem einzigen Buildfile beschreiben und Redundanzen auf ein Minimum beschränken. Das ist jedoch nur der erste Schritt. Ein kompletter Build erfordert in der Regel die Kompilierung auf verschiedenen Plattformen – ein Prozeß, der nach Automatisierung verlangt.

Die Parallelisierung des Buildprozesses ist mit Yabu in mehreren Abstufungen realisierbar. Allen gemeinsam ist die Annahme, daß ein Verbund von Rechnern als Build-Platformen zur Verfügung steht, die alle eine gemeinsame Sicht auf das Dateisystem haben und Benutzer auf allen Rechner einheitlich eingerichtet sind. Insbesondere gibt es ein globales Konfigurationsverzeichnis, auf das alle Rechner unter dem gleichen Namen Zugriff haben. Damit sind folgende Szenarien denkbar:

.1 Ein einfaches Beispiel

Wie oben bereits erwähnt, benötigt Yabu für die parallelisierte Skriptausführung ein globales Konfigurationsverzeichnis, dessen Name beim Aufruf mit der Option -a übergeben wird. Beispiel:

yabu -g /usr/local/yabu all

Den Verzeichnisnamen bei jedem Aufruf von Yabu einzugeben, wäre natürlich mühsam. In der Regel wird es hierfür ein Skript oder ein Shell-Alias geben.

Das Konfigurationsverzeichnis enthält unter anderem die Datei yabu.cfg, die Yabu beim Start auswertet. Außer allgemeinen Einstellungen (siehe Globale Konfigurationsdatei (yabu.cfg)) enthält die Datei den Abschnitt !servers mit Beschreibungen aller Rechner im Verbund. Im folgenden Beispiel besteht der Verbund aus drei Rechnern:

!servers
host frodo   max=2
host gandalf max=5
host gimli   max=2

Der Parameter max gibt an, wieviele Skripte parallel ausgeführt werden sollen. Er richtet sich nach der Leistungsfähigkeit der Rechner, insbesondere nach der Anzahl von Prozessoren bzw. Prozessorkernen.

Mit der obigen Beispielkonfiguration ist noch nicht viel erreicht. Immerhin kann Yabu nun die vorhandenen CPU-Resourcen ohne Hilfestellung durch den Benutzer sinnvoll ausnutzen. Der nächste Schritt ist, jedem Rechner eine Konfiguration zuzuordnen. Wir nehmen an, daß zwei der Rechner unter Linux und einer unter FreeBSD läuft:

!options
   platform(linux freebsd)
!servers
host frodo   max=2 cfg=linux
host gandalf max=5 cfg=linux
host gimli   max=2 cfg=freebsd

Der !options-Abschnitt entspricht der !options-Anweisung im Buildfile (siehe Optionen) – mit dem kleinen Unterschied, daß hier die Einrückung nicht zwingend erforderlich ist. Durch den cfg-Parameter legt man fest, für welche Konfiguration(en) die einzelnen Rechner Skripte ausführen können. Zum Beispiel kann der Rechner gandalf Skripte in der Konfiguration +linux oder +linux+debug ausführen. Dagegen würde Yabu mit einer Fehlermeldung reagieren, wenn man versucht ein Skript für die Konfiguration +freebsd auszuführen. Die Konfigurationsangabe bewirkt also einen gewissen Schutz vor Fehlern im Buildfile oder beim Aufruf von Yabu.

Der wahre Nutzen erschließt sich aber erst, wenn wir die verteilte Skriptausführung zulassen. Voraussetzung hierfür ist, daß auf jedem der Rechner ein Yabu-Server läuft (Details siehe unten). In der Konfiguration wird dies durch einen Doppelpunkt hinter dem Hostnamen kenntlich gemacht:

!options
   platform(linux freebsd)
!servers
host frodo:   max=2 cfg=linux
host gandalf: max=5 cfg=linux
host gimli:   max=2 cfg=freebsd

Damit werden die Rechner zu einem echten Verbund: unabhängig davon auf welchem Rechner man Yabu startet, können Skripte auf allen drei Rechnern ausgeführt werden. Yabu verbindet sich dazu via TCP mit den jeweiligen Serverprozessen, übergibt die auszuführenden Skripte an den Server und empfängt als als Antwort die Ausgaben des Skriptes. Für den Benutzer ist das weitegehnd transparent; er hat den Eindruck als würden alle Skripte lokal ausgeführt. Da sich nun alle Konfigurationen auf allen Rechnern erzeugen lassen, verliert die statische Auswahl der Plattform ihren Sinn. Stattdessen kann man eine Regel definieren, die alle Konfigurationen in einem einzigen Yabu-Aufruf erzeugt:

all: all-linux all-freebsd
all-%: build/%/prog1 build/%/prog2
...

.2 Auswahl des Servers per Konfiguration

Wie im obigen Beispiel gezeigt, definiert man in der Konfigurationsdatei für jeden Rechner mit "cfg=..." eine Konfiguration. Sie beschreibt, für welche Konfigurationen der Rechner Skripte ausführen kann. Wird ein Skript ausführbereit, dann ermittelt Yabu alle Server, deren Konfiguration kompatibel – im Sinne von Konfigurationen – zur aktuellen Konfiguration ist. Einer dieser Server erhält das Skript zur Ausführung. Beispiel: die Konfiguration "linux" des Servers frodo (siehe oben) ist kompatibel zu "" (leere Konfiguration) und "+linux" und "+linux+debug", nicht aber zu "+freebsd".

Die lokale Konfiguration und "_local"

In der Regel ist der Rechner, auf dem Yabu läuft, in yabu.cfg als Server definiert und hat somit eine Serverkonfiguration. Man beachte daß diese "lokale Konfiguration" unabhängig von der Startkonfiguration ist, die Yabu bei jedem Programmlauf festlegt (siehe Auswahl der Konfiguration). Insbesondere kann es vorkommen, daß die lokale Konfiguration nicht kompatibel zur Startkonfiguration ist. Das ist kein Fehler, sondern führt lediglich dazu, daß Yabu alle Skripte auf anderen Servern ausführt. Ein Beispiel, wobei wieder die obige Konfigurationsdatei vorausgesetzt wird: ruft man auf dem Rechner frodo Yabu mit

>frodo# **yabu -c freebsd**

auf, dann ist die Startkonfiguration "+freebsd" (zuzüglich weiterer Startoptionen aus dem Buildfile), die lokale Konfiguration gemäß yabu.cfg ist aber "+linux". Yabu würde deshalb alle Skripte auf derm Server gimli ausführen.

Aus diesem Grunde hat die Startkonfiguration und damit die !configure-Anweisung in einem Rechnerverbund nur noch geringe Bedeutung. Man kann sie nach wie vor verwenden, um nicht plattformspezifische Optionen global ein- und auszuschalten. Die lokale Konfiguration kann man im Buildfile über die Systemvariable $(_LOCAL_CFG) ermitteln. Wurde Yabu ohne -g gestartet oder enthält yabu.cfg keinen Eintrag für den ausführenden Rechner, dann ist der Wert der Variable ein leerer String.

Die lokale Konfiguration enthält – zusätzlich zu den Optionen aus yabu.cfg – immer die Option "+_local". Alle Server erhalten dagegen die Option "-_local". Damit ist es möglich, die lokale Ausführung von Skripten zu erzwingen, und zwar unabhängig davon, auf welchem Rechner Yabu läuft.

.3 Voraussetzungen und Konfiguration

Der Aufbau eines Rechnerverbundes wie im vorigen Abschnitt beschrieben stellt gewisse Anforderungen an die Infrastruktur.

Sind diese Voraussetzungen erfüllt, dann ist der nächste Schritt die Erstellung der Datei yabu.cfg im Konfigurationsverzeichnis. Sie sollte für normale Benutzer nur lesbar sein.

Abschnitt !settings

Der Abschnitt enthält globale Programmeinstellungen, siehe Programmeinstellungen. Beispiel:

!settings
   max_warnings=5

Abschnitt !options

Dieser Abbschnitt hat das gleiche Format wie die !options-Anweisung im Buildfile. In ihm werden globale Optionen definiert, insbesondere die Optionen, die in den Konfigurationsangaben im !servers-Abschnitt benutzt werden. Beispiel:

!options
    os(linux freebsd win32)
    subtype(debug release)

Abschnitt !servers

Im Abschnitt !servers legt man Parameter für die einzelnen Rechner fest. Er besteht aus einer host-Zeile pro Rechner, die eines der folgenden Formate hat:

host gandalf Parameter
host gandalf: Parameter
host gandalf:gandalf-if1 Parameter
host gandalf:gandalf-if1:12345 Parameter
host gandalf::12345 Parameter

Die erste Form definiert lediglich Parameter für einen Rechner. Alle anderen Formen (mit Doppelpunkt hinter dem Hostnamen) bezeichnen einen Yabu-Server, also einen Rechner auf dem der Yabu-Serverprozeß läuft. Neben dem Hostnamen kann man eine IP-Adresse und/oder eine Portnummer angeben, auf der der Server TCP-Verbindungen annimmt. Ohne die entsprechenden Angaben benutzt der Server den Port 6789 und nimmt Verbindungen auf allen lokalen IP-Adressen an.

Parameter ist eine Liste von Elementen der Form Name=Wert. Die erlaubten Parameter sind:

max

Maximale Anzahl parallel ausgeführter Kommandos. Ein sinnvoller Wert ist das Zweifache der CPU-Zahl.

config

String (Default: ""). Legt eine Konfiguration fest, für die der Server Skripte ausführen kann. config=XYZ bedeutet, daß der Server Skripte für alle Konfigurationen ausführt, welche XYZ enthalten. Siehe Auswahl des Servers.

prio

Zahl (Default: 1). Ermöglicht eine gewisse Kontrolle über die Verteilung von Skripten auf die einzelnen Rechner Rechner mit höherer Priorität werden bevorzugt ausgewählt

.4 Der Yabu-Server

Auf jedem Yabu-Server muß ein Serverprozeß laufen. Dabei handelt es sich um die gleiche ausführbare Datei wie yabu, nur wird sie unter dem Namen yabusrv gestartet. Die allgemeine Syntax ist

yabusrv -g CfgDir -S Shell -qvV?

wobei die Optionen die gleiche Bedeutung wie für Yabu haben (siehe Kommandozeile). Es ist wichtig, daß Server und Clients das gleiche Konfigurationsverzeichnis verwenden, denn darauf basiert der Verbindungsaufbau (TCP-Port in yabu.cfg) und die Authentisierung.

Der Server muß als Benutzer "root" gestartet werden, damit er Kommandos im Auftrag eines beliebigen Benutzers unter dessen Idenitität ausführen kann.

Fehlermeldungen gibt der Server über den syslog-Dienst aus, er benutzt dabei die ``Facility'' LOG_USER.

.5 Auswahl des Servers

Wenn ein Skript auszuführen ist, wählt Yabu zunächst die Server aus, die dafür in Frage kommen. Die Auswahl basiert auf der aktuellen Konfiguration (AKT) und den Konfigurationen, welche in yabu.cfg den einzelnen Servern zugeordnet sind (SRV). Ein Server wird ausgewählt, wenn SRV in AKT enthalten ist. Das heißt, jede Option, die in SRV einen definierten Wert (+ oder -) hat, muß den gleichen Wert in AKT haben. Hierzu einige Beispiele:

AKT

SRV

Ergebnis

+linux

ausführbar

+linux

+freebsd

nicht ausführbar

+linux+debug

+linux

ausführbar

+linux-database

+linux

nicht ausführbar

Außer auf den in yabu.cfg aufgeführten Servern kann Yabu Skripte auch selbst ("lokal") ausführen, also genauso wie im serverlosen Modus ohne -g. Dabei kommt es darauf an, ob der Rechner, auf dem yabu läuft, in yabu.cfg aufgeführt ist oder nicht. Enthält yabu.cfg eine host-Zeile für den Rechner, dann bestimmt der dort angegebene Parameter config, welche Skripte lokal ausführbar sind. Andernfalls sind alle Skripte lokal ausführbar.

Server haben immer Vorrang vor der lokalen Ausführung. Ist zum Beispiel ein Skript auf 3 Servern und lokal ausführbar, dann versucht Yabu zuerst, es auf einem der Server auszuführen. Nur wenn keiner der Server verfügbar ist, wird das Skript lokal ausgeführt.

.6 Lokale Ausführung erzwingen mit 'use_server'

Manchmal stört es, daß sich nicht genau voraussagen läßt, auf welchem Server Yabu ein bestimmtes Skript ausführt. Insbesondere bei der Fehlersuche wünscht man sich manchmal, daß Skripte nur lokal ausführt werden. Yabu bietet hierfür eine spezielle Programmeinstellung: use_server=no (oder auf der Kommandozeile: -j) bewirkt, daß Yabu keinen Server anruft und Skripte nur noch lokal ausführt.

Dabei bleiben alle Konfigurationsregeln weiter gültig. use_server=no bedeutet also nicht, daß Yabu nun Skripte ausführt, die nicht zur lokalen Konfiguration passen. Vielmehr muß der Benutzer darauf achten, nur solche Ziele vorzugeben, die in der lokalen Konfiguration erreichbar sind; andernfalls tritt ein Fehler auf. Man kann das auch so formulieren: use_server=no simuliert, daß alle Server ausgefallen sind.