RMI - Remote Method Invocation

Im folgenden sollen die Ziele und Funktionsweisen von RMI dargestellt werden.


Was ist RMI?

Für die Anwendungsenwicklung ist es häufig von entscheidender Bedeutung auf Daten und Dienste, die sich auf anderen Rechnern in einem Netzwerkverbund befinden, zuzugreifen. Insbesondere der Zugriff auf entfernte Dienste ist für viele Anwendungen wichtig.
RMI stellt hierzu einen Mechanismus zur sog. verteilten Anwendungsprogrammierung bereit, d.h. es ermöglicht dem Anwendungsprogrammierer auf entfernte Objekte zuzgreifen und deren Dienste zu nutzen. Als entfernte Objekte (Remote Objects) werden Objekte bezeichnet, die sich auf einer anderen JVM befinden. Diese kann (muß aber nicht) auf einem anderen Rechner laufen und ermöglicht damit die Kommunikation über Netzwerke zwischen verschiedenen Rechnern.
Die Plattformunabhängigkeit der Java-Architektur läßt RMI zu einem mächtigen Werkzeug werden, da es auf einfache weise ermöglicht Programmcode im Netzwerk zu verteilen, auch über verschiedene Plattformen hinweg.

Ziele von RMI.

Die Übertragung von reinen Daten im Netztwerk ist mit dem Zugriff auf die Transportschicht relativ einfach zu erledigen. Das Verteilen von Programmcode dagegen und damit der Zugriff auf die Dienste entfernter Rechner erfordert allerdings ein aufwendiges Kommunikationsprotokoll, daß sich um die Datenerstellung und Kommunikationssteuerung kümmert. Das direkte Ziel von RMI ist es den Anwendungsprogrammierer hierbei zu unterstützen und ihm die aufwendige und fehleranfällige Implementierung eines solchen Protokolls abzunehmen. Dies führt zu einer Reduzierung des Programmieraufwands und befreit den Programmierer davon das "Rad für jedes Programm neu zu erfinden".
Zu den indirekten Zielen von RMI gehört es Lastausgleich von Programmen zu ermöglichen, sowie die Skalierbarkeit von Programmen zu erhöhen. Ein wichtiges Anwendungsbeispiel hierfür ist Middleware.

Grundlagen

RMI bedient sich hierzu RPC, einer Methode, die erstmals 1984 von Birrel und Nielson [Birrel, 1984] vorgestellt wurde und den Zugriff auf die entfernten Serverfunktionen wie lokale Prozeduraufrufe aussehen lässt (siehe RPC).
In JDK Version 1.1 wurde RMI in Java eingeführt und wird durch das Paket java.rmi.* implementiert (siehe Funktionsweise RMI).
Mit CORBA wurde schon 1991 von der OMG ein System zur verteilten Anwendungsprogrammierung in heterogenen Systemen auf Objektbasis vorgestellt, das eine Vielzahl an Plattformen und Programmiersprachen unterstützt. Auch CORBA bedient sich der RPC Methode, allerdings stammt RPC noch aus der prozedualen Welt, RMI und CORBA sind dagegen objektorientierte Mechanismen (siehe CORBA).
 
RPC

RPC steht für Remote Procedure Call und wurde 1983 erstmals von Birrel und Nielson [Birrel, 1983] vorgestellt. Das Prinzip hinter RPC ist es den Zugriff auf entfernte Serverfunktionen wie lokale Prozeduraufrufe aussehen zu lassen und so die Komplexität der Netzwerkprogrammierung vor dem Anwendungsprogrammierer zu verbergen. Die eigentliche Verbindung zwischen Server und Client übernehmen sog. Stellvertreterobjekte (engl. proxies). Diese befinden sich auf Client und Serverseite und stellen lokal die benötigten Stellvertreterfunktionen zur Verfügung. Der Client ruft die lokale Stellvertreterfunktion auf (die genauso aussieht, wie die entfernte Funktion), diese verpackt die Anfrage und schickt sie an den Server. Der Server bearbeitet die Anfrage und schickt das Ergebnis zurück an die Stellvertreterfunktion, die das Ergebnis zurückgibt.

