(WS09-03) Management von virtuellen Maschinen

Aus Verteilte Systeme - Wiki
Zur Navigation springen Zur Suche springen

Aufgabe

Grundlagen

Management Funktionen in Virtualisierungslösungen

Zu Beginn des Projekts werden die Funktionen aktueller Virtualisierungslösungen im Hinblick auf Managementfunktionen untersucht. Mit VMWare vSphere 4 und Novell PlateSpin werden zwei kommerzielle Produkte näher betrachtet, die vor allem im Rechenzentrum zum Einsatz kommen. Dabei liegt der Fokus auf unterstützende Funktionen, die beim Auftreten von Engpässen eine automatisierte Umverteilung von vorhandenen Ressourcen vornehmen und so zu einer möglichst optimalen Auslastung der Ressourcen über verschiedene VMs hinweg sorgt.

VMWare vSphere

  • Im DRS Cluster können Ressourcen (HW) gebündelt und VMs darauf verteilt werden. Mit Regeln kann festgelegt werden welche VMs zusammen auf welcher HW laufen dürfen bzw. welche nicht. DRS kann VMs dann im Sinne von load balancing automatisch umziehen. Dabei liegt der Fokus auf CPU-Leistung.
  • Ein DRS Cluster kann dafür sorgen, das Server bei geringer Auslastung der VMs heruntergefahren werden. Dazu werden Speicherverbrauch und CPU-Auslastung aller VMs in einem Pool und die freien Kapazitäten der Server überwacht. Nun werden Möglichkeiten gesucht einzelne Server auszuschalten und die darauf laufenden VMs auf andere Server zu migrieren.
  • Für die Zuteilung von Speicher kann eine Größe für Reservation und ein Limit angegeben werden. Der Reservierte Bereich wird der VM bei Bedarf schrittweise zur Verfügung gestellt, wobei maximal bis zum Limit angewachsen werden kann. Dabei entscheidet ein Share Parameter mit welcher Priorität Speicher über der festen Reservierung zugewießen wird. Sinkt der Speicherverbrauch wieder, so sinkt die Zuweisung minimal auf den Wert der Reservierung.
  • Es können Workflows entwickelt und automatisiert ausgeführt werden, die VMs umziehen und auch die Parameter einer VM verändern können. In der Dokumentation wird nicht näher darauf eingegangen, aber es sollte so möglich sein ein automatisiertes Management zu realisieren. Allerdings muss man es noch implementierten, es wird also lediglich die Infrastruktur für die Funktion geboten.

Novell

ZenWorks

Bei ZenWorks handelt es sich um ein Produkt für das Management von virtuellen Servern, das aber mittlerweile von Novell PlateSpin abgelöst wurde. Weitere Informationen finden sich unter [1].

PlateSpin

PlateSpin dient zum aufsetzen einer virtuellen Umgebung, in der VMs teilweise automatisch verwaltet werden können. Informationen über die zur Zeit aktuellen Version 2.0.2 in der Dokumentation des Projektes.

PlateSpin® Orchestrate from Novell® transforms a static, manually operated data center into a highly flexible, automated environment where resources are dynamically allocated based on what is needed by any given business at any given time. [2]

Die Software besteht aus mehreren Komponenten und Rollen. Im weiteren werden zwei Rollen näher beschrieben werden. Diese beschäftigen sich direkt mit Planung und Umsetzung des Managements von VMs.

Der VM Administrator verwaltet den Lebenszyklus der VMs in einer virtualisierten Umgebung. Er kann Aktionen wie erzeugen, starten, stoppen, migrieren und löschen einer VM ausführen. Dem Administrator wird mit dem Orchestrate VM Client eine grafische Benutzungsoberfläche zur Verfügung gestellt, mit der er diese und eine Vielzahl von weiteren Aktionen anstoßen und Überwachung durchführen kann. So kann ein Log aller Aktionen eingesehen werden und aktuellen Ressourcesnausnutzung der VMs. (Quelle)

Der Orchestrate Administrator deployed Jobs, verwaltet Benutzer, und überwacht die verteilten Ressourcen, die in der virtuellen Umgebung ur Verfügung stehen. Um das automatisierten Management von VMs zu realisierten, legt er Policies an, die ständig auf einhaltung geprüft werden. Tritt eine Verletzung ein, so werden weitere Ressourcen zur Verfügung gestellt. Jobs können angelegt werden, um bestimmte Managementaufgaben automatisiert in festgelegten Abständen immer wieder auszuführen. (Quelle)

