Software verteilen ist keine leichte Sache. Muss das so sein? Nein, ich glaube nicht. Wir machen es uns nur selbst unnötig schwer, indem wir immer wieder und weiter versuchen, in verteilten Systemen genauso zu kommunizieren, wie in lokalen. Corba, DCOM, .NET Remoting, Webservices, WCF: sie stehen alle in derselben Tradition. Sie alle favorisieren die synchrone, methodenbasierte Kommunikation zwischen entfernten Funktionseinheiten. Ihr Credo: Wenn service.TueEtwas() lokal der Ausdruck eines Servicewunsches ist, dann sollte das auch in verteilten Systemen so sein.
Bei aller Nachrichtenorientierung, in der inzwischen WCF angekommen ist, halte ich das jedoch für falsch. Darüber habe ich auch schon ausführlich hier im Blog geschrieben. Nur wie können wir es anders machen?
Klar, es gibt Alternativen. Es gibt Technologien für asynchrone, nachrichtenorientierte, event-driven Architekturen. MSMQ/System.Messaging gehört dazu und aufbauend darauf z.B. Mass Transit oder NServiceBus. Von größeren und teureren Werkzeugen will ich gar nicht reden.
Trotz dieser Ansätze bin ich jedoch nicht zufrieden gewesen. Denn Messaging - obwohl das für die Verteilung "ehrlichere" Konzept als der Methodenaufruf - ist irgendwie auch einschränkend und immer etwas schwergewichtig. Die Einschränkung liegt im Fokus auf den "Röhren" zwischen Funktionseinheiten. Die halte ich aber für einen Sonderfall. Und die Schwergewichtigkeit liegt im API. Messaging ist eben eng verbunden mit MSMQ. Und Messaging konzentriert sich auf die Verteilung.
Nun bin ich froh, sagen zu können, dass meine Zufriedenheit gerade sehr gestiegen ist. Denn ein Projekt, an dem ich schon einige Zeit beteiligt bin, trägt nun erstmalig öffentliche Früchte. Zusammen mit der TU Wien kann ich im Rahmen der Xcoordination Unternehmung (www.xcoordination.com) bekannt geben, dass wir die erste CTP unseres Xcoordination Application Space (AppSpace) bei CodePlex veröffentlicht haben: http://xcoappspace.codeplex.com.
Nach Vorversuchen und Andeutungen ist nun live, wovon wir meinen, dass es das Verteilen von Software sehr viel einfacher machen kann. Der AppSpace ist damit einerseits tatsächlich als Ersatz für z.B. WCF gedacht - auf der anderen Seite lieben wir aber auch WCF.
WCF ist cool. WCF ist breit und tief und universell. Das ist super! Aber wir glauben nicht, dass WCF einen API bietet, den der Durchschnittsentwickler direkt nutzen sollte, um seine Software zu verteilen. Der Preis für WCFs Mächtigkeit ist schlicht Komplexität und damit geringe Usability.
Der AppSpace verbirgt diese Komplexität nun. Er bietet aufbauend auf WCF und anderen Kommunikationstechnologien einen API für die lokale wie die verteilte asynchrone Programmierung. Er abstrahiert von den Feinheiten der WCF.
Wir meinen, dass damit ein Sprung in der Verteilung von Software geschafft werden kann wie vom Win16/Win32 API zu VB1.0. 1990 konnte man Windows programmieren - aber es war sauschwer, mit dem Windows API in C direkt umzugehen. Nur Experten konnten also das Potenzial graphischer Benutzerschnittstellen ausnutzen.
Dann kam VB1.0 und alles wurde anders. Mit VB1.0 konnten plötzlich Millionen von Entwicklern graphische Benutzerschnittstellen programmieren. Dazu mussten Sie zwar gegenüber den bisherigen umdenken - Stichwort "Event-Driven UI" -, aber das war nicht so schlimm.
Ähnlich sehen wir den AppSpace. (Ein bisschen Größenwahn kann nie schaden, oder? ;-) Mit dem Programmiermodell des AppSpace hoffen wir auch, die Verteilung von Code einer viel größeren Gruppe von Entwicklern zugänglich zu machen.
Dazu ist zwar auch ein Umdenken nötig - Stichwort "Asynchrone Kommunikation" -, aber das wird hoffentlich nicht so schlimm. Vor allem ist der Gewinn doppelt, wenn man sich auf diesen Paradigmenwechsel von synchron nach asynchon einlässt. Nicht nur wird die Verteilung einfacher, man bekommt auch noch die lokale Parallelverarbeitung gleich dazu.
Und warum soll nun der AppSpace der Bringer sein gegenüber anderen Messaging-Technologien? Weil sich der AppSpace eben nicht nur um Messaging dreht. Messaging ist für ihn ein Sonderfall. Oder Messaging passiert für ihn "unten drunter".
Das zentrale Konzept beim AppSpace sind vielmehr Dienstleistungskomponenten. Er bleibt also so dicht wie möglich an der Objektorientierung und der synchronen Komponentenorientierung. Deshalb bietet er auch eine DI Container Schnittstelle. Er holt die Entwickler da ab, wo sie heute stehen: bei den synchronen Komponenten. Und dann bietet er ihnen schrittweise mehr. Zuerst unterstützt er sie auf der Basis der Microsoft Concurrency Runtime dabei, von lokal synchron auf lokal asynchron umzusteigen. Und dann unterstützt er sie beim Umstieg von lokal asynchron zu entfernt asynchron.
Das halten wir für eine natürliche Progression im Denken und in der Codierung. Wer gelernt hat, lokal asynchron zu programmieren, der hat viel weniger Probleme, wenn es dann an die Verteilung von Code geht. Mit dem AppSpace bekommt er die Verteilung dann sozusagen geschenkt.
Für die, die nun ganz gespannt darauf sind, wie denn der API des AppSpace aussieht, hier ein Codeschnippsel. Mehr gibt es bei CodePlex und demnächst in der dotnetpro. Auch Beispielprojekte werden wir bei CodePlex einstellen.
So sieht der Kontrakt eines ganz simplen asynchronen Dienstes aus, der z.B. eine Zeichenkette empfängt und serverseitig ausgibt. Das ist trivial von der Funktionalität her. An dieser Stelle möchte ich aber nur zeigen, wie schlank der AppSpace API ist.
Asynchrone Komponenten haben keine Methoden, die man direkt aufrufen könnte, sondern definieren einen Satz von Nachrichten (Message Contract), die sie über typisierte Microsoft CCR Ports empfangen.
using Microsoft.Ccr.Core;
using XcoAppSpace.Core;public class PPingContract : Port<string>
{}
Das ist die Implementation dies Kontraktes. Eine Klasse vom Kontrakt ableiten und für jede Nachricht eine Behandlungsroutine definieren:
public class PingService : PPingContract
{
[XcoConcurrent]
void ProcessPing(string text)
{
Console.WriteLine("processing: {0}", text);
}
}
Und jetzt der Host für die Serviceimplementation. Zwei Zeilen Code reichen aus. Die asynchrone Dienstleistung "läuft" in der Instanz eines Application Space:
using(XcoAppSpace host = new XcpAppSpace("tcp.port=9001"))
{
host.RunWorker<PPingContract, PingService>("pingservice");
Console.ReadLine(); // keep the host running while waiting for connections
}
Der Client ist dazu symmetrisch! Das ist einer der Vorzüge des AppSpace. Das macht ihn einfach zu bedienen, weil die Zahl der zu lernenden Konzepte so überschaubar ist:
using(XcoAppSpace client = new XcoAppSpace("tcp.port=0"))
{
PPingContract p = client.ConnectWorker<PPingContract>("localhost:9001/pingservice");p.Post("hello, world!");
Console.ReadLine(); // keep client alive
}
Das ist´s so ziemlich. Wenn Sie den Code verstanden haben (und die CCR Grundlagen kennen), dann können Sie mit dem AppSpace lokal asynchron oder verteilt asynchron arbeiten. Rückhabewerte, Notifikationen, Publish/Subscribe... das alles ist mit den immer gleichen Mitteln leicht zu realisieren. Schauen Sie mal bei CodePlex vorbei, wo ich dieses Beispiel noch etwas ausgebaut habe.
Laden Sie den AppSpace aus dem Download-Bereich herunter und spielen Sie mal damit. Ich freue mich über jedes Feedback. Bei allem Anspruch ist der AppSpace ja nicht fertig. Er ist erst am Anfang. Wir bei Xcoordination glauben aber, dass die Richtung stimmt. Wenn Sie wollen, gehen Sie in diese Richtung mit. Erste kommerzielle Projekte sind schon vorausgelaufen und melden zurück, dass es sich lohnt. Bei CodePlex und www.xcoordination.com gibt es viel Platz zum Diskutieren. Und außerdem ist der Application Space eine Open Source Software. Die können Sie aber sogar kostenlos in Ihren kommerziellen Closed Source Projekten einsetzen.
Also, auf ins Raumzeitalter mit dem Application Space! Verteilung die einfach funktioniert.
6 Kommentare:
Beim direkten Messaging mit MSMQ geht es um die "Röhre". Bei MasstTransit/ NServiceBus um den MessageBus.
Dort ist die Nachricht oder der Event im Fokus und nicht die Röhre. Man publiziert auf den Bus und die Infrastruktur kümmert sich um die richtige Röhre.
In der jetzigen Form vom XcoAppsSpace steht der Port im Vordergrund. Der Port ist doch aber genau die Röhre.
Ausserdem muss der Client sehr viel über den Service wissen: "localhost:9001/pingservice". Da wäre ein Publish/ Subscribe Mechanismus schön.
@Christian: Schön zusammengefasst: Röhre vs Event. Und bei WCF geht es um noch nicht mal um die Röhre, sondern um Aufforderungen per Brief.
Worum gehts bei AppSpace? Um die Röhre? Nein, genausowenig wie beim Bus. Beim Bus gibt es auch ein async Send() oder Post(). Dann kommt die Nachricht beim Bus eben auf einem Bus an, an den man sich als Abonnent hängen kann.
Der Port ist beim AppSpace nur ein Mittel, nicht die "Metapher". Im Gegensatz zum Bus kommt die Nachricht an einem konkreten Ort an, bei genau einem Adressdaten.
Der Trick ist nun: Bei MSMQ gibt es nur die Röhre. Beim Bus geht es um Abos. Und der AppSpace ist eine allgemeine Infrastruktur, mit der man beides bauen kann. Ein Worker am Ende eines Ports kann als Bus fungieren. Oder er kann ein Dienstleister sein. You choose.
In den Usage Demos zum AppSpace ist ein Beispiel, wie man mit dem AppSpace einen Bus bauen kann. Nicht perfekt, nur als Denkanstoß. Genauso ist ein Beispiel dabei, wie man damit einen Load Balancer bauen kann. Nicht perfekt, nur als Denkanstoß.
Publish/Subscribe? Nichts einfacher als das: Mit 2 Zeilen Code kann man jede async Komponente (Worker) in einen Publisher verwandeln. Und als Subscriber kann man serverseitige Nachrichtenfilter mit Lambda Expressions formulieren. Der AppSpace "remoted" diese Prädikate zum Publisher.
Der AppSpace ist insofern ein Bauskasten, also der Anfang und nicht das Ende.
In den nächsten Tagen werden wir auch wieder einen neuen Drop machen. Dann mit MSMQ-Transport und Named Pipe WCF Beispiel.
-Ralf
da der AppSpace eine XMPP Schnittstelle hat, und XMPP Publish Subscribe (Pubsub) unterstützt wäre es relativ einfach dies zu erweitern.
Oder wie Ralf schon sagt ist einfaches Pubsub mit wenigen Zeilen Code im aktuellen AppSpace schnell und einfach implementiert.
@Alexander: Ja, wir könnten mit dem Jabber Kommunikationsservice im AppSpace Pub/Sub von Jabber nutzen. Das machen wir aber bewusst nicht, um solche Patterns trnasportunabhängig zu halten. Wer sich für net.tcp oder net.pipe oder rohe TCP Sockets entscheidet, der soll genauso Pub/Sub nutzen können.
Aber es steht jedem frei, sich einen eigenen Jabber Kommunikationsservice zu schreiben, der Pub/Sub unterstützt (oder den vorhandenen aufbohren).
In einer Demo weichen wir von unserer Philosophie allerdings ab: da zeigen wir, wie man mit Jabber ganz einfach Load Balancing implementieren kann. Eine Zeile Code genügt, in der man die Priorität einer Space-Instanz der aktuellen Last anpasst. Der Jabber Server macht den Rest.
-Ralf
"Usage Demos zum AppSpace"
Die Demos würden mich interessieren. Nur finde ich CodePlex derzeit keinen Code. Suche ich an der falschen Stelle?
Oder soll ich geduldig abwarten?
@Christian: Nicht warten, herunterladen. Guckst du bei Releases! Hier die Usage Demos: http://xcoappspace.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=27799.
Im SVN Repo haben wir bei CodePlex noch nichts. Kommt aber auch noch.
-Ralf
Kommentar veröffentlichen