RPC Prinzip
Abb. 1 RPC Prinzip

Dies ist ein klassisches synchrones Kommunikationsschema, d.h. die aufrufende Funktion blockiert so lange, bis der Server das Ergebnis zurückgeschickt hat.
Von RPC existieren eine Vielzahl an Implementierungen, z.B. Sun RPC, Apollo RPC, DCE-RPC und Microsoft RPC.
 
CORBA

Die Common Object Request Broker Architekture wurde 1991 von der OMG entwickelt und stellt ebenfalls ein Mechanismus zur verteilten Anwendungsprogrammierung bereit, der auf dem RPC-Prinzip beruht. CORBA eignet sich insbesondere für größere, heterogene Projekte, da es eine Vielzahl von Plattformen und Programmiersprachen, z.B. C, C++, Java, Ada, Smalltalk unterstützt. Es stellt hierfür einen Transportdienst namens Internet Inter-Orb Protocol zur Verfügung, das mittlerweile auch von RMI unterstützt wird und so ein Austausch zwischen CORBA- und RMI-Anwendungen möglich macht.
 
RMI Protokolle

RMI implementiert mehrere Protokolle zwischen denen der Anwendungsprogrammierer wählen kann, um das für seinen Anwendungszweck passende auszuwählen ohne sich um die Details der Protokolle zu kümmern.
Folgende Übersicht stellt diese Protokolle zusammen und zeigt den jeweiligen Einsatzzweck auf:

  • RMI IIOP zur Integration in CORBA
  • JRMP (Java Remote Method Protocol) auch Wire-Protocol ist das Standardprotokol für RMI
  • RMI über HTTP getunnelt zur Umgehung von Firewalls
  • Verschlüsselt über SSL zur sicheren Kommunikation
 
RMI Features

Die folgende Auftstellung fast kurz die wichtigen Eigenschaften von RMI zur Übersicht zusammen:
  • Nachladen von Programmcode durch Serialisierung, d.h. dynamischer Code-Austausch
  • einfach zu erlernen
  • geringer(er) Implementierungsaufwand
  • erfordert keine zusätzlichen Lizenzen
  • Umgehen von Firewalls möglich
  • Distributed Garbage Collection (DGC)
  • Client-Server Architektur
  • bietet ein hohes Abstraktionsniveau, d.h. die eigentliche Kommunikation bleibt unsichtbar

Funktionsweise von RMI

Die Funktionsweise von RMI soll im folgenden durch die Struktur der RMI- Kommunikations-Architektur bzw. der RMI-Elemente und dem Ablauf eines entfernten  Methodenaufrufs deutlich gemacht werden.

RMI Kommunikations-Architektur

Die RMI-Kommunikations-Architektur ist, wie TCP, eine Schichtenarchitektur, die aus drei solcher Schichten (engl. layern) besteht: der Transportschicht (Netzwerkverbindung), dem Remote-Reference Layer und der Stub/Skeleton Schicht. Folgende Abbildung zeigt die verschiedenen Schichten.

KommunikationsArchitektur
Abb. 2 RMI Kommunikations-Architektur

Die Transportschicht (Netzwerverbindung) umfasst hierbei das Host OS, den sog. Networklayer und das Netzwerkkabel. Das Remote Reference Layer umfasst die Verbindungs-Semantik, d.h. es implementiert die Übertragungsprotokolle und die Verbindungsdetails.
Von größerer Bedeutung für den Anwendungsprogrammierer ist die Stub/Skeleton Schicht, die die komplizierten Details der Kommunikation vor ihm verbergen.
Mit Stub bezeichnet man die Klasse, die das Remote-Interface implementiert und dem Client als Platzhalter für das Remote-Objekt dient. Der Stub kommuniziert über die Netzwerkverbindung mit dem Skeleton auf der Serverseite.