Eingesetzte Virtualisierungs-Technologie

Um das gegeben Ziel der Anpassung von CPU- und Speicheranteil einer VM realisieren zu können, muss in aller erster Liene die eingesetzte Virtualisierungs-Technologie dies unterstützt. Sie muss dazu Möglichkeiten bieten:

  • CPU-Zeit pro VM festzulegen und diese im laufenden Betrieb zu ändern
  • Speicherzuteilung umsetzen und auch während des Beriebs anzupassen

Zuerst wurde KVM für das Projekt in Betracht gezogen. Im Gegensatz zu Xen ist KVM im Linux-Hauptentwicklerzweig und damit in den aktuellen Distributionen integriert. KVM wird als Kernel-Modul geladen und macht den Kernel des Hosts zu einem Hypervisor. Die VMs werden als Prozesse behandelt, für die die Mechanismen (wie z.B. Scheduling) des Kernels eingesetzt werden. Konzeptionell bietet KVM keine weitere Konfigurationsmöglichkeiten, wie z.B. das Anlegen virtueller CPUs mit einem definierten Anteil an der realen CPU. Über den Kernel hätte sich dies nicht so ohne Weiteres realisieren lassen, was KVM ungeeignet für dieses Projekt macht. Die Speicherzuteilung konnte dahingegen aber sehr einfach zur Laufzeit angepasst werden. Wird einer VM so viel Speicher entzogen, dass weniger vorhanden ist als sie bereits verwendet, so wird geswappt.

Im Gegensatz zu KVM ist Xen zur Zeit relativ kompliziert zu Installierbar. Aktuelle Distributionen warten zur Zeit (Stand 12.11.2009) auf die Integration in den Hauptentwicklerkernel. Xen ist Konzeptionell als vollwertiger Hypervisor angelegt. Als solcher bietet er selbst eine Scheduler und kann darüber eine gewichtete Verteilung der CPU-Zeit umsetzen und virtuellen CPUs einen festen prozentualen Anteil an pyhsisch vorhandenen CPUs bereitstellen. So wäre es denkbar, den CPUs der VM nur 50% einer realen CPU zur Vefügung zu stellen. Ein Wert von 200% enspräche das die Leistung von zwei physischen CPUs bereitgestellt werden. Auch die Speicherzuteilung lässt sich zur Laufzeit ändern. Damit ist Xen eine geeignete Technologie zum Erreichen des Projektziels und wird verwendet.

Schnittstellen

Um Einfluss auf die CPU Zuteilung und den bereitgestellten Speicher zu nehmen, ist es notwendig, eine Schnittstelle zur eingesetzten Virtualisierungstechnik zu verwenden. Xen bietet eigene Management-Tools, die für diesen Zweck völlig ausreichen würden. Ein generalisierter Ansatz wäre der Einsatz von libvirt, die das Management vieler Virtualisierungslösungen bietet. Dabei wird eine generalisierte Programmierschnittstelle geboten, um so die Anwendungslogik von der konkret eingesetzten Lösung zu entkoppeln. Eine solche Variante ist nach Meinung des Autors zu bevorzugen.

Problemanalyse

Ziel des Projekts ist die Realisierung einer einfachen Regelung der Ressourcen von virtuellen Maschinen. Dabei sollen CPU-Anteil und bereitgestellter Speicher anhand von QoS-Parametern angepasst werden, um die VM möglichst effizient zu betreiben und ausgehandelte Performanceziele einzuhalten.

Mechanismen zur Ressourcen-Zuteilung

Für die Durchführung des Projekts muss der CPU-Anteil und das Speicherlimit für eine VM gesetzt werden. Diese kann mit Hilfe von libvirt realisiert werden. Dadurch wird die implementierte Lösung unabhängiger vom eingesetzten Hypervisor. Der Arbeitsspeicher einer VM kann Hypervisor-unabhängig mittels libvirt verändert werden.

CPU Anteil

Für den CPU-Anteil gibt es kein Hypervisor-übergreifendes, einheitliches Konzept. So bietet libvirt für z.B. KVM keine Möglichkeit diesen Anteil festzulegen, weil KVM nicht über ein solches Verfahren verfügt. Xen ist konzeptionell anderst ausgelegt als KVM und verfügt z.B. über einen eigenen Scheduler. So kann mit dem Credit-Schedulers ein Gewicht (weight) und ein fixer Wert (cap) vorgegeben werden, die Anteile an den realen CPUs beschreiben und eine Limitierung der CPU pro VM ermöglichen.

