Verteilte Systeme - Praxis

Aus FernFH MediaWiki
Zur Navigation springen Zur Suche springen

Praxis Verteilter Systeme

„Was ist anders an verteilten Systemen?
Nun, sie sind eben nicht zentralisiert.“ [1]

Das Client Server Modell

In diesem Modell unterscheidet man zwei verschiedene Arten miteinander kooperierender Prozesse: die Server, die einen Dienst (Service) bereitstellen und die Clients, die Nutzer eines Dienstes. Ein Client sendet eine Anfragenachricht, in der er einen bestimmten Dienst nachfragt, an einen Server. Dieser erfüllt den Dienst, indem er die nachgefragten Daten oder eine Fehlermeldung zurückliefert, die den Grund des Versagens beinhaltet (siehe auch [I5]).

Es ist aber auch möglich, dass ein Prozess gleichzeitig sowohl Client als auch Server ist. Wenn ein Server für die Bereitstellung eines Dienstes den Dienst eines anderen Servers benötigt, wird er zum Client bezüglich des anderen Servers.

Interprozess-Kommunikation

Zwischen Threads: Alle Threads eines Prozesses befinden sich im selben Adressraum. Dadurch ist es möglich, Daten im Hauptspeicher abzulegen, auf die jeder von ihnen zugreifen kann. Die Kommunikation zwischen den Threads erfolgt also am effektivsten über globale Variablen. Allerdings bildet der Zugriff auf die gemeinsam genutzten Daten einen kritischen Abschnitt, der zu synchronisieren ist. Dies kann mit Hilfe von Semaphoren, Monitoren oder ähnlichen Mitteln erfolgen. Durch sie wird garantiert, dass ein Thread einen kritischen Abschnitt ohne Unterbrechung durch einen anderen ausführt.

Zwischen Prozessen: Mehrere Prozesse können nicht über globale Variablen miteinander kommunizieren, da jeder Prozess seinen eigenen Adressraum besitzt. Betriebssysteme bieten jedoch für Prozesse andere Mittel der Kommunikation an. Laufen zwei Prozesse im selben Rechner ab, so kann bei der Implementierung der Interprozesskommunikation (IPC) der physisch vorhandene gemeinsame Speicher genutzt werden. In UNIX System V werden dafür Bibliotheksroutinen zum expliziten Einblenden vom shared memory oder dem Austausch von Nachrichten angeboten. Besitzen zwei Prozesse Zugriff auf das selbe Filesystem, so kann die Kommunikation auch darüber erfolgen (named pipes in UNIX). Ein allgemein anwendbares Verfahren der IPC ist jedoch der Nachrichtenaustausch. Er funktioniert sowohl zwischen Prozessen, die sich auf dem lokalen Rechner befinden als auch zwischen Prozessen, die sich auf unterschiedlichen Rechnern befinden.

Synchrone Middleware

Geht man vom OSI-Schichtenmodell für Netzwerke aus, positioniert sich die Middleware in den obersten drei Schichten: „Applikation, Präsentation und Sitzung“. Sie definiert dabei auf Grundlage des darunter liegenden Netzwerkes die Kommunikationsmechanismen zwischen den einzelnen Applikationen.

Zum Einsatz einer Middleware-Lösung muss diese auf den zu integrierenden Systemen überhaupt zur Verfügung stehen, es muss die Funktionalität der entsprechenden Schnittstelle im Mittelpunkt der Spezifikation bzw. des Design stehen und sie sollte über ausreichende Mechanismen zur Transaktionssicherung verfügen bzw. Möglichkeiten zur Verschlüsselung und Authentifizierung anbieten.

Bei der synchronen Kommunikation ist der Sender (Client) von der Anforderung einer Verbindung zum Empfänger (Server) bis zum Erhalt der gewünschten Informationen oder Ergebnisse blockiert (blocking), was bedeutet, dass die Ausführung des entsprechenden Programms für die Dauer der Kommunikation und der Bearbeitung der Anfrage durch den Server ausgesetzt wird. Hat der Server den Wunsch eines Verbindungsaufbaues bestätigt, können keine weiteren Verbindungen zu ihm aufgebaut werden (siehe auch [P9] und [P10]).

