RPC
- Remote Procedure Call
ÜBERSICHT
1. Definition und Funktionsweise
des RPC
2. Ablauf eines RPC
3. Aufgaben der Prozedurrümpfe (Stubs)
4. RPC-Semantiken
5. RPC-Protokolle
6. Waisenbehandlung
7. Quellen
1.
Definition und Funktionsweise des RPC
RPC ist ein Mechanismus um verteilte
Anwendungen auf Basis des Client/Server-Modells zu realisieren.
Neben dem Client/Server gibt es zwei weitere Kooperationsformen,
nämlich Produzenten/Konsumenten-Systeme und das Pipeline-Modell.
Prozesse kooperieren, um ein gemeinsames Ziel zu erreichen.
Client/Server-Modell
Der Server bietet seinen Service einer Menge a priori unbekannter
Clients an. Service bezeichnet die Software-Instanz, die auf
einer oder mehreren Maschinen ausgeführt wird. Der Server
ist eine Maschine, die Service-Software ausführt. Der
Client ist der Nutzer eines Services.
Produzenten/Konsumenten-Systeme
Der Konsument nimmt Daten auf, die vom Produzenten erzeugt
wurden. Hier genügt ein unidirektionaler Kanal.
Pipeline-Modell
Eine Pipeline kann man sich als ein unidirektionalen Kanal
vorstellen.
2. Ablauf eines RPC
3. Aufgaben der Prozedurrümpfe
(Stubs)
3.1 Binden von Clients an
Server
Binden ist die Zuordnung eines
Clients an einen Server. Der Server muss die vom Client gewünschte
Prozedur anbieten. Beim Binden unterscheidet man zwei Arten,
nämlich das statische Binden und das dynamische Binden.
Statisches Binden
Beim statischen Binden geschieht das Binden beim Übersetzen
des Clientprogramms. Der Client-Stub identifiziert den Server
mittels einer Adresse. Diese Art des Bindens hat den Vorteil,
dass es kein Overhead zur Laufzeit gibt. Ein großer
Nachteil ist aber, dass keine dynamische Server-Rekonfiguration
möglich ist. Auch ist der Einsatz von mobilen Servern
nicht möglich. Sämtliche Server müssen zur
Zeit der Übersetzung bekannt sein.
Dynamische Binden
Beim dynamischen Binden gibt es Unterschiede in der Wahl des
Bindezeitpunktes und der Art des Bindevorgangs.
Das Binden kann zu Beginn des
Programmablaufs gemacht werden. Dies hat den Vorteil, das
ein Bindevorgang pro entfernter Prozedur nötig ist. Dabei
spielt die Anzahl der Aufrufe der entfernten Prozedur keine
Rolle. Der Nachteil ist, dass keine dynamische Anpassung an
den aktuellen Systemzustand während der Programmausführung
möglich ist.
Geschieht das Binden erst beim Aufruf der entfernten Prozedur,
so hat es des Vorteil, dass eine dynamische Anpassung an den
Systemzustand möglich ist. Dem gegenüber steht der
Nachteil des mehrfachen Bindens pro entfernter Prozedur.
Auf welche Art kann ein Bindevorgang
durchgeführt werden? Es gibt die Möglichkeit der
Zuhilfenahme eines Directory-Dienstes oder mittels Broadcast-Aufrufen.
Einen Directory-Dienst kann man
sich als Dienst vorstellen, der sämtliche Server mit
den angebotenen Diensten verwaltet. Falls ein Client einen
RPC startet, so wird zuerst im Directory-Dienst nachgeschaut,
welcher Server den gewünschten Dienst anbietet. Als Antwort
auf die Anfrage wird dem Client die Adresse des Servers übergeben.
Erst dann kann auf der Client-Seite das Binden gemacht werden.
Diese Art des Bindevorgangs kann auch in größeren
Systemen eingesetzt werden, hat aber den Nachteil, dass der
Directory-Dienst sehr zuverlässig und leistungsfähig
sein muss.
Falls kein Directory-Dienst gewünscht
wird, so bietet sich die Möglichkeit mittels Broadcast-Aufrufen
den Server zu finden, der den gewünschten Dienst anbietet.
Dabei startet der Client einen Broadcast-Aufruf. Alle Server
antworten mit den zur Verfügung gestellten Diensten und
ihren Adressen. Der Client entscheidet sich für den Server,
der den benötigten Dienst zur Verfügung stellt.
Diesen kann er mittels der Adresse ansprechen. Broadcast-Aufrufe
erfordern, dass alle Server den Aufruf bearbeiten. Auch sind
sie nur in lokalen Netzen praktikabel.
3.2 Transparente Kommunikation:
Transport-Mechanismus (z.B. TCP, UDP), Datenrepräsentation
und Sicherheit (Verschlüsselung, Authentifizierung)
Auf welche Art und Weise (welches
Protokoll, Art der Verschlüsselung, Authentifizierung)
die Kommunikation zwischen Client und Server stattfindet ist
Sache des Client-Stubs. Z.B. baut SUN RPC auf TCP und UDP
auf.
Idealerweise sollte der Aufruf
von eine entfernten Prozedur das gleiche Verhalten haben wie
der Aufruf einer lokalen Prozedur. Man unterscheidet zwischen
call-by-value und call-by-reference Parameteraufrufen.
3.3 Kodierung (Marshalling)
und Dekodierung (Unmarshalling) von Argument- und Ergebnisparametern
der entfernten Prozedur
call-by-value
function inc1(i: integer) : integer;
begin
i:= i+1;
return (i)
end;
Aufruf z:=inc1(x);
Client-Stub: Bei einem Aufruf
der entfernten Prozedur inc1, wird der Wert des Variable x
als Argument in die Nachricht an den Server kopiert.
Server-Stub: Der Server-Stub kopiert die Nachricht in eine
Variable i
Die Prozedur wird ausgeführt.
Server-Stub: Server-Stub kopiert aus Variable i Ergebnis in
Nachricht an Client-Stub.
Client-Stub: Kopiert Ergebnis aus Nachricht in Variable z
call-by-reference, Mögliche
Realisierung durch Call-by-Copy / Restore-Ansatz
procedure inc2 (var i : integer);
begin
i:=i+2;
end;
Aufruf inc2(x);
Client-Stub: Bei einem Aufruf
der entfernten Prozedur inc2, wird Variable x als Argument
in Nachricht an den Server kopiert.
Server-Stub: Der Server-Stub kopiert Argument aus Nachricht
in Stub-Variable und übergibt der Prozedur Pointer auf
Stub-Variable.
Die Prozedur wird ausgeführt.
Server-Stub: Kopiert wird der Wert der Stub-Variable als Ergebnis
in Nachricht an den Client.
Client-Stub: Kopiert Ergebnis aus Nachricht in Variable x
Allerdings gibt es Probleme mit
dem Call-by-Copy / Restore Ansatz. Falls es bei einem entfernten
Prozeduraufruf unterschiedliche Kopien für eine Referenzvariable
gibt, so unterscheiden sich die Ergebnisse bei einer lokalen
und entfernten Ausführung. Kurz: Probleme entstehen,
falls zwei oder mehr Parameter das gleiche Objekt referenzieren.
Eine alternative Realisierung
ist der Zugriff des Servers auf den entfernten Parameterwert
auf der Clientseite. Das verursacht allerdings einen hohen
Overhead.
Als Fazit kann man festhalten,
dass Call-by-Value Parameterübergabe einfach und effizient
zu realisieren sind. Call-by-Reference und Pointer-Parameter
sind problematisch bzw. ineffizient. Deshalb erlauben viele
RPC-Systeme nur Call-by-Call-Value-Parameter.
3.4 Fehlerbehandlung (Kommunikationsfehler,
Clientfehler und Serverfehler)
Es können folgende Fehler
auftreten:
Fehler 1: RPC Auftrag nicht korrekt
übertragen oder geht verloren.
Fehler 2: RPC Ergebnis nicht
korrekt übertragen oder geht verloren.
Fehler 3: Server kann Prozedur
nicht beenden, z.B. durch Rechnerausfall oder Software-Fehler.
Fehler 4: Client wird während
des RPCs abgebrochen, z.B. durch Rechnerausfall oder Software-Fehler.
Es gibt drei Möglichkeiten
wie der Client-Stub im Falle des Ausbleibens einer Antwort
reagiert.
1: Als erstes kann der Client-Stub
auf die Antwort warten, ohne etwas zu unternehmen. Damit ist
der Client permanent blockiert. Die Prozedur wird entweder
irgendwann ausgeführt oder nicht.
2: Der Client-Stub benutzt Timeout-Mechanismus.
Falls es innerhalb der eingestellten Zeit zu keiner Ausführung
der Prozedur kommt, gibt der Client-Stub eine Fehlermeldung
an den Client weiter.
3: Der Client-Stub benutzt Timeout-Mechanismus.
Falls es innerhalb der eingestellten Zeit zu keiner Ausführung
der Prozedur kommt, sendet der Client-Stub den Auftrag erneut
an Server. Falls der Server Duplikate (von Anfragen) erkennt,
wird die Prozedur nur einmal ausgeführt, falls nicht
>=1.
Ohne Fehler garantiert jedes
RPC-System, dass eine entfernte Operation genau einmal ausgeführt
wird. Im Fehlerfall können unterschiedliche RPC-Systeme
ein unterschiedliches Verhalten aufweisen, wie oben beschrieben.
RPC-Semantiken beschreiben, wie
sich ein RPC-System im Fehlerfall verhält.
4. RPC-Semantiken
4.1
Maybe
Ein Aufruf wird nicht oder höchstens einmal ausgeführt.
Der Client erhält im Fehlerfall eventuell keine Information
über den Status des Aufrufs.
4.2
At-Least-Once
Ein Aufruf wird mindestens einmal ausgeführt, d.h. Mehrfachausführungen
sind möglich.
4.3
At-Most-Once
Ein Aufruf wird genau einmal ausgeführt. Jedoch gibt
es Einschränkungen bei Systemfehlern. D.h. es wird keine
Garantie für eine Ausführung gegeben, aber es wird
garantiert, dass es keine Mehrfachausführung gibt.
4.4
Exactly-Once
Der Aufruf wird genau einmal ausgeführt, es gibt keine
Einschränkung bei Systemfehlern.
5. RPC-Protokolle
Ein RPC-Protokoll ist die Realisierung
einer RPC-Semantik. Unter 4. wurden RPC-Semantiken vorgestellt.
Hier soll näher darauf eingegangen werden, wie die geforderten
Eigenschaften der jeweiligen RPC-Semantik erreichen lässt.
Es gibt zwei unterschiedliche
Protokollklassen. Request/ Response (RR) und Request/ Response/
Acknowledge (RRA)
5.1 Maybe
Der Client-Stub sendet einen
Auftrag und startet Timer. Falls Timeout oder ein Fehler auftritt,
bevor die Antwort eintrifft, wird eine Fehlermeldung (Exception)
an den Client weitergegeben.
Der Server-Stub erkennt keine Duplikate. Er sendet die Antwort
nach Ausführung der Prozedur.
Was passiert, wenn request unterwegs verloren geht? Der Client-Stub
wartet bis Timeout und gibt Exception an den Client weiter.
Was passiert, wenn response verloren geht? Der Client-Stub
wartet bis Timeout und gibt Exception an den Client weiter.
Falls es zu keinem Fehler kommt, wird der Aufruf höchstens
einmal ausgeführt. Bei einem Fehler wird der Aufruf nicht
ausgeführt. Somit ist die obere Forderung erfüllt.
5.2
At-Least-Once
Der Client-Stub speichert den Auftrag in einem flüchtigen
Speicher. Falls es zu einem Timeout kommt, sendet er Auftrag
periodisch an den Server, bis eine Antwort eintrifft. Der
Auftrag wird aus dem flüchtigen Speicher gelöscht,
wenn die Antwort eintrifft.
Der Server-Stub erkennt keine Duplikate und sendet Antwort
nach Ausführung der Prozedur an Client-Stub.
Was passiert, wenn request verloren geht? Nach Timeout sendet
der Client-Stub die Anfrage nochmals. Dies wird so oft wiederholt,
bis eine Antwort eintrifft.
Was passiert, wenn response verloren geht? Nach Timeout sendet
der Client-Stub die Anfrage nochmals. Dies wird so oft wiederholt,
bis eine Antwort eintrifft.
Falls request verloren geht, wird die Anfrage nur einmal ausgeführt.
Falls allerdings response verloren geht, wird die Anfrage
mehrmals ausgeführt. Der Server erkennt nämlich
keine Duplikate.
Die Forderung ist erfüllt. Aufruf wird mindestens einmal
ausgeführt, aber Mehrfachausführungen sind möglich.
5.3 At-Most-Once
Der Unterschied zu At-Least-Once
ist, dass der Server die Antwort in einen flüchtigen
Speicher schreibt und sie danach erst an den Client-Stub sendet.
Der Server-Stub ist in der Lage Duplikate auf der Basis von
Auftrag-Id zu erkennen und führt eine Anfrage genau einmal
durch. Nur wenn ack beim Server einkommt, wird das Ergebnis
der Anfrage aus dem Speicher gelöscht. Wenn nicht, sendet
der Server-Stub die Antwort periodisch bis ack eintrifft.
Was passiert, wenn request verloren geht? Nach Timeout sendet
Client-Stub die Anfrage nochmals. Die wird periodisch wiederholt,
bis eine Antwort eintrifft.
Was passiert, wenn response verloren geht? Nach Timeout sendet
Client-Stub die Antrage erneut. Durch den Auftrag-Id erkennt
der Server-Stub das Duplikat. Die gespeicherte Antwort wird
ausgelesen und erneut gesendet. Damit ist die Forderung erfüllt,
dass die Anfrage genau einmal berechnet wird.
Was passiert, wenn ack verloren geht? Server-Stub sendet die
Antwort periodisch, bis ack eintrifft. Weitere Frage: Wie
weiß der Client-Stub, falls er die Anfrage nach Empfang
von response (d.h. ack ging verloren) löscht, ob er ein
ack einfach so, nach einem erneuten Empfang von response,
senden soll? Eine Möglichkeit wäre, dass der Client-Stub
die acks speichert und erst nach einer gewissen Zeit löscht.
Die Forderung, dass der Aufruf
genau einmal ausgeführt wird, ist somit erfüllt.
Bei Client- und Server-Fehlern kann die Ausführung nicht
garantiert werden.
5.4 Exactly-Once
Dieses Protokoll ist wie bei
At-Most-Once, außer das die Aufträge und Antworten
auf stabilen Speicher geschrieben werden. Save und Unsave
sind atomare Operationen. Ein Server-Fehler vor save macht
alle Änderungen der Prozedur rückgängig.
6. Waisenbehandlung
Ein Abbruch von Clients kann
zu Waisen (Orphans) führen. Ein Waise ist ein aktiver
Server ohne wartenden Clients. Waisen bedeuten Verschwendung
von Ressourcen, sowie die unnötige Sperrung von Betriebsmitteln.
Außerdem können die Nachrichten von verwaisten
Servern weiderangelaufene Clients stören. Es gibt einige
Ansätze, um diese Probleme zu lösen.
6.1 Extermination
Der Client-Stub schreibt alle
Adressen der aktiven Server in einen stabilen Log. Nach Wiederanlauf
des Client sendet dieser "abort-server"-Nachrichten
an alle Server im Log.
Bei diesem Ansatz führt der Client die Waisenentdeckung
durch. Außerdem führt häufiges Schreiben auf
stabilem Speicher zu einem hohen Overhead. Allerdings kann
eine Netzpartitionierung den Server unerreichbar machen.
6.2 Expiration
Bei diesem Ansatz bekommt der
Server eine genaue Zeit zur Auftragsbearbeitung. Läuft
die Zeit ab, so muss der Server die Verlängerung explizit
beantragen. Wird die Verlängerung nicht gewährt
oder nicht beantwortet, so wir der Auftrag abgebrochen.
Hier übernimmt der Server die Waisenentdeckung. Eine
Netzwerkpartitionierung wird hier toleriert, d.h. falls der
Client und der Server sich nicht mehr erreichen können,
erfolgt trotzdem ein Abbruch der Auftrages auf dem Server.
Außerdem gibt es hier einen erhöhten Aufwand durch
die Anfrage-Nachrichten.
6.3 Drakonische Inkarnation
Die Zeit wird in Epochen eingeteilt
und sequentiell durchnumeriert. Das System hält die Nummer
der aktuellen Epoche auf stabilem Speicher fest. request-
und response-Nachrichten enthalten die Nummer der aktuellen
Epoche. Nach einem Crash des Client startet dieser nach dem
Wiederanlaufen eine neue Epoche mit new epoche und wird mittels
Broadcast new epoche an alle Server gesendet. Die empfangenden
Server werden abgebrochen. Falls ein Server ein request aus
einer neuen Epoche empfängt, so wird dieser ebenfalls
abgebrochen. Es gibt also zwei Möglichkeiten um eine
Server zum Abbruch zu bringen.
Wie merkt der angefahrene Client, dass er kurz zuvor zusammengebrochen
war? Nach dem Anfahren vergleicht der Client seine aktuelle
Epochennummer mit der Nummer auf dem stabilem Speicher.
Die Waisenentdeckung übernehmen Client und Server. Ein
großes Nachteil der drakonischen Inkarnation ist, dass
bei einem Wechsel der Epoche alle Server abgebrochen werden.
6.4 Behutsame Inkarnation
Der Unterschied zur drakonischen
Version ist hier, dass beim Beginn einer neuen Epoche der
Server überprüft, ob er tatsächlich Waise ist.
Das hat den Vorteil, dass nur Waise abgebrochen werden.
7. Quellen
[1] Skript Grundlagen Verteilte
Systeme; Prof. Dr. Kurt Rothermel - Abteilung Verteilte Systeme
an der Universität Stuttgart
|