Die libvirt Bibliothek ermöglicht das abgefragen und setzen dieser Parameter:

virsh # schedinfo 6
Scheduler      : credit
weight         : 256
cap            : 0

virsh # schedinfo 6 --weight 1024
Scheduler      : credit
weight         : 1024
cap            : 0

virsh # schedinfo 6
Scheduler      : credit
weight         : 1024
cap            : 0

Das weight gibt ein Gewicht an, das der Credit-Scheduler für die VM verwendet, um die Rechenzeit zu vergeben. Dieses Gewicht wird aber nur dann berücksichtigt, wenn die Rechenzeit knapp ist und auf mehrere VM aufgeteilt werden muss.

Der cap Wert gibt an, wie viel Prozent an realen CPUs die vCPU(s) einer VM maximal verwenden. Ein Wert von 20 bedeutet in diesem Fall, das unabhängig von der Anzahl der vCPUs nur 20 Prozent der Host-Rechenzeit bereitgestellt werden. Ein Wert von 200 entspricht der Leistung von zwei CPUs.

Arbeitsspeicher

Um die Größe des bereitgestellten Arbeitsspeichers anzupassen, bietet libvirt (und Xen) zwei Paramter:

Max memory:     90000 kB
Used memory:    20000 kB

Max memory gibt dabei die Größe des Speichers an, die für die zukünftige Nutzung maximal vorgesehen ist, auch wenn diese im Moment noch nicht voll ausgeschöpft wird. Im obigen Beispiel gibt Used memory den aktuell zugewiesenen Teil mit 20 MB an. Dieser steht der VM dann bereit. Durch den Balloon Driver von Xen ist es möglich, diese 20 MB zur Laufzeit auf maximal 90 MB zu erweitern. Auch der Maximalwert kann zur Laufzeit angepasst werden. Dies schlägt aber fehl, wenn mehrere Maschinen laufen und eine Erhöhung dieser Granze zu einem Speicherengpass führen würde.

Regelung

Als Wissensbasis zur Ermittlung des Ressourcenbedarfs, sollen die Performancedaten einiger Probemessreihen dienen. Eine Instrumentierte Anwendung wird diese Daten liefern.

Einstellungen

Für dieses Projekt wird der cap Parameter zur Limitierung der CPU verwendet. Dieser Wert gibt an, wie viel Prozent an realen CPUs die vCPUs einer VM verwenden dürfe. Ein Wert von 20 bedeutet in diesem Fall, das unabhängig von der Anzahl der vCPUs nur 20 Prozent der Host-Rechenzeit bereitgestellt werden. Ein Wert von 200 entspricht der Leistung von zwei CPUs.

Da der erste Prototyp dieser Regelung mit nur einer VM arbeitet, werden Max memory und Used memory gleich behandelt. Die Mechanismen zum Abrufen und Setzen der parameter werden aber so ausgelegt, dass ein fortgeschrittener Algorithmus eine anderes Verfahren umsetzen kann.

Algorithmus

Auf Basis der Daten der Probemessreihen wird ein Diagramm erstellt, aus dem Einstellungen für CPU-Anteil, RAM und der erreihte Durchsatz entnommen werden können. Es wird erwartet, dass bei der dreidimensonalen Darstellung von Durchsatz (Z-Achse), CPU-Anteil (Y) und Speicher (X) ein Teppich entsteht, der an einigen Stellen optimalen Einstellungen aufzeigt. Diese Einstellungen werden für die Regelung einer VM verwendet.

Der Regelalgorithmus wird dazu eine Initiale Einstellung wählen und dann den Durchsatz beobachten. Fällt dieser unter ein vorgegebenes Limit, wird eine andere Einstellung gewählt. Die Auswahl einer Menge von Einstellungen obligt dabei dem Benutzer, sie wird nicht von der Anwendung durchgeführt.

Konzept

Die Regelnung der Ressourcen wird in zwei Phasen eingeteilt. Bei der ersten, werden Probemessreihen gefahren. Die dadurch gewonnenen Daten diesen als Grundlage für die Regelung. Diese kommt in der zweiten Phase zum Einsatz, wo sie auf verschiedenen Lastsituationen reagiert.

