WCF Cluster 1.0

Nach einiger Zeit, möchte ich jetzt endlich die erste Version von meinem WCF-Cluster Beispiel vorstellen. Wie man einen einfachen Client bauen kann hatte ich ja schon im vorigen Artikel geschrieben. Ich lade jetzt auch noch einen Command mit hoch, der Pi berechnet um mal ein richtiges Beispiel mit längerer Ausführungsdauer zu haben.

Der ganze Quellcode ist im Download mit drin, deshalb werde ich hier nicht viel reinkopieren. Das Distributor-Gerüst sieht so aus:

public class ComputingPowerDistributor : IComputingPowerDistributor
{
  public void ExecuteCommand(Stream input)
  {
      calculators.ElementAt(calculatorIndex).Value.ProducerExecuteCommand(input);
  }

  public void Connect()
  { 
     calculators[header.ClientAdress] = new ChannelFactory<IPowerProducerClient>(binding, new EndpointAddress(header.ClientAdress)).CreateChannel();
  }

  public void Disconnect()
  {
      calculators.Remove(header.ClientAdress);
  }
}

Die Producer/Calculator können sich an- und  abmelden, jeder Command, der von einem Consumer kommt wird an einen Producer weitergeleitet. Die Adressen und IDs werden im Header von der Nachricht übertragen.

Dann ist die Funktion von Producer/Consumer eigentlich nur noch Fleißarbeit. Einen WCF-Service im Code erstellen und die Methoden vom Distributor aufrufen. Der Producer ist ja immer gleich, deshalb habe ich dafür mal ein UI geschrieben, das im Moment so aussieht:

p1

Der Test-Conumer, der mitkommt sieht so aus:

p2

Der setzt 50 Commands ab, die bei der Pi-Berechnung mitmachen. Diese Commands werden der Reihe nach vom Distributor auf alle Calculator verteilt. Natürlich ist das noch nicht die Endlösung der Lastverteilung, aber zum Testen funktioniert es ganz gut.

Wenn man mit mehreren Computern arbeitet ist es wichtig vorher die Adresse vom Distributor zu ändern (im Moment als localhost), ansonsten sollte alles so funktionieren.

Als erstes muss man den Distributor Host starten, dann die Power Producer und den Consumer, die dll vom Command liegt schon im bin Verzeichnis.

Und hier ist der Link zum Download: Selen.Clustering

Free Hosting ASP.NET und WCF

Für einen .NET Entwickler ist es immer schön auch im Web mit C# hantieren zu können und nicht auf lästige Skripts zurückgreifen zu müssen. Es gibt ja nun Silverlight, aber wenn man nicht möchte, dass der Benutzer ein Plugin installieren muss, oder zum Beispiel einen WCF Service ins Netz stellen möchte, steht man vor einem Problem: Es gibt kaum freie Hoster auf denen ASP.NET läuft. Rein aus Interesse hab ich also mal gegoogelt und auch ein paar Server gefunden, die dann aber alle nach ein paar Monaten Geld haben wollten. Bis ich einen Hoster gefunden hab, der wirklich frei ist: somee.com. Free Hosting ASP.NET und WCF weiterlesen

Die Macht der Cluster

