11. Anlage
 
zurück
11.5 Verteilte Systeme (Anlage E)


Diese Anlage definiert durch Kategorisierungspragmas, Attribute und einer Ada-Paketschnittstelle eine sprachkonforme Erweiterung des Ada-Standards für die Unterstützung der Programmierung von homogenen Verteilten Systemen (Verteiltes System).
Für das Verständnis des Ada-Verteilungsmodells werden einführende Aussagen zu Verteilten Systemen gemacht:
  • Vorteile eines Verteilten Systems.
  • Erstellung einer Verteilten Anwendung.
  • Wichtige Eigenschaften des Ada-Verteilungsmodells.
Das Ada-Model eines Verteilten Systems beruht semantisch auf dem Partitionsmodell.
Für die Interprozeßkommunikation in einer Verteilten Anwendung (Verteilte Anwendung) sieht der Ada-Standard den "Remote Procedure Call (RPC)"-Mechanismus vor (Remote Subprogram Call).
Das Partition Communication Subsystem (PCS) enthält die standardisierte Ada-Paketschnittstelle "System.RPC", welche die Mechanismen für die RPC-Kommunikation zwischen den Verteilten Einheiten bereitstellt.


Einige wichtige Gründe für den Einsatz einer Verteilten Anwendung sind:
  • Bestimmte Anwendungen besitzen von der Natur aus eine verteilte Ausprägung (z. B. Produktionssteuerungssysteme).
  • Verbesserung der Leistung einer Anwendung durch Ausnutzung von Parallelität (z. B. Vektorgrafikanwendungen).
  • Steigerung der Verfügbarkeit und Zuverlässigkeit durch Ausnutzung von Redundanz (z. B. sicherheitskritische Anwendungen).
  • Leichte Erweiterbarkeit durch Hinzunahme von Prozessoren oder durch Leistungssteigerung von Prozessoren und Kommunikationsverbindungen (z. B. Server-Anwendungen).
Die Erstellung einer Verteilten Anwendung erfolgt in mehreren Schritten, die für Anwendungen auf Einzelprozessorsystemen generell nicht notwendig sind.
Hierzu gehören die Schritte:
  • Partitionierung:
    Hierunter versteht man die Zerlegung des Systems in Teile, die als Partitionseinheiten für die ausführenden Elemente des Zielsystems geeignet sind.
  • Konfiguration:
    Bei der Konfiguration werden Konfigurationseinheiten gebildet, die den physischen Knotenrechnern des jeweils eingesetzten Zielsystems zugeordnet werden sollen. Im einfachsten Fall entsprechen sich Partitions- und Konfigurationseinheiten. Darüber hinaus können mehrere Partitionen zu einer Konfigurationseinheit zusammengefaßt werden.
  • Zuteilung:
    Beim Zuteilungsprozeß werden ausführbare Module aus dem konfigurierten System erzeugt und den ausführenden Elementen (Prozessoren) des Zielsystems zugeteilt.
Beachte:
Die Anlage "Verteilte Systeme" legt nur Anforderungen hinsichtlich des Partitionierungsprozesses fest, um die Portabilität von homogenen Verteilten Systemen für unterschiedliche Zielrechnersysteme zu verbessern. Er schließt die Programmierung von heterogen Verteilten Systemen zwar nicht aus, unterstützt sie aber auch nicht explizit.
Der Konfigurations- und Zuteilungsprozeß kann von der Ada-Implementation bereitgestellt werden, wie z. B. von dem Lieferanten des Ada-Laufzeitsystems (Übersetzerhersteller) oder von jeder anderen Implementierungsinstanz (sogenannte Drittanbieter). Es werden keine Anforderungen hinsichtlich der Zuteilungsproblematik in fehlertoleranten Systemen gestellt (z. B. Behandlung von Rechnerausfällen
etc.).
Diese bewußt gewählten Festlegungen und Einschränkungen stellen sicher, daß die Implementierer für ein spezielles Zielrechnersystem immer die anwendungsspezifisch optimalen Kommunikationsmechanismen einsetzen können.