Phase 1: Performancedaten ermitteln

Performancedaten sammeln

In der ersten Phase werden CPU-Auslastung, Speichernutzung VM und Antwortzeit einer Web-Anwendung vermessen. Dabei kommt ein instrumentierter Tomcat und das ARM Instrumentierungs-Too zum Einsatz.

Die Web-Anwendung simuliert eine Sitzung eines Benutzers, indem in einer Schleife bis zu einer vorgegebenen Zahl gezäht und Speicher allokiert wird. Die Zahl wird so hoch gewählt, dass die CPU für einige Millisekunden beschäftigt ist. Der instrumentierte Tomcat wird für jede Anfrage die Performancedaten ermitteln.

Am Ende einer Promemessung werden Antwortzeit, Start- und Stop Zeitstempel in die Datenbank geschrieben. Für jede Probemessung wird eine fixe Anzahl von 1000 Anfragen gesendet und der Durchsatz pro Sekunde ermittelt. Die Einstellungen für Speicher und CPU-Anteil werden für jede Messung neu gewählt, so dass Bereiche wie z.B. 200-400 MB Speicher und 60-140% des CPU-Anteils in kleinen Schritten vermessen werden. Es resultinert eine List, ähnlich dem folgenden Beispiel:

CPU-cap  RAM  Durchsatz/s
  80     256     2 
  85     256     4 
  ..     ..      ..
  120    512     20 
  ..

Auf diesen Daten aufbauend, kann mittels gnuplot ein dreidimensionales Diagramm erstellt werden, das als Grundlage für die Implementierung der Steuerung dient.

Phase 2: Automatische Regelung der VM

Regelung

Die Regelung wird von einer Anwendung übernommen, die nicht in der zu regelnden VM ausgeführt wird. Dies entspricht der Aufgabenstellung, die eine Ausweitung des Konzepts auf mehrere VMs fordert, denn dann ist eine zentrale Regelung erforderlich, die über die Daten aller geregelten VMs verfügt. Zudem können die Algorithmen zur Regelung sehr komplex sein und würde damit die Leistung der VM verfälschen.

Die VM stellt den aktuellen Durchsatz, Speicherverbrauch und CPU Idle-Time über einen Apache Web-Server bereit. Der Virtualisierungs-Host bereichert diese Daten noch um die aktuellen Einstellungen von CPU-Anteil und Speicher und stellt diese der Regelung zur Verfügung. Sie benötigt diese Daten, um entscheiden zu können, ob mehr Ressourcen benötigt werden oder ob die vorgegebenen QoS-Parameter eingehalten und noch Ressourcen freigegeben werden können. Der Regelalgorithmus muss diese Werte in einem Intervall abfrageb und stets auf Einhaltung der vorgegebenen QoS-Parameter achten.

Eine Einstellung für CPU-Limit und Speicher kann ebenfalls mittels eines HTTP-Requests gesetzt werden. Der Host verwendet libvirt, um diese Parameter anzuwenden.

Realisierung

Phase 1: konfigurationen ermitteln

Durchführung der Probemessungen

Für die Durchführung der Vermessung der Auswirkung von unterschiedlichen Ressourcen-Einstellungen, wurde eine Para-Virtualisierte VM mit 2 CPUs gewählt. Als Betriebssytems kam dabei Ubuntu Linux "Karmic" mit 2.6.31.6 Kernel. Mit Java SE JDK 1.6.0_15-b03 wurde der Applicationserver Tomcat 5.5 betrieben, der die serverseitige Komponente der Stressumgebung des Labor für Verteilte Systeme. Ram und CPU-Anteil werden an dieser Stelle nicht weiter genannt, da diese beiden Faktoren im Rahmen der Messung jeweils verändert wird.

Auf dem Host war ein Debian Linux mit 2.6.26-2-xen-amd64 und Xen 3.2.0. Für die Anpassung der Ressourcen wird in diesem Projekt libvirt verwendet, die in Verison 0.4.6 installiert war. Die PostgreSQL Datenbank zum Sammeln der Messdaten war ebenso auf dem Host installiert. Ihm stand eine CPU und ~5 GB Ram zur Verfügung.

Vorbereitungen

Eingestellte Werte für RAM und CPU-Share werden samt gemessener Antwortzeit in einer Datenbank gespeichert.

