Zahlreiche Implementierungen von Agentensystemen (= Agentensystem-Typen) wurden mittlerweile entwickelt, darunter Grasshopper, Voyager, IBM Aglets, usw. Die teilweise höchst unterschiedlichen Konzepte die dabei integriert werden, sollen in diesem Abschnitt sollen in diesem Abschnitt veranschaulicht dargestellt werden.
Eine Programmiersprache muss theoretisch sowohl für den Mobilen Agenten selbst, als auch für deren Agentensystem festgelegt werden. Da allerdings insbesondere aus Portabilitätsgründen bestehende Systeme vor allem auf interpretierenden Sprachen wie TCL oder Java basieren, gibt das Agentensystem dadurch gleich auch die konkrete Agentensprache vor.
Waren die ersten Systeme noch auf Basis von TCL (bzw. AgentTCL) realisiert, konnte sich in den letzten Jahren insbesondere Java als dominierende Agentensprache durchgesetzt.
Einige Gründe hierfür sind:
Portabilität | ein Java-Interpreter (JDK) ist inzwischen vom Mobilem Handy bis hin zum Mainframe, für große Anzahl and Plattformen erhältlich. | |
Sicherheit | Java-Programme laufen in einer Virtuellen Maschine ab und haben deshalb keinen direkten Zugriff auf systemkritische Komponenten (wie etwadem Framestack). Zusätzlich befindet sich jedes Java Programm in einem eigenen Kontext (sog. Sandbox), für den spezifische Rechte festgelegt werden können | |
Dynamisches Binden |
Dynamisches Laden von Klassen während der Laufzeit | |
Multithreading | Sogenannte leichtgewichtige Prozesse gewährleisten einen ressourcensparende und performanten Betrieb |
Hingegen existieren jedoch auch Argumente, die gegen den Einsatz von Java sprechen, etwa die fehlende Kontrolle des Ressourcenverbrauchs eines Threads / Objektes und insbesondere die nur eingeschränkte Serialisierbarkeit, auf die später genauer eingegangen wird.
Agenten werden aus der Sicht eines Agentensystems über einen sogenannten Agentenlebenszyklus (vgl. Abb. 2.1) abgebildet:
Ähnlichkeiten zu einem lebenden Wesen sind hier offensichtlich: der Agent wird „geboren“, lebt, schläft und wacht auf, pflanzt sich fort und, wenn seine Zeit gekommen ist stirb er.
Die Phasen des Agentenzyklus sind letztlich die bestimmenden Faktoren, auf die ein Agentensystem zur Steuerung eines Mobilen Agenten zugreift. Aus diesem Grund ist dieser auf manchen Systemen in leicht abgewandelter Form vorzufinden.
Weiterhin wird in diesem Zusammenhang auch eine Form von eindeutiger Adressierung für den Agenten benötigt. Übliche Form für eine globale Agentenadressierung ist dabei Agent-Identifier@host/context/place wobei konkreter auf dieses Thema in Kapitel Standardisierung behandelt wird.
Die Konzepte die dem Agenten seine Mobilität verleihen lassen aus netzwerktechnischer
(Protokolle) wie aus softwaretechnischen Sicht (Migration) betrachten.
Protokolle
Je nach Agentensystem, werden hier verschiedene Technologien angeboten. In den meisten Fällen basiert die Übertragung auf Plain-Sockets oder RPC/RMI, manchmal jedoch auch ganz ungewöhnlichen Techniken, wie Mail (z.B. Voyager) oder HTTP (z.B. Grasshopper ).
Bereits zuvor wurde ein Agent im übertragenen Sinne mit einem lebenden Wesen verglichen. Dementsprechend soll durch die Migration eines Agentenprozesses erreicht werden, dass dieser nicht etwa beendet und auf dem Zielsystem neu gestartet, sondern vielmehr in seiner Ausführung fortfährt - also angehalten und reaktiviert wird. Der Umfang, in dem dies ein Agentensystem ermöglicht bestimmt die Stärke der Migration, auf die etwas weiter unten eingegangen wird.
Die einzelnen Schritte, die von einem Agentensystem durchgeführt werden müssen um einen Agenten(-Prozess) von einem System auf ein anderes zu bewegen, wird durch die MAFO-Spezifikation (vgl. Kapitel Standardisierung) wie folgt empfohlen:
System A (versendet Agenten) 1) Ausführung des Agenten wird unterbrochen |
System B (empfängt Agenten) 7) Authentifizierung von System A |
Welche Informationen letztlich in den serialisierten Agenten-Datenstrom gespeichert und auf dem Zielsystem rekonstruiert werden, ist maßgeblich durch die verwendete Agentensprache, aber auch durch das Agentensystem selbst, bestimmt.
Neben einem Codeteil (der die benötigten Klassen enthält) betrifft dies insbesondere den Kontextteil . Hier sind verschiedene Informationen zum Agenten (Name, Identifikation) - vor allem aber auch der bereits diskutierte Zustand des Agenten - enthalten
Diesen unterteilt man in Daten-Zustand (z.B. Variablen-Werte) und Ausführungszustand (u.a. Programm-Counter). Unterstützt ein Agentensystem auch die Serialisierung nach der zweiten Form, so spricht man von starker- ansonsten von schwacher Migration.
Grundsätzlich gilt in diesem Zusammenhang nach [Braun2000] die Regel:
=> je schwächer Migrationsart, desto mehr Aufwand
für den Programmierer
=> je stärker die Migrationsart, desto komplizierter für das Agentensystem
Diese Form ist in der Praxis fast ausschließlich anzutreffen; auch hier wieder in zwei unterschiedlichen Konzepten: mit festem und beliebigen Einstiegspunkt.
Bei der schwache Migration mit festem Einstiegspunkt wird beim instanziierten Agentenprozess auf dem Zielsystem an einen fest vorbestimmten Punkt gesprungen. Bei Aglets ist dies beispielsweise durch Callback-Methoden realisiert.
01 public class Display implements java.io.Serializable
02 Boolean isRemote; 03 public class Example1 extends Aglet { 04 public void onCreation(Object init) { 05 addMobilityListener( new MobilityAdapter() { 06 public void onArrival( MobilityEvent e) { Einstiegspunkt auf System B 07 System.out.println("i am remote"); 08 isRemote = true; 09 } 11 } 12 }; 13 public void run() { 14 if (! isRemote) { 15 moveTo(„Host2“); Ausstiegspunkt auf System A 16 } 17 }
Dem hingegen gibt ein Konzept der schwachen Migration mit beliebigen Einstiegspunkt dem Agenten (bzw. der aufrufenden Instanz) die Möglichkeit, vor dem Verlassen eines Systems, den Punkt (z.B. eine Methode) zu bestimmen, an dem dieser auf dem Zielsystem, seine Ausführung fortsetzt:
Bei Voyager sieht das etwa wie folgt aus:
01 public class Display implements java.io.Serializable
02 public void display(String message ) Einstiegspunkt auf System B 03 { System.out.println( message); } 04 } 05 public class AgentClient {
04 Display agent1 = Proxy.of( new Display() );
05 Agent.of( agent1 ).moveTo( Ausstiegspunkt auf System A
"//host:8000", "display", new Object[]{ „show on remote"); 06 } 07 };
Durch starke Migration (beispielsweise in AgentTCL umgesetzt) kann ein Prozess an exakt der gleichen Stelle (z.B. innerhalb einer Schleife) auf dem Zielsystem rekonstruiert werden, an der er sich bei seiner Ausführung zuletzt befand.
String Hosts[] = { „Host1“, ... „Hostn“ };
for (int i=0; i < Hosts.length(); i++) {
moveTo( Hosts[i] ); Ausstiegspunkt auf Host 1
Einstiegspunkt auf Host 2 }
Die Form der starken Migration ist insbesondere durch interpretierende Sprachen aber nur schwer umsetzbar, da hierbei auf den Framestack des Betriebssystems zugegriffen werden muss um schließlich u.a. den Programm-Counter auszulesen.
Jedoch lässt sich durch die vorangegangene Betrachtung der Möglichkeiten der schwachen Migration hier auch Fragen, ob starke Migration wirklich benötigt wird.
Ein anderer Aspekt der Migration stellt die Verfahrensweise da, in dem diese durchgeführt wird.
Bei der Push-Migration (eingesetzt z.B. in IBM Aglets), die am geläufigsten ist, wird der Agentenkontext mit sämtlichen benötigten Klassen auf einmal an das Zielsystem übertragen.
Die Pull-Migration (eingesetzt z.B. in Voyager 2.0), sieht dagegen zunächst nur die Übertragung des Kontextes vor. Das Zielsystem fordert dann je nach Bedarf, einzelne Klassen wiederum beim ersten System an.
Die Vorteile die für die zweiten Variante sprechen, sind insbesondere bei Agenten mit zahlreichen Klassen denkbar. Auf der anderen Seite erzeugt diese wohlmöglich unnötigen Netzwerk-Traffic, vor allem bei Agenten mit nur wenigen Klassen.
Je nach Anwendung bietet sich somit die eine – oder andere Möglichkeit
ein.
Um ein Objekt in Java serialisieren zu können braucht lediglich das Interface java.io.Serializable eingebunden zu werden. Dieses enthält zwar zwei Methoden (writeObject() und readObject()), die auch überschrieben werden können, etwa um die Serialiserung anzupassen, was jedoch nicht unbedingt erforderlich ist; bereits die bloße Einbindung dieses Interfaces reicht hierfür aus, damit die Virtuelle Maschine (JVM) weis, dass dieses Objekt serialisiert werden muss.
Java unterstützt die beiden Formen der schwachen Migration, indem alle Klassen-Attribute (im objekt- und statischen Kontext) berücksichtigt werden. Sollen einzelne Variablen von der Serialisierung ausgenommen werden, können diese über den Bezeichner transistent entsprechend gekennzeichnet werden
Beispiel:
01 class MyAgent extends java.io.Serializable { 02 int myvar1; // wird serialisiert 03 static int myvar2; // wird serialisiert 04 transistent int myvar3; //wird nicht serialsiert 05 transistent static int myvar4; // wird nicht serialisiert
Variablen innerhalb von Methoden, sind hier von der Serialisierung ausgenommen,
schließlich sind diese nur sinnvoll würde auch der Ausführungszustandes
serialisiert werden können, was dann für starke Migration erforderlich
wäre., von Java jedoch nicht direkt unterstützt wird, was durch die
Architektur Java’s bestimmt und durchaus auch begründbar ist.
Zwei bekannte Möglichkeiten existieren hier jedoch um starke Migration
indirekt zu realisieren:
1. durch Anpassung der JVM (vgl.: CIA)
=> Nachteil: Inkompatibilität zu anderen
Systemen
2. durch Anpassung von Sourcecode (vgl Frühstöcken 98)
=> Nachteil: sehr komplex; Vergrößerung
des Sourcecodes
Unter Kommunikation soll in diesem Kontext, die Möglichkeiten verstanden werden, unter denen die einzelnen Komponenten eines Agentensysteme miteinander in Kontakt aufnehmen und Daten austauschen.
Hierbei sind die folgenden Kommunikations-Beziehungen relevant:
Da der letzte Punkt in den einzelnen Systemen insbesondere durch eigene Interfaces realisiert ist, soll dieser hier nicht näher betrachtet werden.
Grundsätzlich lässt sich jedoch in Bezug auf Mobile Agenten die folgende Unterscheidung davon treffen, wie zwei Agenten miteinander kommunizieren:
1. im Sinne Stationäre Agenten
Dabei bedienen sich diese verschiedener Kommunikationsmechanismen, die das Agentensystem zur Verfügung stellt (z.B. RPC/RMI).
2. im Sinne Mobiler Agenten
Dass bedeutet, dass der Agent auf das System des Kommunikationspartners (Kommunikator) migriert und mit diesem dort lokal kommuniziert.
Für beide Fälle, also für lokale wie entfernte Kommunikation, existieren wenigstens drei Konzepte, die je nach Agentensystem, in unterschiedlichem Umfang und Ausführungen vorzufinden sind:
Dem Kommunikator (Agent als Nachrichtensender) ist der Standort des Kommunikanten (Agent als Nachrichtenempfängers) bekannt. Somit schickt direkt an seine Adresse: Agent1 -> Agent2@host/context...
Der Standort des Kommunikanten muss hierbei dem Kommunikator nicht bekannt
sein. Stattdessen bedient sich dieser einer vermittelnden Stelle (sog. Broker),
über die eine Nachricht indirekt an den Kommunikanten ausgeliefert wird.
Ist ein Stellvertreter mit einem bestimmten Agenten direkt assoziierbar so wird
dieser als dessen Mailbox bezeichnet. Eine solche stellt empfangene
Nachrichten entweder direkt an den Agenten aus (reaktives Konzept) oder wartet
darauf, dass der Agent diese abfragt (aktives Konzept).
Nicht geleerte Mailboxen können dem Agentenkontext zugeführt werden,
wenn dieser auf ein anderes System migrieren will, oder als lokale Stellvertreter
(als sog. Proxy-Objekte) auf einem Agentensystem verbleiben
um die Erreichbarkeit des Agenten sicherzustellen.
Prinzipiell entspricht diese dem vorangegangenem Konzept, nur dass hierbei der Stellvertreter keinen Rückschluss auf einen bestimmten Agenten ermöglicht. Man spricht hier von sog. Blackboards („Schwarzen Brettern“), die dem Prinzip von IRC ähneln:
Zwei Agenten braucht dabei nur eine gemeinsame Queue (z.B.
„Queue1421 auf Host3) bekannt sein, an die sie nun Ihre Nachrichten senden.
Ein Agentensystem braucht die benötigte Queue mit dem entsprechenden Namen
erst anzulegen, wenn es die erste Nachricht an eine diese erhält. Eine
hohe Dynamik ist dadurch sichergestellt.
Hierunter sind die Techniken zu verstehen, die dazu dienen den Standort eines bestimmten Agenten zu ermitteln, was natürlich elementar notwendig für eine Kommunikation mit diesem ist.
Zwei Methoden sind hierbei zu unterscheiden:
Broadcast, bei dem ein Dienst alle Agentensysteme eines Netzwerk
(oder alle ihm bekannten) befragt ob sich auf diesen der gesuchte Agent befindet.
Bei einer Vielzahl potenzieller Aufenthaltsorte, ist eine derartige Vorgehensweise
natürlich höchst ineffizient.
Etwas umfangreicher zu implementieren aber deutlich effektiver ist eine zentrale
Registrierung, bei der sich Agenten vieler Systeme an- bzw. wieder
abmelden. Ein Dienst braucht deshalb lediglich die Registrierung zu befragen
und erhält dadurch die aktuelle Adresse des gesuchten Agenten.
Auch ein dezentralisierter Registrierungsdienst ist hierbei vorstellbar, bei dem ein Agentensystem etwa die Verantwortung für ein bestimmtes Netzwerk besitzt. Verlässt ein Agent nun dieses, so hält es das Zielsystem des Agenten gespeichert, um entsprechende Suchanfragen an dieses zukünftig weiterzuleiten.
Und noch ein Vorteil besitzt ein solcher Dienst: er erlaubt eine zentrale Kontrolle
einzelner Agenten, wodurch sich diese beispielsweise terminieren lassen, sollten
diese einmal nicht mehr zu ihren Erschaffern zurückfinden. Solche Agenten
werden auch Weisen genannten.
Aufgrund der hohen Relevanz, die dieses Thema gerade für Mobile Agenten Systeme darstellt würde eine vollständige Behandlung hier sicherlich den Rahmen dieser Arbeit sprengen. Deshalb soll hier nur auf einige relevante Aspekte eingegangen werden. Für eine umfassende Betrachtung sei hier auf [Hohl2001] und [Jansen1999] verwiesen.
Agentensysteme müssen sich vornehmlich vor anderen Agenten selbst – sogenannter bösartigen Agenten – schützen.
Schon die Wahl der Programmiersprache, kann für den Entwickler eines solchen Systems bereits insofern relevant sein, wenn diese über ein eigenes Sicherheitskonzept verfügt. Java beispielsweise integriert mit ihrer virtuellen Maschine und dem „Sandbox“-Konzept bereits einige mächtige Sicherheitsfunktionen.
Dennoch reicht ein solches sprachspezifisches Konzept natürlich nicht aus, um Sicherheitsrichtlinien auch für die Anwendungsschicht vorzugeben.
Hierzu ist das Agentensystem selbst aufgefordert, eine entsprechende Sicherheitsarchitektur
bereitzustellen.
Beispiel: Voyager
Voyager beinhaltet einen AccessControlWrapper. Durch diesen lassen sich verschiedene Agenten-Operationen (z.B. create(), migrate(), listenOnPort(), clone()) für unbekannte (foreign agents) und bekannte (known agents) Agenten festlegen. Um einen Agenten dem Voyager-System bekannt zu geben, muss dessen Signatur beim jeweiligen System eingetragen sein.
Mobile Agenten zu schützen ist weitaus komplizierter, als es etwa bei einem stationäres Agentensystem der Fall ist. Schließlich migriert dieser autonom zwischen diversen (potenziell unbekannten) Systemen, auf die der Erstellter in den vielen Fällen keinen Zugriff haben wird.
Folglich ergeben sich für Agenten zumindestens die drei folgenden Gefahrenquellen:
Hierunter fallen vorwiegend sogenannte „Man-In-The-Middle“-Angriffe, bei denen ein Dritter die Netzwerkübertragung abhört und ggf. auch manipuliert.
Viele Agentensysteme bieten hier bereits die Möglichkeit zur Verschlüsselung der Übertragung durch SSL. Weiterhin ist eine Identifikation von Agentensystemen durch installierte Signaturen oder etwa durch eine Zertifizierungsstelle denkbar.
Bestimmte Agenten könnten versuchen andere Agenten zu manipulieren, oder deren Informationen auszuspähen. Hierfür ist es erforderlich, dass das Agentensystem eine entsprechende Sicherheitsarchitektur bietet (z.B. getrennte Adressräume/Threadgruppen) und der Agent nur so viele sensible Informationen wie nötig speichert.
Java bietet hier – wie bereits gesehen – hierzu beispielsweise die Möglichkeit ausgewählte Informationen (z.B. Passwörter) explizit von der Serialisierung explizit auszuschließen:
transistent string Passwort
Eine weitere Gefahr, die von anderen Agenten ausgehen kann, besteht darin, dass diese die Identität eines anderen Agenten vorgeben. Dies lässt sich insbesondere durch Signaturen vermeiden, die natürlich vom entsprechenden Agentensystem unterstützt werden müssen.
Die weit größte Gefahr für Mobile Agenten geht von Agentensystemen selbst aus. Das Problem wurde bereits angesprochen: der Agent – ein Stück Software mit potenziell sensiblen Informationen – bewegt sich auf fremden Systemen, auf die der Absender meist keinen Zugriff e hat. Wie kann er hier sichergehen, dass ein Agentensystem nicht auf geschützte Daten des Agenten zugriff erhält, oder etwa die Abfragen des Agenten manipuliert ?
Für den letzten Fall, wäre ein Szenario vorstellbar, in dem das Agentensystem
eines Reiseanbieters, die Preisabfrage des Agenten in der Form manipuliert,
so dass dieser fälschlicherweise genau den betreffenden Anbieter an den
Absender als Günstigsten ausweisen würde.
Gerade der letzte Punkt macht deutlich, wie problematisch immer noch die Sicherheitslage Mobiler Agenten ist. Wer würde freiwillig einen Agenten auf ein fremdes System versenden, wenn er nicht sicher gehen kann, dass dieses den Agenten nicht manipulieren oder ausspähen wird ?
Sollen Agenten nicht nur in einem geschlossenen System, sondern gar internetweit eingesetzt werden, so ist eine Zertifizierungsstelle notwendig. Diese hätte nicht nur die Aufgabe, Authentitäten zu bestätigen, sondern eben auch einzelne Agentensysteme zu testen und nur wirklich sicheren Systemen ein entsprechendes Zertifikat auszustellen. Ob dies jedoch überhaupt umzusetzen ist, bleibt fraglich.