Letztens einen Artikel vom Spiegel gelesen, über Mieten von einem Cluster. Mich hat schon immer mal der Gedanke umgetrieben, dass meine Trainingsalgorithmen von NNSpace einfach viel zu langsam auf einem einzelnen Computer laufen. Es gibt ja auch viele andere Sachen, die man eigentlich gerne auf die Computer im ganzen Haus verteilen würde, zugegeben das geht nicht mit Allem aber ich denke das was Amazon hier zum Beispiel anbietet ist schon eine Richtung, die in Zukunft auch genutzt werden wird. So weit denk ich aber noch gar nicht, mir gehts vielmehr um das Prinzip. Es wäre doch mal interessant zu Testen ob man fähig ist so eine Clusterstruktur aufzubauen, jetzt mal ohne Amazon und 1000 Prozessoren, sondern einfach nur mit 2 oder 3 Computern im eigenen Haus. Letztendlich ist dann der Schritt (falls man das Aufteilen der Arbeit in 1000 Teile vorher schon erledigt hat) nicht mehr so groß zum Rechenzentrum. Es geht ja vielmehr um die Fähigkeit der Anwendung überhaupt auf irgend so einem System zu laufen.

  1. Ich glaube wir haben dabei erst mal zwei Typen von Teilnehmern, ich nenne sie jetzt mal Distributor(davon gibts einen) und Calculator(davon kann es unendlich viele geben). Das heißt jetzt nicht unbedingt, dass nicht auch mehrere solcher Typen auf derselben Maschine laufen können, aber wir brauchen irgendwie eine Instanz(Distributor), die Befehle vom Benutzer annimmt und die dann auf die Arbeitspferde(Calculator) verteilt.
  2. Dann ist noch ein Format nötig über das sich Distributor und Calculator unterhalten. Dabei denk ich jetzt nicht an irgendein Protokoll oder oder Ähnliches, das ist Implementierung und gehört nicht zur Architektur, sondern vielmehr die Art der Ergebnisse und Aufträge. Man muss dann eben immer beachten, dass die Übertragung eine kurze Weile dauert, und deshalb die Daten nicht zu oft gesendet werden dürfen und nicht zu groß sein dürfen.

Dabei ist selbstverständlich das Hauptproblem das Aufteilen der Arbeit, denn die Calculators sollten schon eine Weile zu Rechnen haben, bevor sie das Ergebnis zurückschicken, damit sich die ganze Sache lohnt.

Einen Anwendungsfall sehe ich hier zum Beispiel wenn man viele parallele Ausführungen von einem Netz durchführen möchte, mit dem Lernen sieht es hier schon etwas komplizierter aus, weil sich ja die Gewichte ständig ändern und deshalb immer hin und hergeschickt werden müssten. Letztendlich werde ich wohl zuerst über eine generelle Infrastruktur zum Zusammenschließen eines solchen Rechenclusters nachdenken müssen, die mein Netze-Programm dann benutzen kann. Aber diese Funktionen werden natürlich noch nicht mit der CTP 2 kommen, aber wenn sowas funktioniert, dann wäre das sicherlich ein Release für sich wert.

Jabber Update – Part 3

Jabber der dritte. Wir haben uns letztes Mal Gedanken darüber gemacht, wie der Client funktioniert, jetzt ist der Service dran. Zunächst wird eine Datenbank gebraucht, in der alle verfügbaren Updates gelistet werden. Dazu kommt eine Anwendung, die der Datenbank mit Schlüssel und dem genauen Verzeichnis auf der lokalen Platte, wo sich die Dateien für die entsprechende Installation befinden einen Eintrag hinzufügt. Die Anwendung wird, wenn sich irgendwas geändert hat einfach nochmal aufgerufen, und dann gibt der Server beim nächsten Update die neuen Infos zurück.

Dann gibt es einfach eine kleine Konsolenanwendung, die den Server startet(mittels AppSpace). Jetzt passiert der erste Schritt vom Update:

  • Step 1 – Benutzer klickt auf Update

Ok, der Benutzer will also seine Anwendung aktualisieren, der UpdateManager geht ins Netz, sucht sich den Service und schickt ein Telegramm mit den Informationen über die Anwendung, die gerade läuft. Der Service sucht nach dem Schlüssel in der Datenbank, und gibt die aktuelle Version der Anwendung an den Client zurück.

  • Step 2 – Updatebeginn

Der Client empfängt die Antwort, wenn die Version vom Service neuer ist als die eigene, wird ein Dialog angezeigt, und der Benutzer kann sich entscheiden, ob er das Update installieren möchte. Wenn das so ist, wird sofort ein weiteres Telegramm an den Service geschickt, mit der Bitte das Update zu starten. Sobald der Service diese Information erhält startet er intern eine Klasse mit einer eindutigen ID, die beginnt die Dateien auszulesen, und zunächst ein Telegramm zum erstellen neuer Dateien an den Client zurücksendet, was die ID enthält.

  • Step 3 – Update