CREATE TABLE test_series (
  id INT PRIMARY KEY,
  cpu_share INT,
  cap INT,
  ram INT,
  requests INT, 
  threads INT,
  stressfactor INT, 
  allocBytes INT
);


CREATE sequence test_series_seq;

CREATE TABLE response_times (
  id INT REFERENCES test_series (id),
  response_time DECIMAL(8,2),
  start NUMERIC DEFAULT 0,
  stop NUMERIC DEFAULT 0
);

-- Einfügen
-- INSERT INTO test_series VALUES(nextval('test_series_seq'), 250, 256000, 1000, 50);

Durch diese Struktur lassen sich verschiedene Testreihen in der Datenbank speichern. Die Auswertung der Daten kann dann mit Hilfe von SQL erfolgen.

Durchsatz ermitteln und Plotten

Die gesammelten Daten aus der ersten Phase werden nun grafisch aufbereitet und in Form eines Diagramms dargestellt. Der Benutzer kann dieses einsetzen, um Punkte zu identifizieren, an denen eine Anpassung der Parameter einer VM sinnvoll erscheint. Aufbauend auf diesem Wissen werden manuell Regeln definiert, die später für die Zuteilung von Ressourcen verwendet werden.

Im folgenden Beispiel wird der Durchsatz für eine Testreihe bestimmt. Im WHERE Block kann über die einzelnen Parameter gesteuert werden, welche Testreihe verwendet wird.

SELECT cap, ram / 1001 AS ram, req_per_sec FROM test_series A JOIN 
      (SELECT id, count(*) / ((max(start) - min(stop)) / 1000) AS req_per_sec FROM 
       response_times GROUP BY id) B ON 
                                                 (A.id=B.id) WHERE 
                   A.requests=1000 AND
                   A.threads=40 AND
                   A.stressfactor=50000000 AND 
                   A.allocbytes=2048000 AND 
                   A.cap>=80  AND 
                   A.cap <= 180 AND 
                   A.ram>=80 AND 
                   A.ram <= 500000 ORDER BY ram, cap;

Bei der Aufbereitung der Daten, so dass sie mit gnuplot dargestellt werden können, wird ein Shell-Skript eingesetzt. Es trennt die nach CAP und RAM sortierten Ergebnisse in Blöcke, getresst durch eine Leerzeile. Diese wird von gnuplot benötigt, um das resultierende Diagramm aufzubauen. Ein Block beinhaltet alle CAP Einstellungen und den Durchsatz, zu einer bestimmten RAM Einstellung.

RAM=0
cat ./psql_output_file | while read LINE
do
	CURRAM=$(echo $LINE | awk '{ print $3 }')
	# init RAM variable
	if [[ $RAM -eq 0 ]]; then
	    RAM=$CURRAM
	fi
	
	# Test whether new datablock begins
	if [[ $RAM -ne $CURRAM ]]; then
	    # Add an empty line to indicate that the next datablock begins
	    echo "" >> $OUTFILE
	    RAM=$CURRAM
	fi
	COUNT=$(expr $COUNT + 1)
	echo $LINE | awk '{ print " "$1" "$3" "$5  }' >> $OUTFILE
done

Anschließend können die bearbeiteten Daten geplottet werden

set zrange [90:0]
set title 'Durchsatz einer VM mit Tomcat'
set view 60,75,1.0,1.0
set isosample 40
set ticslevel 0
set ylabel "RAM"
set xlabel "CPU cap"
set ytics rotate
set pm3d
splot "file.dat" with lines

Diagramme auswerten

Bei dem vorherigen Schritt wurden die folgenden Diagramme erstellt.

  • Auf der X-Achse ist die Menge an Ram in MB zu sehen
  • Auf der Y-Achse ist der CPU-Anteil aufgetragen
  • Die Z-Achse zeigt den Durchsatz (Anfragen/s)

Messung 10 Threads.png

Wie zu erkennen ist, wird bei einer Belastung durch 10 Threads, die jeweils Anfragen an die Web-Anwendung senden, eine Sättingung erreicht. Diese tritt bei einem CPU-Anteil von ca. 60 und 125 MB Ram ein.

Messung 20 Threads.png

Bei 20 Threads werden wesentlich mehr Ressourcen benötigt, um eine Sättigung zu erhalten. Diese ist hier bei einem CPU-Anteil von ca. 140 und 150 MB Ram erreicht. Werden mehr Ressourcen hinzugefügt, so wirkt sich dies nicht weiter auf den Durchstz aus.