Asynchrone Middleware

Das asynchrone Kommunikationsprinzip beinhaltet die Unabhängigkeit der internen Verarbeitung und Kommunikation beim Sender und Empfänger. Nach Übergabe des zu sendenden Datenstroms an das Kommunikationssystem fährt der Sender mit weiteren Prozeduren fort, ohne zu blockieren. Er wartet demzufolge nicht auf eine Quittierung oder ein Bearbeitungsresultat des Empfangssystems. Dieses Konzept bietet den Vorteil, dass der Server weder direkt mit dem Client verbunden noch überhaupt verfügbar sein muss, damit eine Kommunikationsanforderung im Netzwerk abgesetzt werden kann (non-blocking) und trotzdem erfolgreich bearbeitet wird (siehe auch [I5]).

Bei asynchroner Kommunikation, auch Message Passing genannt, arbeitet der Sender nach dem Abschicken einer Nachricht bereits weiter, ohne auf eine Antwort zu warten. Die Anfrage verbleibt dann unter Umständen längere Zeit in der Anfrageschlange beim Empfänger, ohne den Prozess komplett zu blockieren. Eine solche Entkopplung ermöglicht eine sehr flexible Arbeitsweise der Anwendungen. Neben dem Begriff Message Passing wird dies auch als „fire and forget“ bezeichnet. Die beiden hier in Frage kommenden Varianten sind die Broadcasting- und Publish/Subscribe-Kommunikation.

Beim Broadcasting schickt der Sender die Nachricht über einen öffentlichen Kanal ab. Jeder Empfänger, der Zugang zu diesem Nachrichtenmedium hat, kann die Nachrichten verwerten oder nicht. Die grundsätzliche Idee hinter der Publish/Subscribe-Kommunikation ähnelt der des Broadcastings mit dem Unterschied, dass die Nachricht nur an Empfänger zugestellt wird, die im Vorhinein diese Nachricht oder das Thema der Nachricht abonniert (siehe auch [P9]).

Nachrichtenorientierte Middleware

Die in den vorhergehenden Abschnitten beschriebenen Middleware-Ansätze gehen in ihrer praktischen Umsetzung weitgehend von einer synchronen Kommunikation zwischen zwei Applikationen oder zwischen einer Applikation und einer Datenbank aus. Solange kommuniziert wird, sind der Sender und der Empfänger in allen Fällen blockiert. Erst in jüngster Zeit existieren Bestrebungen, beispielsweise bei der OMG mit CORBA, asynchrone Kommunikationsmechanismen in die Standards zu implementieren. Ein weiterer Nachteil ist die strenge Peer-to-Peer Ausrichtung der Middleware-Ansätze. Dadurch wird eine Einbindung neuer Applikationen aufgrund der hohen Kopplung zwischen den Systemen wesentlich erschwert.

Message-orientierte Middleware (MOM) geht einen anderen Weg. Die Kommunikation zwischen zwei Applikationen erfolgt hier ausschließlich über den Austausch von Nachrichten, d.h. dass nach Übertragung einer Nachricht an die Middleware-Schicht die Applikation sofort weiterarbeiten kann. Der Transport und das Routing der Informationen werden von der MOM-Software übernommen. Somit kann über message-orientierte Middleware asynchron kommuniziert werden. Allerdings werden auch synchrone Mechanismen zum Datenaustausch angeboten (siehe auch [P9]).

Enterprise Applikationen und e-Business

Um Komponentenorientierte Middleware beschreiben zu können, muss zunächst einmal geklärt werden, was Komponenten überhaupt sind. Allgemein versteht man unter einer Komponente einen ausführbaren Programmkode, der eine bestimmte Funktionalität beinhaltet und diese in Form von Diensten über definierte Schnittstellen den Clientanwendungen oder anderen Komponenten bereitstellt. Im Unterschied zur objektorientierten Programmierung ist ein Zugriff auf Funktionalitäten und Daten nur über diese Schnittstellen möglich. Die strikte Kapselung ermöglicht es, die Implementation auszutauschen ohne das Gesamtsystem zu beeinflussen solange Funktionalität und Schnittstellen gleich bleiben. Der Zugriff auf Komponenten ist dabei nicht auf einzelne Prozesse oder auf einzelne Computer beschränkt. Verteilung und Kommunikation werden durch eine Middleware-Schicht realisiert, wodurch Modifikationen am Quellcode der Clientprogramme wegfallen können. Komponenten sind somit insbesondere für n-Tier Applikationen geeignet. Ziel der Entwicklung ist es, durch die lose Kopplung und das Black-Box-ähnliche Verhalten die Wiederverwendung zu fördern und den Prozess der Softwareentwicklung mit der Unterstützung von Drag-und-Drop basierter Zusammenstellung von Applikationen aus Softwarekomponenten zu beschleunigen.