(Anm. Seit dem JDK 1.2 ist der Skeleton für reine RMI-Anwendungen, die auf das JDK 1.2 aufbauen nicht mehr notwendig und wird mit Hilfe von Reflections implementiert. Es soll aber hier dazu dienen das Prinzip zu erläutern und ist in Form der Ties für RMI-IIOP notwendig.)

Ein Skeleton ist das Gegenstück zum Stub auf Serverseite. Der Skeleton "kennt" das tatsächliche Remote-Object, leitet die Anfrage des Stubs an dieses weiter und gibt den Rückgabewert an den Stub zurück.
Stub und Skeleton werden automatisch von dem Werkzeug rmic erstellt (siehe Implementierung von RMI), so dass der Anwendungsprogrammierer diese nicht von Hand implementieren muß.
Die Stub-Skeleton-Schicht implementiert damit das Entwurfsmuster (Remote) Proxy [Gamma, 2004], wobei der Stub den Proxy darstellt und das Skeleton das eigentliche Subjekt.

RMI Elemente und Ablauf

Für die Kommunikation zwischen Client und Server sind vier Elemente wichtig, die im folgenden beschrieben werden sollen:
  • Das Remote-Interface definiert die Funktionen, die auf dem Server zur Verfügung stehen sollen und Beschreibt damit das Verhalten der entferneten Funktionen (ohne dieses Verhalten zu implementieren).
  • Die Remote-Objekte implementieren das Remote-Interface und das Verhalten der entfernten Funktionen. Vom Server können eine oder mehrere Instanzen des Remote-Objekts erstellt werden.
  • Beim Namens-Dienst (RMI Registry) werden die Remote-Objekte vom Server registriert und die Referenzen auf diese Remote-Objekte können von den Clients abgefragt werden. RMI Registry ist eine Implementierung eines einfachen Namens-Dienstes und Bestandteil des RMI Pakets.
  • Als Remote-Referenzen werden die Referenzen auf Remote-Objekte bezeichnet.
Elemente Ablauf
Abb. 3 RMI: Elemente und Ablauf

Der Ablauf läßt sich damit wie folgt beschreiben.
  1. Zuerst wird die RMI Registry mit dem Befehl $ start rmiregistry über die Befehlskonsole auf dem Server gestartet. 
  2. Danach instanziiert der Server ein oder mehrere Remote-Objekte und meldet diese mit der Funktion Naming.bind(), die Bestandteil des RMI-Pakets ist, bei der RMI Registry an.
  3. Im dritten Schritt erfragt der Client mit der Funktion Naming.lookup() von der RMI Registry eine Referenz auf das entfernte Objekt und ist danach in der Lage auf dieses zuzugreifen.
  4. Jetzt kann der Client die entfernte Funktion aufrufen und erhält 
  5. im fünften und letzten Schritt den Rückgabewert bzw. eine Exception zurück, wenn bei der Kommunikation ein Fehler aufgetreten ist.
 
Implementierung von RMI

Die folgende Abbildung soll einen Überblick über die einzelnen Schritte bei der Implementierung geben und die relevanten Elemente hervorheben.
Eine High-Score Liste dient als Implementierungs-Beispiel, das im darauffolgenden beschrieben wird.
Implementierung
Abb. 4 Implementierungsschritte

Remote Interface definieren

Das Remote-Interface definiert die Funktionen, die auf dem Server zur Verfügung stehen sollen und muß folgende Eigenschaften erfüllen:
  • es muss vom Interface Remote des Pakets java.rmi abgeleitet werden
  • es muß als public deklariert sein
  • jede Methode muß eine RemoteException deklarieren, die alle Arten von Kommunikationsproblemen anzeigt
Die Beispiel-Implementierung von dem Remote-Interface heißt HighScore und sieht folgendermaßen aus:

import java.rmi.*;

public interface HighScore extends Remote {

    public void setHighScore(String name, int highScore)
        throws RemoteException;
   