Messung 40 Threads.png

Bei 40 Threads kann ein Durchsatz von bis zu 90 Anfragen/s erreicht werden, zumindest in dem untersuchten Bereich. Auffällig ist, dass für einen derart hohen Durchsatz kaum mehr Speicher benötigt wird. Zwischen 150 MB und 160 MB kann man in dem Diagramm ablesen. Allerdings wird ein sehr hoher CPU-Anteil von 160-180 benötigt.

Messung 80 Threads.png

In der letzten Messung mit 80 Threads können bis zu 90 Anfragen/s verarbeitet werden. Dies ist wiederum mit sehr moderaten Konfigurationen für CPU-Anteil (ca. 170-180) und Ram (ca. 165-185) möglich.

Phase 2: Regelung der VM

Die Regelung ist auf Server und Client aufgeteilt. Dabei ist eine VM in der Rolle des Clients, der Performancedaten liefert und die Anpassung der Einstellungen für CPU-Anteil und RAM ermöglicht. Als Server dient eine Anwendung, die diese Daten abruft und mit Hilfe einer Regelungsalgorithmuses bei Bedarf eine neue Einstellung bestimmt.

Client (VM)

Der Client (VM) stellt zwei CGI Skripte bereit, die mittels HTTP-Request

  • den aktuellen Ressourcenverbrauch, sowie Einstellungen von CPU-Anteil und RAM liefern
  • die Einstellung von CPU-Anteil und RAM setzen

Aktuelle Ressourcenverbrauchsdaten ermitteln

Um eine zielgerichtete Anpassung der bereitgestellten Ressouren zu ermöglichen, müssen der aktuelle Speicherverbrauch sowie die CPU-Auslastung der VM abrufbar sein. Zur Ermittlung der Daten wird das folgende CGI-Skript eingesetzt:

#!/bin/bash

# Einen HTTP-konformen Header ausgeben
echo Content-type: text/plain
echo ""

# Ermittelt maximal verfügbaren und aktuell belegten Speicher
MAXMEM=$(free | grep Mem | awk '{ print $2 }')
CURMEM=$(free | grep Mem | awk '{ print $3 }')

# Ermittelt die durchschnittliche Idle-Time
IDLE=$( mpstat 1 1| grep Average | awk '{ print $10 }')

# Holt Hostname
HOSTNAME=$(hostname)

# XML zusammenbauen
echo "<performance-data>"
echo "<host>$HOSTNAME</host>"
echo "<maxmem>$MAXMEM</maxmem>"
echo "<curmem>$CURMEM</curmem>"
echo "<cpuidle>$IDLE</cpuidle>"
echo "</performance-data>"

Es kann mittels HTTP über den Apache Web-Server abgerufen werden (asterix00, asterix01) und gibt ein XML-Dokument zurück:

<performance-data>
  <host>asterix01</host>
  <maxmem>512000</maxmem>
  <curmem>240636</curmem>
  <cpuidle>98.22</cpuidle>
</performance-data>
  • maxmem - Speicher der maximal verwendet werden kann
  • curmem - Speicher der aktuell verwendet wird
  • cpuidle - Prozent von 100 die die CPU in idle ist (CPU Auslastung = 100 - cpuidle)


Host-Manager (Virtualisierungshost)

Auf dem Virtualisierungshost arbeitet der Host-Manager, der mittels HTTP-Requests das Abrufen von allgemeinen und performancebezogenen Daten der VMs ermöglicht. Zudem dient er als Schnittstelle zum Hypervisor und ändert die Werte des CPU-Anteils und des bereitgestellten Arbeitsspeichers.

Regelung

Der in Java geschriebene Hauptteil des Projektes verwaltet verschiedene VMs und verfügt über einen Regel-Algorithmus, um deren Ressourcen zu kontrollieren. Dazu wird der Host-Manager verwendet, der das Abfragen von Informationen und Anwenden von Parametern bezüglich der Ressourcen ermöglicht.

Konfiguration

Für jede vm kann ein eigener Eintrag angelegt werden. In diesem wird ein Durchsatz festgelegt, den die Regelung einzuhalten hat. In regelmäßigen Abständen müssen die Performancedaten der VMs erneuert werden, damit Regelung entscheiden kann, ob ein Ressourcenengpass vorliegt. Der Wert kann zwar in Millisekunden angegeben werden, da aber Netzwerkkommunikation und einige aufwändige Operationen dabei ausgeführt werden, empfiehlt es sich den Wert etwas höher zu legen. 10 Sekunden +/- 4 Sekunden hat sich als guter Kompromiss herausgestellt.

