Rechenleistung auf Befehl – WCF Cluster

Hier hatte ich mir schon mal ein paar Gedanken zu Clustern und Rechenleistung gemacht. Jetzt hab ich die Idee ein bisschen ausgebaut und einen ersten Entwurf mit WCF umgesetzt.

1. Die Architektur

Ein Cluster baut sich aus drei Teilen auf, dem Client (fordert die Abarbeitung einer Aufgabe an), dem Distributor (verteilt die Aufgaben) und dem Calculator (arbeitet die Aufgaben tatsächlich ab). Dabei kann es beliebig viele Clients und Calcultors geben, aber (erst mal) nur einen Distributor.

Der Reihe nach passiert dann folgendes:

  1. Der Distributor startet
  2. Ein Calculator startet und verbindet sich mit dem Distributor
  3. Ein Client startet und übergibt dem Distributor eine Aufgabenstellung
  4. Der Distributor leitet die an den Calculator weiter
  5. Der Calculator erledigt die Aufgabe und schickt das Ergebnis direkt an den Client zurück

Aus Performancegründen schickt der Calculator sein Ergebnis direkt zum Client zurück.

cluster

2. Die Implementierung

Die Implementierung basiert auf WCF. Jeder der drei Teilnehmer ist ein eigenständiger WCF-Service. Das ist nötig, denn Streaming (was ich hier für nötig halte, weil man ja auch mal ein paar größere Aufgaben erledigen will) läuft über einen eigenen WCF-Transport Channel, wir können also keine Callbacks verwenden. Der Vorteil ist, dass der Client einfach seine Service-Adresse als string an den Distributor und der an den Calculator übermitteln kann und dann die direkte Verbindung von Calculator zu Client ganz einfach hergestellt werden kann. Ok, ich hab gesagt ich hab einen Entwurf, also Code, hier ist er:

 1: ComputingPowerConsumer powerConsumer = new ComputingPowerConsumer();
 2: powerConsumer.CommandExecuted += (operationID, output) =>
 3: {
 4:     Console.WriteLine(output);
 5: };
 6:
 7: powerConsumer.ExecuteCommand(SayHelloCommand.SayHelloCommandID, Guid.NewGuid().ToString(), null);
 8: Console.ReadLine();

Das ist alles, was nötig ist um einen Command/Aufgabe ans Cluster abzusetzen.

  1. Einen neuen PowerConsumer erstellen (Helper Klasse von mir)
  2. Auf das Event registrieren, wenn die Aufgabe fertig ist
  3. Aufgabe abschicken, alles was man braucht ist
    1. Eine Command ID (später mehr dazu)
    2. Eine Operation ID (wird einfach überall durchgeschleift und kommt am Ende im Event wieder rein, damit man weiß zu welchem Aufruf man gerade was empfängt)
    3. Ein object als Parameter, das dem Command zur Ausführung übergeben wird

Ja und was ist nun dieser Command? Eigentlich nur eine Klasse, die von IComputingPowerCommand (noch ein Baustein von mir) ableitet:

 1: public class SayHelloCommand : IComputingPowerCommand
 2: {
 3:     public const string SayHelloCommandID = "{D89930D2-06CD-4B9B-B09A-AE54CF7DD818}";
 4:
 5:     public string CommandID
 6:     {
 7:         get
 8:         {
 9:             return SayHelloCommandID;
 10:         }
 11:     }
 12:
 13:     public object Execute(object input)
 14:     {
 15:         return "Hello World!";
 16:     }
 17: }

Jeder Command hat eine Execute Methode, die das object vom Clientaufruf reingereicht bekommt und eine eindeutige ID, die der Client im Aufruf mitgibt. Die DLL in der sich der Command befindet muss in jedem bin-Verzeichnis von jedem Calculator sein, und das wars auch schon!

Das einzige was noch fehlt ist die Angabe der Distributor-Adresse in der App-Config und fertig ist der Cluster Client:

 1: <system.serviceModel>
 2:     <client>
 3:         <endpoint name="SRSIPowerConsumerDistributor1"
 4:                     address="net.tcp://winwf7:8002/DistributorService"
 5:                     binding="netTcpBinding"
 6:                     bindingConfiguration="streamedTcp"
 7:                     contract="Selen.Clustering.PowerDistributor.IPowerConsumerDistributor"/>
 8:     </client>
 9:     <bindings>
 10:         <netTcpBinding>
 11:             <binding name="streamedTcp" transferMode="Streamed">
 12:                 <reliableSession enabled="false" ordered="false"/>
 13:                 <security mode="None"/>
 14:             </binding>
 15:         </netTcpBinding>
 16:     </bindings>
 17:     <behaviors>
 18:         <serviceBehaviors>
 19:             <behavior name="IComputingPowerDistributorBehaviour">
 20:                 <serviceMetadata/>
 21:                 <serviceDebug includeExceptionDetailInFaults="true"/>
 22:             </behavior>
 23:         </serviceBehaviors>
 24:     </behaviors>
 25: </system.serviceModel>

Wer sich hier die Config-Datei mal genau anschaut sieht sicherlich den komischen Namen vom Distributor-Endpoint (“SRSIPowerConsumerDistributor1”), das hängt damit zusammen, dass die Verbindung zum Distributor intern über ein weiteres kleines WCF-Framework von mir aufgebaut wird, das es ermöglicht mehrere Endpoints anzugeben zwischen denen dann im Fall eines Fehlers automatisch umgeschaltet wird um eine hohe Ausfallsicherheit zu gewährleisten.

Leider bin ich noch nicht ganz so weit das ganze Framework zu veröffentlichen, in ein paar Tagen, gibt´s dann aber das Selen.Clusteing Framework 1.0 und noch einen Artikel zum Thema WCF und Ausfallsicherheit.

Veröffentlicht von

Winfried

Student TU Chemnitz

3 Gedanken zu „Rechenleistung auf Befehl – WCF Cluster“

  1. Hey Florian,
    sorry für die späte Antwort. Ich hoffe ich komme am Wochenende dazu endlich noch einen Artikel dazu veröffentlichen. Ich hab dir den aktuellen Stand vom Quellcode einfach mal raufgeladen: http://compositedevtec.tk/upload.zip. Du musst als erstes den Distributor Host als Admin starten, dann den Power Producer und den Consumer, die dll vom Command liegt schon im bin Verzeichnis.

    Viele Grüße
    Winfried

  2. Hallo,

    ich habe mir den Artikel durchgelesen und finde die Anregungen zum vernetzten Rechnen sehr interessant. Könntest du vielleicht ein Einfaches Programm dazu als Download bereitstellen, so dass ich mir die Funktionsweise noch mal genauer anschauen kann ?

Kommentare sind geschlossen.