Mit der 1997 vorgestellten Enterprise Java Beans (EJB) Technologie stellt die Firma Sun ein entsprechendes Komponentenmodell für die Entwicklung und das Deployment von serverseitigen Unternehmensanwendungen zur Verfügung (siehe auch [P8] und [P10]). Die Veröffentlichung der Modell-Spezifikation ermöglicht es Drittanbietern, die Implementation von Laufzeit- und Entwicklungsumgebungen selbst umzusetzen. Lösungen existieren beispielsweise von Bea Systems, Iona Technologies und IBM.

Der EJB-Container stellt die Laufzeitumgebung für die Enterprise Java Beans zur Verfügung. Dazu gehören eine Anzahl von Diensten, die durch die EJB-Spezifikation festgelegt oder vorgeschlagen werden (siehe Tabelle unten). Die Infrastruktur für den EJB-Container wird wiederum durch den EJB- Server bereitgestellt. Zu seinen Aufgaben gehören u.a. das Pooling von Datenverbindungen und die Thread-Verwaltung.

Tab. 1: Strukturbilanz EJB Dienste und Spezifikationen (Quelle [P10])

Ressourcenverwaltung Verwaltung und Zuteilung von benötigten Ressourcen. Dazu gehören beispielsweise der Hauptspeicher und die Kommunikationsverbindungen
Life Cycle Management Kreierung, Initiierung und Zerstörung von Bean-Instanzen
Transaktionsmanagement Bereitstellung von Mechanismen für die Transaktionsverwaltung
Security Dazu gehört u.a. Verschlüsselung von Kommunikation und Daten und die Authentifizierung von Nutzern und Nutzergruppen
Persistenz Lokales Speichern von EJB-Komponenten und Wiederherstellung nach Ausfällen (beispielsweise des Server-Rechners)
Distribution Verteilung der Enterprise Beans und Entkopplung von der zugrunde liegenden Netzwerkschicht.
Load balancing Aufteilung von Anfragen durch Clients auf gleichartige Enterprise-Beans

Die Enterprise Beans enthalten die Implementation der Business-Prozess Logik und die zugehörigen Daten. Sie existieren in drei Ausprägungen:

  • Session Beans enthalten die Anwendungslogik. Sie sind nicht persistent. In der Applikationsintegration werden sie oft benutzt, um den Zugriff auf bestehende Unternehmensanwendungen zu realisieren.
  • Entity Beans dienen zur Modellierung von Unternehmensdaten und dem Zugriff auf diese. Sie repräsentieren eine objektorientierte Sicht auf die zugrunde liegenden persistenten Daten.
  • Message driven Beans enthalten, wie die Session Beans, die Anwendungslogik mit dem Unterschied, dass die Kommunikation hier über Nachrichten abgewickelt wird.

Komponentenorientierte Middleware bietet umfassende Lösungen für die Probleme der EAI. Durch sie wird eine Integration auf Geschäftsprozess Ebene (Business-Prozess Level EAI) wesentlich vereinfacht oder erst ermöglicht (siehe [P10]).

Praktische Übungen 1: Parallel-Quicksort

Implementieren Sie ein Quicksort Programm in einem verteilten System. Das Prinzip des Quicksort Algorithmus basiert darauf, dass eine lange Liste von Daten in mehrere Teillisten unterteilt wird und diese Teillisten dann sortiert und wieder zusammengeführt werden. Wenn diese Teillisten nun parallel zueinander sortiert werden können, dann kann der Sortiervorgang weiter beschleunigt werden.