Anschließend können die Zustände definiert werden, zwischen denen die Regelung hin- und herschaltet. Dabei verfügt jeder Zustand über eine eindeutige Nummer (id), sowie über einen Wert für den CPU-Anteil (cap) und RAM (ram). Um Beziehungen zwischen den Zuständen abzubilden, werden die jeweiligen eindeutigen Nummern verwendet. Die Regelung nutzt diese Beziehungen, um in den nachfolgenden Zustand zu schalten, falls ein Engpass besteht, oder einen Zustand zurück zu schalten, falls zu viele Ressourcen bereitgestellt wurden.

<configuration>
    <vms>
        <vm name="asterix01">
            <!-- The throughput we aim for -->
	    <throughputAim>40</throughputAim>
	    <!-- Interval to update a VMs performance data -->
	    <updateInterval>6000</updateInterval>
	    <states>

	    <!--
		Define as many states as you like. Each state has to provide a cap
		value between 1..200 and a value for ram in Kbytes.
	    -->
	        <state>
		    <id>1</id>
		    <cap>70</cap>
		    <ram>110000</ram>
		    <successor>2</successor>
		</state>

		<state>
		    <id>2</id>
		    <cap>110</cap>
		    <ram>119000</ram>
		    <predecessor>1</predecessor>
		    <successor>3</successor>
		</state>

		<state>
		    <id>3</id>
		    <cap>90</cap>
		    <ram>129000</ram>
		    <predecessor>2</predecessor>
		    <successor>4</successor>
		</state>

		<state>
		    <id>4</id>
		    <cap>95</cap>
		    <ram>159000</ram>
		    <predecessor>3</predecessor>
		</state>

		</states>
        </vm>
    </vms>
</configuration>

Die entsprechenden Werte können von den erzeugten Diagrammen abgelesen werden. Dies war ursprünglich der Grund für die Erzeugung der Diagramme. Allerdings ist es einfacher, wenn man sich die Gnuplot Quelldateien vornimmt und dort nach einer Konfiguration für den gewünschten Durchsatz sucht.

Algorithmus

Da es im Rahmen des Projekts aus Zeitgründen nicht möglich war einen ausgefeilten Regel-Algorithmus zu finden und diesem zu implementieren, wurde die Anwendung an dieser Stelle flexibel ghalten. Über die Schnittstelle IResourceControl können weitere Algorithmen implementiert und in die Software eingebunden werden.

Der folgende, einfache Algorithmus verwendet im Wesentlichen die Parameter

  • Durchsatz (Ziel und aktueller Wert)
  • CPU-Idletime
  • Absolute Varianz des gewünschten Durchsatzes
  • Prozentuale Varianz des gewünschten Durchsatzes

um festzustellen, ob ein Bedarf an weiteren Ressourcen bzw. Überkapazitäten bestehen. Dies wird anhand der Aspekte Durchsatz und CPU-idletime durchgeführt.

Im ersten Fall wird geprüft, ob der aktuelle Durchsatz größer bzw. kleiner als der gewünschte ist. Da man den Durchsatz kaum konstant auf einem Wert halten kann, dient eine absolute und einer prozentuale Varianz um Grenzwerte zu finden. So kann bspw. der gewünschte Durchsatz bei 10 Anfragen/s liegen, die absolute Varianz bei 5 und die prozentuale Varianz bei 25%. Aufgrund der hohen absoluten Varianz wäre ein Durchsatz von 5 bis 15 Anfragen/s ok. Es steht dem Benutzer frei, einen prozentualen oder absoluten Wert anzugeben.

Die CPU-idletime gibt aufschluss darüber, ob zur Zeit Last besteht und die CPUs der VM arbeiten (niedriger Idle Wert) oder ob gerade keine Last besteht (hoher Idkle Wert). Diese Information wird verwendet, um bei 0 Anfragen bzw. wenn die Durchsatzziele erfüllt sind aber kaum Belastung vorliegt, wieder kontrolliert herunterzuschalten. Ganz ähnlich wird der Wert ebenso eingesetzt, um Ressourcen hinzuzugeben.