Wichtige Eigenschaften des Ada-Verteilungsmodells
  • Die Unterschiede zwischen der Programmierung einer Verteilten Anwendung und der einer nicht verteilten Anwendung sind minimal. Insbesondere geht die Typsicherheit bei Verteilten Anwendungen nicht verloren. Es ist möglich, eine Ada-Bibliothek für verschiedene Verteilungskonfigurationen zu verwenden, ohne die Anwendung neu übersetzen zu müssen.
  • Die Partitionierung ist unabhängig von den Details der verwendeten speziellen Netzwerkarchitektur.
  • Das Modell unterstützt die Programmierung von fehlertoleranten Applikationen, d. h., daß der Ausfall einer Verteilten Einheit das Gesamtsystem nicht blockiert. Zum Beispiel ist es möglich, die Serviceleistungen einer defekten Partition während der Laufzeit auf eine neue Partition zu verlagern.
  • Die begriffliche Kompatibilität mit bestehenden Standards für "Offene Verteilte Systeme" wird eingehalten (z. B. zu denen des RPC-Committees der ISO, der OSF und des U.S. Government).

Partitionsmodell

Unter der Annahme, daß das Verteilte System aus einer Kollektion von Rechnerknoten und gemeinsamen Adreßbereichmodulen besteht, kann man zwischen aktiven Prozessoreinheiten mit lokalem Speicher und passiven Einheiten mit globalem Speicher unterscheiden, die ihrerseits über keine Prozessorkapazitäten verfügen. Hinsichtlich dieses Modells definiert
das Ada-Modell verschiedene Partitionsarten: Aktive Partitionen und Passive Partitionen.

Beachte:
Das Ada-Partitionsmodell für Verteilte Systeme spezifiziert eine Partition als elementare Verteilungseinheit. Partitionen werden nicht durch Basis-Sprachelemente von Ada repräsentiert, d. h. daß Partitionen nicht durch Typdeklarationen oder Objektinstantiierung erzeugt werden können. Statt dessen besteht eine Partition aus einer Ansammlung von Bibliothekseinheiten (separat übersetzte Bibliothekspakete oder Unterprogramme), die gemeinschaftlich auf einem Verteilten Zielsystem ausgeführt werden können. Hierbei bilden die Paketspezifikationen die typischen Schnittstellen zwischen den Partitionen.
Die Kategorisierung einer Bibliothekseinheit zu einer Partitionsart erfolgt durch entsprechende Kategorisierungspragmas. Eine Verteilte Anwendung besteht in diesem Zusammenhang aus einer oder mehreren aktiven Partitionen sowie keiner oder mehreren passiven Partitionen.




Aktive Partitionen

Aktive Partitionen modellieren autonome Prozessormodule.
Man unterscheidet zwischen sogenannten "Remote Call Interface (RCI)"-Bibliothekseinheiten und "Remote Types"- Bibliothekseinheiten.
In den erstgenannten Bibliothekseinheiten können "Remote Procedure Call (RPC)"- Prozeduren wie lokale Prozeduren deklariert und durch Anwendung einer Kontextklausel von anderen aktiven Partitionen aufgerufen werden.
Mit der letztgenannten Bibliothekskategorie können Typdeklarationen vereinbart werden, die für die Kommunikation zwischen aktiven Partitionen einsetzbar sind (z. B. als formale Parameter für RPC-Prozeduren).
Jede aktive Partition kann ein eigenes Hauptprogramm besitzen, oder aber aus einer Ansammlung von Bibliothekseinheiten bestehen. Ähnlich einem Ada-83-Hauptprogramm enthält jede aktive Partition einen Umgebungsprozeß, der die Elaborierung, Aktivierung und Deaktivierung der Bibliothekseinheiten der Partition steuert.

Aktive Partitionen sind unabhängig voneinander und haben damit keinen Zugriff auf Variable in anderen aktiven Partitionen.
Das Laufzeitsystem einer aktiven Partition ist unabhängig von allen anderen Laufzeitsystemen eines aus mehreren Partitionen bestehenden Programms. Dies bedeutet unter anderem, daß keine Eingangsaufrufe von Prozessen oder geschützten Verbundtypen im sichtbaren Teil eines Schnittstellenpakets verwendet werden dürfen und daß die Pakete "Calendar" und "Ada.Real_Time" sowie der Untertyp "Priority" in einer aktiven Partition nur lokale Gültigkeit haben. Es existiert kein
Rendezvouskonzept zwischen Prozessen aus verschiedenen aktiven Partitionen.
Jede aktive Partition verwaltet ihr eigenes Prozeßsystem und vermeidet dadurch die generell in Verteilten Systemen bekannten Probleme hinsichtlich einer verteilten Zeitverwaltung und der Aktivierung und Terminierung von Prozessen.