Der Client erstellt die Dateien und schickt die ID wieder zurück. Dann werden auf dem Service nach und nach alle Bytes der Dateien gelesen und verschickt(immer 50kB in einer Nachricht). Zwischen dem Versenden dieser Nutzdatentelegramme wird zwischendurch immer wieder auf die Antwort des Clients gewartet, der die Dateien nach und nach auf die Platte schreibt und immer ein OK mit ID zurückliefert, was verhindert, dass die Nachrichten in der verkehrten Reihenfolge eintreffen, aber vor allem dafür sorgt, dass die Leitung nicht überfüllt wird, und der Client erst gar nichts erhält, und dann alles auf einmal. Denn wenn beispielsweise der Service alle Telegramme sofort mit einer Reihenfolgenummer losschicken würde, müssten alle Bytes gleichzeitig durch die Leitung, was bei größeren Dateien also mehreren Megabyte bis Gigabyte entsprechen würde. Es gäbe dann wahrscheinlich irgendwann ein Timeout, aber auf jeden Fall würde der Client zum Schluss mit einer Flut aus Nachrichten überschwemmt werden, die er gar nicht alle auf einmal bearbeiten kann. Ein Abbruch des Updates seitens des Clients wäre dann auch nicht möglich.

  • Step 4 – Ready

Der Server vermeldet die Fertigstellung des Updates nach dem letzten erfolgreich versandten Bytepacket. Dann startet der Client die Installer-Datei und die Installation kann beginnen!

Hier nochmal die Kommunikation im Detail:

Jabber Update – Part 2

Nochmal zurück zu Jabber und Updates. Wir wollen jetzt einen Schritt weiter gehen, von der grauen Theorie weg jetzt einfach mal eine Bibliothek implementieren, die die Update Funktion kapselt. Dazu brauchen wir zuerst ein API, was die Anwendung intern aufruft, um das Update durchzuführen. Wir beschäftigen uns also erst einmal mit der Client-Seite der ganzen Geschichte, und gehen jetzt mal davon aus, dass die Dateien schon auf dem Server registriert sind, und einfach als Bytes verschickt werden können, wenn der Client sie mit den Informationen zur Anwendung(Anwendungsname), über die diese identifiziert werden anfordert. Wie dann konkret der Service aussieht, darum kümmern wir uns später. Also erstellen wir doch einfach mal eine Klasse AppUpdateManager mit den Methoden BeginUpdate() und EndUpdate(). Wie man sicherlich schnell festellt handelt es sich hier um eine asynchrone Ausführung, logisch, weil ich als Anwender keine Lust hab die ganze Zeit eine blockierende Anwendung anzuschauen, während das Update läuft, und untätig rumzusitzen. So kann die Anwendung weiter verwendet werden, und das Update läuft einfach im Hintergrund ab. Wenn der Benutzer die Anwendung beendet kommt dann eben eine Message-Box, und fragt ihn, ob er das Update, wenn es noch nicht fertig ist, wirklich abbrechen will. Nur Pech, wenn die Anwendung abstürtzt ;-) Der UpdateManager kommuniziert dann über Jabber mit dem Server und lädt sich das Update in das aktuelle Temp Verzeichnis(vom aktuell angemeldeten User) runter. Dann startet er die MSI Datei(wieder asynchron, um dann noch sofort anschließend bevor die Installation überhaupt richtig gestartet ist noch den nächsten Schritt auszuführen), und löst dann ein Ereignis aus, auf was sich die Anwendung vorher registriert, und was diese beendet, da es wenig Spaß macht eine Anwendung frisch zu installieren, die gerade noch läuft. Soweit die Client Seite, es braucht jetzt nur noch der Code:

// Noch die aktuelle Assembly mitgeben, damit der UpdateManager weiß, was genau er aktualisieren soll
AppUpdateManager uManager = new AppUpdateManager(Assembly.GetExecutingAssembly());
uManager.Restart += delegate
{
    // hier irgendwie die Anwendung beenden
};
uManager.BeginUpdate();

eingefügt zu werden, und dann läuft das Update los. Allerdings sollte man peinlichst darauf achten, wenn die Anwendung geschlossen wird uManager.EndUpdate() aufzurufen, da sonst das Update im Hintergrund weiterläuft, was (vor allen Dingen wenn es dann fertig ist, und auf die tote Oberfläche zugreifen will) größere Komplikationen nach sich ziehen kann.
Im nächsten Teil geht es dann um die Serverseite, aber soweit erstmal:

Happy Jabber

Jabber my Updates

Mit dem Neuron Net Builder kommt auch die Update – Funktion über  das Internet.  Man könnte jetzt denken die laufen über den FTP Server, gänge wahrscheinlich auch schneller, aber es soll mal eine Lösung gefunden werden, bei der kein FTP, oder sonst ein Server aufgesetzt werden muss. Das heißt das Update basiert rein auf der Kommunikation von zwei Rechnern, nämlich  meinem Laptop, und dem Computer, von dem aus das Update durchgeführt wird.  Daraus ergibt sich allerdings das Problem, dass ich mit herkömmlichen Methoden(das heißt zum Beispiel  normales  http, oder tcp, oder  sonstwas) nur im lokalen Intranet kommunizieren kann, es sei denn ich registriere das Zeug im IIS, bezahl eine teure Domain, und so weiter. FTP Server aufsetzen ist also wesentlich billiger und  weniger aufwendig(falls man sich  mit einem freien zufrieden geben kann). Wir können unser Problem auf diese Art und Weise also nicht lösen. Wir brauchen also eine Kommunikation über das Internet, wobei sich der Computer, der das Update zieht mit irgend einem Server im Internet verbindet, den ein Williger ins Netz stellt. Dann muss ich  dort eine Session aufmachen, und alle Anfragen, die der Server vom Computer, der das Update zieht an meine Machine weiterleiten, und dann auf dem gleichen Umweg wieder zurückschicken. So brauch ich keinen Server aufzusetzen, sondern alles läuft über diese Zwischenstelle. OK, so was denk ich mir natürlich nicht aus, diese Lösung hat den Namen Jabber(oder XMPP = Extensible Messaging and Presence Protocol).

Das funktioniert also, bliebe noch zu klären, wie ich genau meine Anwendung jetzt verteile.

  1. Was wird verteilt
    Die  Installationsdateienen liegen als msi vor, die  noch  mit zusätzlichen Dateien übertragen werden müssen(normalerweise setup.exe)
  2. Wie wird das über die Leitung geschickt?
    Hier kommt die Open Source Bibliothek namens AppSpace von Xcoordination zum Einsatz, welche  das Versenden und Empfangen von Nachrichten via Jabber ermöglicht(sie selbst setzt auf der AgsXMPP  Bibliothek auf,  die die Jabber – Kommunikation allgemein kapselt). Die Frage ist nun, wie viele Bytes meiner Installationsdateien in solch einer Nachricht enthalten sein sollten. Es macht zum Beispiel keinen Sinn immer nur einige wenige Bytes zu versenden, da ja auch der Header der Nachricht, und alles zugehörige noch mitgeschickt werden muss. Ich habe einfach mal immer 50  kByte Nutzdaten  geschickt, der  Wert kann einfach als  Konstante im Programm geändert werden.
  3. Empfangen
    Dann werden die Bytes vom Empfänger empfangen, in irgend  ein temporäres Verzeichnis kopiert, und dann wird die  msi Datei ausgeführt.
  4. Fertige Updatefunktion ohne  FTP Server, eigene Website oder ähnliches