    public int getHighestScore()
        throws RemoteException;
}

Sourcecode HighScore.java

Remote-Object implementieren

Das Remote-Object implementiert das Verhalten der entfernten Funktionen und muß folgende Kriterien erfüllen:
  • es muß von UnicastRemoteObject abgeleitet sein
  • es muß das Remote-Interface implementieren
  • es muß einen parameterlosen Konstruktor haben, denn dieser ruft nur den Konstruktor von UnicastRemoteObject auf und könnte sonst eine RemoteException auslösen
  • jede Methode muß eine RemoteException deklarieren, auch der parameterlose Konstruktor!
Die beispielhafte Implementierung von Remote-Object heißt HighScoreImpl:

import java.rmi.RemoteException;
import java.rmi.server.*;


public class HighScoreImpl
extends UnicastRemoteObject
implements HighScore
{
    public HighScoreImpl()
        throws RemoteException
        {
        }
   
    public void setHighScore(String name, int highScore)
        throws RemoteException
        {
            // setze highscore
        }

    public int getHighestScore()
        throws RemoteException
        {
            int        HighestScore=0;
            // get highest score from list
            return(HighestScore);
        }
}
Sourcecode HighScoreImpl.java

Stub und Skeleton mit rmic erstellen

Die Stellvertreterobjekte werden automatisch von dem Werkzeug rmic erstellt. Dazu ist in der Befehlskonsole folgendes einzugeben:
$ rmic HighScoreImpl
Mit HighScoreImpl gibt man das Remote-Objekt an, anhand dessen Stub und Skeleton erzeugt werden.
Folgende Parameter können u.a. verwendet werden:
  • -v1.2 (default) erstellt Stubs für das neue JRMP Protokoll
  • -iiop erstellt Stub und Tie für die CORBA Integration
  • -keep sorgt für das Speichern der Quelltexte von Stub und Skeleton/Tie

Server implementieren

Der Server ist ein "normales" Java-Programm, daß folgende Aufgaben zu erfüllen hat:
  • es muß mit new HighScoreImpl() das Remote-Objekt instanziieren 
  • und dieses mit Naming.bind() beim Namens-Dienst eintragen 
Die Beispielimplementierung des Servers heißt HighScoreServer.

import java.rmi.*;

public class HighScoreServer {

    public static void main(String[] args)
    {
        try {
            Naming.bind("rmi://localhost/HighScore",
                        new HighScoreImpl() );

        } catch(Exception e) {
            // Registrieren des Remote-Objects fehlgeschlagen
        }       
    }
}
Sourcecode HighScoreServer.java

Client implementieren

Als letztes fehlt noch der Client, der die implementierte Serverfunktionen nutzt. Auch dieser ist ein gewöhnliches Java-Programm, daß sich hierfür eine Remote-Referenz von der RMI Registry holt und die entfernte Serverfunktion aufruft.

import java.rmi.*;

public class HighScoreClient {

    public static void main(String[] args)
    {
        try {
           
            HighScore myHighScore = (HighScore) Naming.lookup("rmi://localhost/highscore");
           
            myHighScore.setHighScore("Adele", 100);
           
        } catch(Exception e) {
            // Zugriff auf Remote-Object fehlgeschlagen
        }
    }
}
HighScoreClient.java

Zusammenfassung

Die wesentliche Eigenschaft der RMI Implementierung ist die Trennung von der Beschreibung (Interface) und der Implementierung des Verhaltens. Das Remote-Interface beschreibt das Verhalten, das Remote-Objekt Implementiert das eigentliche Verhalten:

"definition of behavior and the implementation of that behavior are seperate concepts"

Das folgende UML-Diagramm soll die Zusammenhänge noch einmal deutlich machen.
UML Diagramm
Abb. 5 UML Diagramm

Als letztes soll noch darauf hingewiesen werden, dass ein entfernter Methodenaufruf deutlich mehr Zeit verbraucht, als ein lokaler. Deswegen sollte der Einsatz der entfernten Methodenaufrufe gut durchdacht sein, um Geschwindigkeitseinbußen zu vermeiden.