Passive Partitionen

Passive Partitionen stellen Daten und eventuell Code zur Verfügung, die zwischen den aktiven Partitionen geteilt werden können. Aktive Partitionen können auf Daten in passiven Partitionen zugreifen und diese gemeinschaftlich nutzen ("shared data").
Man unterscheidet zwischen sogenannten "Pure"-Bibliothekseinheiten und "Shared Passive"-Bibliothekseinheiten.

"Pure"-Bibliothekseinheiten besitzen Datenstrukturen, die über keinen laufzeitabhängigen Status verfügen. Konstantendeklarationen sind typische Beispiele für Datenstrukturen, die keinen laufzeitabhängigen Status besitzen.

"Shared Passive"-Bibliothekseinheiten können über Status verfügen, weil diese Bibliotheks-einheiten Objekte enthalten können, die zur Laufzeit veränderbar sind und damit einen Status besitzen, z. B. Variablendeklarationen.

Passive Partitionen besitzen kein eigenes Laufzeitsystem (z. B. keine Unterstützung von Prozeßsteuerung und Echtzeituhr).

Kategorisierung von Bibliothekseinheiten über Pragmas

In Abhängigkeit von der Rolle, die Bibliothekseinheiten in einem Verteilten System spielen, unterscheidet Ada zwischen verschiedenen Kategorien und belegt diese Bibliothekskategorien mit bestimmten Einschränkungen.
Diese Einschränkungen sollen die Typkonsistenz und die Erkennung von illegalen Partitionierungen (z. B. direkter Variablenzugriff zwischen Partitionen) in einem Verteilten System sicherstellen.
Folgende Kategorien von Bibliothekseinheiten sind durch Angabe eines entsprechenden Kategorisierungspragmas spezifizierbar:
  • "Pure"-Bibliothekseinheiten,
  • "Shared Passive"-Bibliothekseinheiten,
  • "Remote Types"-Bibliothekseinheiten,
  • "Remote Call Interface"-Bibliothekseinheiten,
  • "Normale"-Bibliothekseinheiten.

Konsistenz eines Verteilten Systems

Konsistenz in einem Verteilten System basiert auf dem Konzept der Version einer Übersetzungseinheit. Diesbezüglich bezeichnet man eine Bibliothekseinheit als konsistent, wenn die gleiche Version ihrer Deklaration in allen Partitionen des Verteilten Systems verwendet wird.
Folgende Attribute sieht die Anlage für eine Programmeinheit P vor:
  • P’Version
    Liefert einen Wert des vordefinierten Typs "String", der die Version derjenigen Übersetzungseinheit identifiziert, die die Deklaration der Programmeinheit enthält.
  • P’Body_Version
    Liefert einen Wert des vordefinierten Typs "String", der die Version der Übersetzungseinheit identifiziert, die den Rumpf der Programmeinheit enthält.
Die genaue Ausprägung der Versionsdarstellung im Typ "String" ist implementierungsabhängig.
Beim Elaborieren kann die Ausnahme "Program_Error" ausgelöst werden, falls inkonsistente Versionen von Bibliothekseinheiten in den Partitionen erkannt werden.


Remote Subprogram Call

Ein Aufruf eines fernen Unterprogramms (in Ada semantisch dem "Remote Procedure Call RPC" äquivalent) ist eine Prozedur/Funktion, die in einer "Remote Call Interface"-Paketspezifikation deklariert ist und deren Aufruf in der Regel die Ausführung der Prozedur/Funktion in einer anderen Partition bewirkt.
Ein RPC kann auf drei verschiedenen Wege ausgeführt werden:
  • direkt durch Aufruf eines Unterprogramms im sichtbaren Teil eines "Remote Call Interface"- Pakets von einer anderen Partition (statischer Bindevorgang).
  • indirekt durch Dereferenzierung einer Variablen eines entfernten Zeigers
    auf ein Unterprogrammtyp "remote access-to-subprogram-type" (dynamischer Bindevorgang) .
  • durch einen verzweigenden Aufruf eines entfernten Zeigers auf einen klassenweiten Typ "remote access-to-class-wide-type" (dynamischer Bindevorgang).