public State control(VirtualMachine vm, State currentState, StatesTree states) {
    if (vm == null || currentState == null || states == null) {
	throw new NullPointerException("Could not control the vm. At least one parameter was null");
    }
		
    State result = null;
    
    if ((vm.getPerformanceData().getThroughput() >= vm.getAimedThroughput() + absMinVariance || 
         vm.getPerformanceData().getThroughput() >= vm.getAimedThroughput() * (1.0 + relMinVariancePercent)) || 
	 vm.getPerformanceData().getCpuIdle() > 85.0d) {
	    result = states.getLast(currentState);
    } 
		
    if (vm.getPerformanceData().getCpuIdle() < 20.0d || 
        ((vm.getPerformanceData().getThroughput() < vm.getAimedThroughput() - absMinVariance ||
	vm.getPerformanceData().getThroughput() < vm.getAimedThroughput() * (1.0 - relMinVariancePercent)) &&
	vm.getPerformanceData().getThroughput() > 0)) {
	// We definitely have to apply the next state if possible
	result = states.getNext(currentState); 
    }

    if (result != null && result.equals(currentState)) { // If no better state has been found, no state change is needed, 
	result = null;
    } else if (result != null){
	log.info(String.format("Proposed state for %s: cap=%d ram=%d", vm.getName(), result.getCap(), result.getRam()));
    }
	
    return result;
}

Der Algorithmus hat ganz klar seine Schwächen. So ist es z.B. nur schwer möglich eine Maximallast anzusetzen, die unter den gesteckten Durchsatzzielen liegt. In diesem Fall würden die Ressourcen so lange erhöht, bis beim Maximum angelangt wurde. Dabei ist die Limitierung aber nicht bei den Ressourcen zu suchen. Es werden schlicht nicht mehr als n < Durchsatzziel Anfragen gesendet.

Ausserdem gerät der Algorithmus schnell ins Flattern. Dann schaltet er in relativ kurzen Abständen zwischen zwei Zuständen hin und her. Der eine hat zu wenig, der andere zu viele Ressourcen. An dieser Stelle muss ein intelligenteres Verfahren eingeführt werden, das entweder das Flattern erkennt oder zwischen den Zuständen interpolierte neue Zustände generiert.

Leider blieb am Ende des Projekts keine Zeit um diese Ideen umzusetzen.

Fazit

Leider liegen die ermittelten Zustände zu nahe beieinander. Dadurch tendiert der einfache Regelungsalgorithmus dazu, zwischen zwei Konfigurationen hin- und herzuschalten. Dieses Verhalten kann als Flattern bezeichnet werden und führt zu wechselndem erfüllen und verfehlen des angestrebten Durchsatzes. Hier wäre das automatische Erzeugen neuer Konfigurationen eine Lösung. Damit könnte evtl. eine Einstellung zwischen den beiden "Flatter"-Konfigurationen gefunden werden, die zur Erfüllung des Durchsatzziels führt, ohne das lästige hin- und herschalten.

Zudem stellte sich heraus, dass das ermitteln aktueller Performancedaten, so wie es in diesem Projekt implementiert wurde, zu aufwändig ist. Dieser Umstand führt dazu, dass das Abrufen der Daten teilweise im hohen, zweistelligen Sekundenbereich liegt. Für ein Eingreifen der Regelung ist es dann oft schon zu spät. Ausserdem kann man beobachten, das die VM in dieser Zeit teilweise lahmgelegt ist und keine weiteren Anfragen bearbeitet. Weiterhin führt der zusätzliche Aufwand zur Bestimmung der Performancedaten zu einer Verfälschung der Messergebnisse, auf denen aber die Regelung aufbaut.

Ein weiteres Problem ist nach Meinung des Autors das harte Umschalten zwischen Konfigurationen, das nicht selten zum Stillstand einer VM führt. Dies tritt vor allem dann auf, wenn die neue konfiguration zu wenig Ram bereitstellt und die VM swappen muss. Weichere Übergänge zwischen Zuständen wünschenswert.

Abschließden bleibt positiv anzumerken, dass die automatische Anpassung der eingesetzten Ressourcen eine enorme Erleichterung gegenüber manuellem Anpassen darstellt. Allerdings ist der Weg dorthin mit diesem Verfahren der Meinung des Autors nach zu aufwändig und ungenau. Die durchgeführten Messungen können höchstens als Grundlage bzw. grobe Richtung interpretiert werden.

Literatur

HowTos