Beim „gewöhnlichen“ seriellen Quicksort geschieht folgendes: Um eine Folge F = k1,...,kN von N Elementen anhand des Quicksort Algorithmus der Größe nach zu sortieren, wählt man als erstes ein beliebiges Element k = {k1,...,kN}, das als Pivotelement verwendet wird. Anhand dieses Elements wird die Folge F in zwei Teilfolgen geteilt, wobei die erste Teilfolge nur Elemente beinhaltet die kleiner oder gleich k sind, die zweite Teilfolge nur Elemente die größer oder gleich k sind. Nun wird dieses Verfahren für die beiden Teilfolgen rekursiv wiederholt. Zuletzt werden alle Teilfolgen zusammengesetzt.

Der erste Schritt des parallelen Quicksorts ist identisch mit dem des seriellen. Man wählt aus der Folge F = k1,...,kN ein beliebiges Element k = {k1,...,kN} das als Pivotelement dient. Jetzt werden die Teilfolgen Subset 1 und Subset 2 nicht vom gleichen Prozess weiterverarbeitet, sondern jede Teilfolge wird an einen anderen Prozess geschickt. Dort werden die Teilfolgen wieder in Teilfolgen unterteilt und an weitere Prozesse verschickt. Dies geschieht so lange bis jeder Prozess im System in dem man sich befindet eine Teilfolge zur weiteren Verarbeitung zur Verfügung hat. Diese CPUs führen dann den seriellen Quicksort durch bis ihre Teilfolge sortiert ist und schicken dieses Ergebnis an die erste CPU. Sobald alle Ergebnisse zur Verfügung stehen ergeben diese dann die geordnete Folge F.

Details und weitere Erklärungen zum Quicksort Algorithmus finden Sie unter:

Die folgenden Übungsvarianten sollen mit Hilfe der Programmiersprache Java gelöst werden. Beantworten Sie auch die Frage, unter welchen Bedingungen Ihre Implementation eines Parallelen Algorithmus dem eines seriellen überlegen ist, also: Unter welchen Bedingungen ist ein verteilter Quicksort schneller als ein lokal-serieller. Die zu sortierende Liste soll aus einer Reihe zufällig erzeugter Zahlen bestehen. Beschreiben Sie Ihre Implementierung auf 3-5 Seiten.

Parallel Quicksort Implementierung mit Threads

Implementieren Sie den oben beschriebenen parallelen Quicksort Algorithmus in einem Java Programm. Dabei soll jede Teilliste in einem eigenen Thread implementiert werden. Am Ende der Sortiervorgänge sollen die Teillisten wieder zusammengeführt werden.

Information zu Java Threading finden unter anderem unter:

Parallel Quicksort Implementierung mit TCP/Sockets

Implementieren Sie den oben beschriebenen parallelen Quicksort Algorithmus in einem Java Programm. Dabei soll jede Teilliste in einem eigenen Java Programm sortiert werden. Die Java Programme sollen dabei die Teillisten mit Hilfe von einfachen TCP-Sockets verschicken. Am Ende der Sortiervorgänge sollen die Teillisten wieder zusammengeführt werden.

Information zur Java Socket Programmierung und Objekt-Serialisierung finden unter anderem unter:

Parallel Quicksort Implementierung via HTTP GET/POST

Implementieren Sie den oben beschriebenen parallelen Quicksort Algorithmus in einem Java Programm. Dabei soll jede Teilliste in einem eigenen Java Programm sortiert werden. Die Java Programme sollen dabei die Teillisten mit Hilfe von HTTP GET oder POST Requests verschicken. Am Ende der Sortiervorgänge sollen die Teillisten wieder zusammengeführt werden. Die fertig sortierten Teillisten können in der 200 OK Antwort-Nachricht zurückgegeben werden.

Bibliotheken und Dokumentation zur Verwendung von HTTP in Java finden unter anderem unter:

Parallel Quicksort Implementierung via XML-RPC

Implementieren Sie den oben beschriebenen parallelen Quicksort Algorithmus in einem Java Programm. Dabei soll jede Teilliste in einem eigenen Java Programm sortiert werden. Die Java Programme sollen dabei die Teillisten mit Hilfe des XML-RPC Protokolls austauschen. Am Ende der Sortiervorgänge sollen die Teillisten wieder zusammengeführt werden.