Alle RPC-Ausprägungen in Ada sind potentiell blockierend (Ausnahme: "Asynchroner RPC") und laufen in der Fehlerklasse "At Most Once" ab.
Die RPC-Implementierung soll über das vordefinierte Paket "System.RPC" erfolgen.

Wenn ein Paket durch Anwendung der Kontextklausel der gleichen Partition zugeordnet ist als das "Remote Call Interface"-Paket, dann kann die Implementierung aus Optimierungsgründen die RPC-Aufrufe als lokale Prozeduraufrufe behandeln (unter Umgehung des Partition Communication Subsystem (PCS)).
Durch Anwendung des Pragmas "All_Calls_Remote" wird erzwungen, daß alle Aufrufe über das Partition Communication Subsystem (PCS) zu erfolgen haben. Dies ermöglicht z. B. das Testen eines Verteilten Systems auf einer Einprozessoranlage.

Syntax des Pragmas:
pragma All_Calls_Remote [(library_unit_name)];


Beispiel:

-- Dieses einfache Beispiel soll den Unterschied zwischen
-- einem statischen und einem dynamischen RPC-Bindevorgang in Ada
-- demonstrieren.

-- ********************************
-- Aktive Partition A: Alarm-Server
-- ********************************
-- Die aktive Partition A modelliert einen Alarm-Server mit der
-- RPC-Prozedur "Registriere_Alarm". Diese RPC-Prozedur enthält
-- neben dem Parameter "Tageszeit" für die Registrierungszeit der
-- Alarmaktion den formalen Parameter "Aktion", der einen
-- Zugriffswert auf eine Prozedur erwartet.
-- Ein Aufruf dieser RPC-Prozedur führt zu einem dynamischen Binde-
-- vorgang, weil das Ada-Laufzeitsystem erst während der Programm-
-- ausführung durch Auswertung des formalen Parameters "Aktion"
-- entscheiden kann, auf welche Prozedur zugegriffen werden soll.
package Alarm_Server is
   pragma Remote_Call_Interface;
   type Alarm_Aktions_Typ is access procedure;
   procedure Registriere_Alarm (Tageszeit: in Duration; Aktion : in Alarm_Aktions_Typ);
end Alarm_Server;



-- **************************
-- Aktive Partition B: Client
-- **************************
-- Die aktive Partition B modelliert einen Client, bestehend aus
-- dem RCI-Paket "Datensicherung" und dem Hauptprogramm "Client".
-- Das Paket "Datensicherung" bietet für die Datensicherung die RPC-
-- Prozedur "Sichere_Dateien" an. Jeder direkte Aufruf dieser RPC-
-- Prozedur von einer beliebigen aktiven Partition führt zu einem
-- statischen Bindevorgang, weil bereits vor der Programmausführung
-- dem Ada-Laufzeitsystem die Kommunikationspartner bekannt sind.
package Datensicherung is
   pragma Remote_Call_Interface;
   procedure Sichere_Dateien;
end Datensicherung;

with Alarm_Server;
with Datensicherung;
-- Das Hauptprogramm "Client" demonstriert noch einmal zusammenfassend
-- den RPC-Aufruf für den statischen und den dynamischen Bindevorgang
-- aus der Sicht des Aufrufers.
procedure Client is
begin
   -- Dies ist ein RPC-Aufuf mit statischem Bindevorgang
   Datensicherung.Sichere_Dateien;
   -- Dies ist ein RPC-Aufruf mit dynamischem Bindevorgang
   Alarm_Server.Registriere_Alarm (Tageszeit => 3600.0,
                                   Aktion    => Datensicherung.Sichere_Dateien’ACCESS);
end Client;


Partition Communication Subsystem