Glossar

RMI Remote Method Invocation
RPC Remote Procedure Call
RRL Das Remote Reference Layer (siehe Kommunikations- architektur) implementiert die Verbindungssemantik, d.h. das Übertragungsprotokoll und kümmert sich um die Verbindungs-Details.
Remote Object Stellt das entferntes Objekt dar und liegt auf dem Server. Es implementiert das Remote Interface und das Verhalten der für die Clients zur Verfügung stehenden entfernten Methoden.
Remote Interface Beschreibt die Funktionen, die auf dem Server zur Verfügung stehen und definiert damit das Verhalten des entfernten Objekts.
Remote Reference Referenzen auf Remote Objects werden als Remote Referenzen bezeichnet. Die Clients bekommen die RR von der RMI Registry.
CORBA Common Object Request Broker Architekture ist wie RMI ein Mechanismus zur verteilten Anwendungsprogrammierung, der nach dem RPC-Prinzip funktioniert und für sehr viele Plattformen und Programmiersprachen verfügbar ist, z.B. C, C++, Java, Ada, Smalltalk u.a.
RMI Registry Ist ein spezieller Namensdienst und Bestandteil des java.rmi.* Pakets. Remote Objects werden bei der RMI Registry angemeldet und Clients können von der RMI Registry Referenzen auf die Remote Objects bekommen, um auf diese zuzugreifen.
Stub Klasse die dem Client als Platzhalter für das Remote Object dient.
Skeleton / Tie Das Gengenstück zum Stub auf der Serverseite. Das ab JDK 1.2 verwendete, neue Protokoll (JRMP) benötigt keine Skeleton-Klasse mehr, sondern verwendet Reflections (ebenfalls ein Bestandteil des Java-Pakets).
Die Bezeichnung Tie wird verwendet, wenn das RMI-IIOP Protokoll verwendet wird.

 
Literatur

[Birrel, 1983]

Birrell, A. D. & Nelson, B. J., "Implementing Remote Procedure
Calls", XEROX CSL-83-7, October 1983

[Darwin, 2002] Java Kochbuch, Ian F. Darwin, 1. Aufl. 2002, O'Reilly
[Gamma, 2004] Erich Gamma, Richard Helm, Ralph E. Johnson u. a., Entwurfsmuster, 2004, ADDISON-WESLEY, MÜNCHEN
[Krüger, 2004] Krüger, Handbuch der Java Programmierung, 4. Aufl., Addison-Wesley
[Middendorf, 2002] Java - Programmierhandbuch und Referenz,  3. Auflage 2002
Stefan Middendorf, Reiner Singer, Jörn Heid
[RFC 1057, 1988]

RPC: Remote Procedure Call
Protocol Specification
Version 2, June 1988,  http://www.ietf.org/rfc/rfc1057.txt

[Sun1, 2005] Sun Microsystems, JDK 5.0 Documentation, http://java.sun.com/j2se/1.5.0/download.jsp#docs
[Sun2, 2005]
Sun Microsystems, White Paper 'Java Remote Method Invocation - Distributed Computing for Java'
[Sun3, 2000] Sun Microsystems, jGuru: Remote Method Invocation, http://java.sun.com/developer/onlineTraining/rmi/index.html
[Ullenboom, 2004] Java ist auch eine Insel, Galileo Computing, 4. Aufl.
[Wikipedia, RMI, 30.10.2005] Wikipedia, Artikel RMI, vom 30.10.2005, http://de.wikipedia.org/wiki/RMI

 
Download
Präsentation

Hier können die Folien zur Präsentation heruntergeladen werden:

Vortrags-Folien Adobe PDF-Format
Vortrags-Folien Open Document Format
Vortrags Folien Microsoft Power Point

Erstellt von Stephan Bögel. Letzte Änderung am 16.11.2005 um 15:39. http://www.sbgl.de/rmi