Bibliotheken und Dokumentation zur Verwendung von XML-RPC in Java finden unter anderem unter:

Parallel Quicksort Implementierung via Java RMI

Implementieren Sie den oben beschriebenen parallelen Quicksort Algorithmus in einem Java Programm. Dabei soll jede Teilliste in einem eigenen Java Programm sortiert werden. Die Java Programme sollen dabei die Teillisten mit Hilfe des XML-RPC Protokolls ausgetauscht werden. Am Ende der Sortiervorgänge sollen die Teillisten wieder zusammengeführt werden.

Informationen zur Verwendung von Java RMI finden unter anderem unter:

Praktische Übungen 2: Verteilte Datenspeicherung

Im Angesicht von populären Filesharing Diensten und P2P Netzwerken soll in dieser Übung eine sehr einfache Variante von verteilter Datenspeicherung implementiert werden. Dabei soll ein beliebiger Knoten in einem Netzwerk zwei verschiedene Befehle implementieren:

  • put_data(key, data)
  • data = get_data(key)

Dabei stellt der Parameter „key“ eine Zeichenkette (einen String) dar, welche Schlüssel benutzt, um die Daten, beschrieben durch die Variable „data“, ab zuspeichern und wiederzufinden. Der Schlüssel soll eindeutig sein. Der Einfachheit halber sollen auch die Daten durch eine Zeichenkette repräsentiert sein (für Fortgeschrittene könnte man dies erweitern, sodass ein beliebiges Objekt abgespeichert werden kann). Diese beiden Funktionen sollen in etwa so funktionieren wie die allseits bekannten Hashtables, assoziativen Arrays oder die sog. Dictionaries.

Nun sollen aber nicht alle Daten auf dem selben Rechner gespeichert werden. Dazu soll ein einfacher Verteilalgorithmus herangezogen werden, um die zu speichernden Daten auf verschiedene Rechner zu verteilen. Der einfachste Form eines sogenannten Hashalgorithmus könnte so aussehen:

Speichere alle Daten deren Schlüssel „key“ Zeichenkette beginnt mit

  • A,B,C, auf Rechner 1 abspeichern
  • D,E,F, auf Rechner 2
  • G,H,I auf Rechner 3 und so weiter bis Z

Sie können aber auch einen anderen Hash-Algorithmus verwenden, um die Daten zu verteilen.

Beim Implementieren müssen Sie nicht 8 Rechner einsetzen Es reicht, wenn alle Programm-Instanzen auf einem Rechner laufen, aber an verschiedenen Adressports lauschen. Dabei sollten 4 Instanzen ausreichend sein.

Sie müssen die zu Speichernden Daten dabei nicht persistieren, d.h. wenn Sie Ihr Programm beenden sind auch die Daten verloren (bei einem richtigen Produkt dürfte so was natürlich nicht passieren).

Verteilte Datenspeicherung via XML-RPC

Implementieren Sie die oben beschriebene verteilte Datenspeicherung in einem Java Programm. Die Java Programme sollen dabei die get_data() und put_data() Funktionen mit Hilfe des XML-RPC Protokolls realisieren.

Bibliotheken und Dokumentation zur Verwendung von XML-RPC in Java finden unter anderem unter:

Verteilte Datenspeicherung via Java RMI

Implementieren Sie die oben beschriebene verteilte Datenspeicherung in einem Java Programm. Die Java Programme sollen dabei die get_data() und put_data() Funktionen mit Hilfe von Java RMI realisieren.

Informationen zur Verwendung von Java RMI finden unter anderem unter:

Verteilte Datenspeicherung via SOAP

Implementieren Sie die oben beschriebene verteilte Datenspeicherung in einem Java Programm. Die Java Programme sollen dabei die get_data() und put_data() Funktionen mit Hilfe des SOAP Protokolls realisieren.

Bibliotheken und Dokumentation zur Verwendung von SOAP in Java finden unter anderem unter:

  1. Frei übersetzt nach Roger N. Needham (1989): „What’s different about distributed systems? They’re not centralised!“