Das Partition Communication Subsystem (PCS) ermöglicht den aktiven Partitionen die Kommunikation über den RPC-Mechanismus. Das Kernstück dieser Schnittstelle ist das Paket "System.RPC".
Das Paket "System.RPC" spezifiziert eine Standardschnittstelle, mit der die RPC-Prozeduren auf den Client und Server Partitionen implementiert werden sollen. Diese Schnittstelle legt sowohl die Operationen als auch die semantischen Bedingungen fest, mit denen die RPC-Prozeduren generiert werden.
Der Rumpf des Pakets wird in der Regel nicht vom Anwender, sondern vom Implementierer realisiert. Der Implementierer kann in diesem Fall entweder der Lieferant des Ada-Laufzeitsystems (Übersetzerhersteller) sein oder aber auch jede andere Implementierungsinstanz (sogenannte Drittanbieter).
Eine Implementierung dieses Ada-Pakets darf anwendungsspezifische Erweiterungen enthalten (z. B. für Message-Passing- oder Broadcast-Funktionen), sie muß aber über einen Modus verfügen, in der nur der vorgeschriebene Umfang des Pakets "System.RPC" benutzt wird.

Der Programmierer einer Verteilten Ada-Anwendung verwendet in der Regel das Paket "System.RPC" nicht, sondern nur der Übersetzer und Implementierer des PCS-Kommunikationssystems. Für den Programmierer ist das Kommunikationssystem PCS transparent, weil er die Kommunikation zwischen den Partitionen über ferne Prozedur-/Funktionsaufrufe (RPCs) in "Remote Call Interface"-Paketen sprachkonform spezifiziert und abwickelt.


Ablauf eines RPCs in einer Verteilten Ada-Anwendung

Die folgende Abbildung demonstriert den Ablauf einer RPC-Kommunikation für eine Client-/Server-Anwendung in einem Verteilten Ada-System unter Einbeziehung des Partition Communication Subsystems PCS.





Die Grundidee des "Remote Procedure Call"-Konzepts ist einfach. Der Programmierer teilt sein Anwendungsprogramm in zwei oder mehrere Teile: in das Hauptprogramm (Client-Anwendung auf Partition A) und in ein oder mehrere Pakete aus Unterprogrammen (Server-Anwendung auf Partition B). Der Client ruft diese Unterprogramme mittels RPCs auf.
Für die Client-Anwendung sieht der Fernaufruf genauso aus wie bei lokalen (Unterprogramm-) Aufrufen.
Wenn der Client eine Routine im Server rufen möchte, dann ruft er in Wirklichkeit eine gleichnamige Routine im sogenannten Client-Stub. Dieser Stub schickt über das RPC-Laufzeitsystem ein Datenpaket, bestehend aus einer Kennung für die Routine und den Eingabe-Parametern zum Server.
Der Server-Stub empfängt über das lokale RPC-Laufzeitsystem dieses Datenpaket und ruft die gewünschte Routine im Server auf. Gegebenenfalls werden Ausgabeparameter auf gleiche Weise zurückübertragen. Das RPC-Laufzeitsystem übernimmt dabei die Kodierung und Übertragung der Aufrufe und Parameter.


Zusammenfassende Darstellung

Die Erstellung einer Verteilten Anwendung in Ada läßt sich anhand der zu durchlaufenden SW-Entwicklungsphasen grob folgendermaßen zusammenfassen:

In der Übersetzungsphase der Anwendung werden die Bibliothekseinheiten, die für die Partitionierung relevant sind, vom Anwender anhand von Kategorisierungspragmas identifiziert. Für eine eventuelle RPC-Kommunikation zwischen den aktiven Partitionen generiert die Ada-Implementierung die Client- und Server-Stubs.

In der Binderphase erfolgt eine Zuordnung der RCI-Pakete und der "Shared-Passive"-Pakete zu den Partitionen durch den Anwender. Die sonstigen Ada-Bibliothekseinheiten werden entsprechend dem vorliegenden Kontext den einzelnen Partitionen zugeordnet.

In der Elaborationsphase werden RCI-Pakete und "Shared-Passive"-Pakete in genau einer Partition elaboriert, während die anderen Bibliothekseinheiten überall dort elaboriert werden, von wo aus sie referenziert werden. Ein Umgebungsprozeß ruft nach der Elaboration das Ada-Hauptprogramm (falls vorhanden), und wartet dann auf die Terminierung aller Prozesse,
die von den Bibliothekseinheiten der Partition abhängen.


 
zurück
 Index   Ada Tour - Dokumentation  
© 2003 Förderverein Ada Deutschland e.V.