Tuesday 2 May 2017

Zeromq Handelssystem


Zeromq-dev Kann eine Trading-Plattform auf OslashMQ verlassen haben Ich habe eine finanzielle Austausch-Client wo (Markt) Daten müssen von einem Kern-Trading-System zu einem Lager über TCPIP übergeben werden. Was ich in dem Guide sehe, ist das in einigen seltenen Fällen MQ fällt Nachrichten still, wenn es keine offensichtliche Strategie für die Wiederherstellung von der Fehlerquote gibt. Offensichtlich können wir nicht zulassen, dass alle Nachrichten, die gelöscht werden, ignoriert werden. Ich gehe durch den Führer und spiele mit mehreren Mustern, um ein besseres Gefühl für MQ API und Philosophie zu haben, aber ich würde wirklich die Kenntnis von jemandem schätzen, der sich schon sehr kompetent mit dem Produkt fühlt, um mir einen Teil des Quoten-Öls zu retten: 1. Gibt es einen eingebauten Mechanismus zum Beispiel Starten Sie das Laden von Nachrichten auf die Festplatte, falls eine Warteschlange in der Nähe ist, um überlaufen zu werden oder einfach nur STOP, anstatt Nachrichten zu verwerfen. 2. Mad Black Box ist etwas, das am nächsten kommt, was wir brauchen, aber wir haben bereits Verleger selbst beschämt. Würde sie weiter in verschiedene Abonnenten abschneiden, um einen Quotsubscriber39s Overflowquot zu vermeiden (zB die Bearbeitungsseite wäre langsamer, da es vermutlich google protobufs deserialisiert und Nachrichten auf Festplatte aufnimmt) 3. Falls die Antwort auf 3 JA ist, ist kein zusätzliches (Z. B. ein Faden stirbt, etc.), in welchem ​​Fall gibt es eine Art von eingebauten Wiederherstellungs-Wiederholungsmechanismus (ähnlich wie PGM, aber ein bisschen ein höheres Niveau, da wir es zu tun haben ZMTP-Nachrichten) Suche Diskussionen Martin Sustrik Hi Anatoly, There39s ZMQSWAP Option in 2.x Versionen. Die Anwendung des Gegendrucks (quotSTOPquot) arbeitet vor REQREP - und PUSHPULL-Mustern. Mit PUBSUB kann das Anlegen von Gegendruck in Verbindung mit dem langsamen Teilnehmer zu unbegrenzten Latenzen führen, sogar zum Deadlock des gesamten Nachrichtenverteilungssystems. Ich denke, Sie sprechen hier von Marktdaten. Wenn der Publisher überlastet ist, denken Sie daran, eine komplexere Topologie mit Geräten in der Mitte zu schaffen, um die Last zu verteilen. Wenn der Punkt, der die Nachricht am 7. September 2011 um 6:51 Uhr speichert 1. Gibt es einen eingebauten Mechanismus, z. B. Starten Sie das Laden von Nachrichten auf die Festplatte, falls eine Warteschlange in der Nähe ist, um überlaufen zu werden oder einfach nur STOP, anstatt die Nachrichten stillzulegen. Es gibt keine ZMQSWAP-Option in 2.x-Versionen. Die Anwendung des Gegendrucks (quotSTOPquot) arbeitet vor REQREP - und PUSHPULL-Mustern. Mit PUBSUB kann das Anlegen von Gegendruck in Verbindung mit dem langsamen Teilnehmer zu unbegrenzten Latenzen führen, sogar zum Deadlock des gesamten Nachrichtenverteilungssystems. 2. Mad Black Box ist etwas, das am nächsten kommt, was wir brauchen, aber wir haben bereits Verleger selbst zerschlagen. Würde sie weiter in verschiedene Abonnenten abschneiden, wenn es darum geht, einen Quotsubscriber39s-Overflowquot zu vermeiden (z. B. die Verarbeitungsseite wäre langsamer, da es vermutlich google protobufs deserialisiert und Nachrichten auf Festplatte weitergibt), ich denke, du sprichst hier von Marktdaten. Wenn der Publisher überlastet ist, denken Sie daran, eine komplexere Topologie mit Geräten in der Mitte zu schaffen, um die Last zu verteilen. 3. Falls die Antwort auf 3 JA ist, führt kein zusätzliches internes Schütteln einen neuen Punkt des Versagens ein (z. B. ein Faden stirbt usw.), in welchem ​​Fall gibt es eine Art von eingebautem Wiederholungs-Wiederholungsmechanismus (ähnlich wie bei PGM, aber ein bisschen höheres Niveau, da es sich um ZMTP-Nachrichten handelt) Wenn der Punkt, der die Nachricht speichert, stirbt, geht die Nachricht verloren. Das gilt für PGM oder einen anderen Mechanismus. Die einzige Möglichkeit besteht darin, die Nachrichten auf einem Datenträger zu speichern, mit offensichtlicher Leistungsstrafe. Sogar dann, wenn die Platte stirbt, sind die Nachrichten verloren. Um zu verhindern, dass du sie auf RAID, SAN oder somesuch speichern musst. Wenn das ganze RAID zerstört wird usw. Am Freitag, den 7. September 2011 um 2:51 Uhr, schrieb Martin Sustrik: 1. Gibt es einen eingebauten Mechanismus, z. B. Starten Sie das Laden von Nachrichten auf die Festplatte, falls eine Warteschlange in der Nähe ist, um überlaufen zu werden oder einfach nur STOP, anstatt die Nachrichten stillzulegen. Es gibt keine ZMQSWAP-Option in 2.x-Versionen. Die Anwendung des Gegendrucks (quotSTOPquot) arbeitet vor REQREP - und PUSHPULL-Mustern. Mit PUBSUB kann das Anlegen von Gegendruck in Verbindung mit dem langsamen Teilnehmer zu unbegrenzten Latenzen führen, sogar zum Deadlock des gesamten Nachrichtenverteilungssystems. 2. Mad Black Box ist etwas, das am nächsten kommt, was wir brauchen, aber wir haben bereits Verleger selbst zerschlagen. Würde sie weiter in verschiedene Abonnenten abschneiden, wenn es darum geht, einen Quotsubscriber39s-Overflowquot zu vermeiden (z. B. die Verarbeitungsseite wäre langsamer, da es vermutlich google protobufs deserialisiert und Nachrichten auf Festplatte weitergibt), ich denke, du sprichst hier von Marktdaten. Wenn der Publisher überlastet ist, denken Sie daran, eine komplexere Topologie mit Geräten in der Mitte zu schaffen, um die Last zu verteilen. 3. Falls die Antwort auf 3 JA ist, führt kein zusätzliches internes Schütteln einen neuen Punkt des Versagens ein (z. B. ein Faden stirbt usw.), in welchem ​​Fall gibt es eine Art von eingebautem Wiederholungs-Wiederholungsmechanismus (ähnlich wie bei PGM, aber ein bisschen höheres Niveau, da es sich um ZMTP-Nachrichten handelt) Wenn der Punkt, der die Nachricht speichert, stirbt, geht die Nachricht verloren. Das gilt für PGM oder einen anderen Mechanismus. Die einzige Möglichkeit besteht darin, die Nachrichten auf einem Datenträger zu speichern, mit offensichtlicher Leistungsstrafe. Sogar dann, wenn die Platte stirbt, sind die Nachrichten verloren. Um zu verhindern, dass du sie auf RAID, SAN oder somesuch speichern musst. Wenn das ganze RAID zerstört wird usw. WARNUNG: Dieser Text ist veraltet und bezieht sich auf eine alte Version von MQ. Es bleibt hier für historisches Interesse. NICHT VERWENDEN DIESES ZU LERNEN MQ. Einleitung Da MQ in erster Linie dazu bestimmt ist, das Aktienhandelsgeschäft zu treiben, hat wir eine Musteranwendung erstellt, die die interne Arbeit einer Börse simuliert. Der Schwerpunkt dieses Beispiels liegt darin, zu zeigen, wie sich MQ in real-world-like Szenario befindet. Das folgende Diagramm zeigt die Architektur der Anwendung: Die Gateway-Komponente sollte Aufträge von Händlern über das Netzwerk (mit FIX-Protokoll oder einem bestimmten proprietären Protokoll) erhalten und Antworten an die Händler senden. Da die Beispielanwendung jedoch zeigen soll, was die möglichen Durchsatzmengen eines solchen Systems sind, erzeugt das Gateway zufällige Befehle, anstatt sie von den Händlern zu empfangen. Beim Start des Gateways können Sie die Anzahl der zu erzeugenden Aufträge pro Sekunde angeben. Matching-Einheit enthält den Kern der Börsengeschäftslogik. Es stimmt mit einem anderen zusammen und produziert Trades und Zitate. Unsere Implementierung ist minimalistisch, basierend auf Timeprice Matching Algorithmus (Implementierung pro rata Algorithmus ist als eine Übung für den Leser links). Dennoch hat der Algorithmus eine Komplexität von O (1) und ist stark optimiert. Weve gesehen, dass es etwa 18 Millionen Bestellungen pro Sekunde verarbeitet. Die Statistikkomponente empfängt Leistungsinformationen, die von Gateway und Matching Engine generiert werden, und zeigt sie in menschlich lesbarer Form an. Um das Lesen von Statistiken noch bequemer zu machen, ist einfaches grafisches Werkzeug im Beispiel enthalten. Leistung Nachfolgende Screenshots zeigen Beispiele Performance auf zwei High-End 8-Core (3GHz) Boxen mit jeweils 2 dedizierten 1GbE NICs. Denken Sie daran, dass, wenn Sie es auf der unterschriebenen und untuned Hardware laufen kann es immer noch ziemlich schnell, aber youll Erfahrung niedrigere Nachrichten-Durchsätze und mehr Latenz-Gipfel. Wenn Sie die Meldungsrate zu hoch einstellen, können Sie sogar einen Gatterausfall erleben, da die Tickerkomponente, die verwendet wird, um Aufträge an der stabilen Rate zu senden, nicht in der Lage sein wird, Schritt zu halten. Die gelbe Linie zeigt die Rundlauf-Latenz, d. H. Wie lange es dauert, bis die Bestellung vom Gateway zum passenden Motor übergeben wird, verarbeitet und die Auftragsbestätigung wieder an das Gateway sendet. In unserer Test-Latenz schwankte etwa 200 Mikrosekunden Durchschnitt. Die untere Durchgangslinie (900.000 Messagessecond) ist die Rate der Aufträge, die vom Gateway zum passenden Motor übergeben werden. Die obere Durchgangslinie (2.300.000 Messagessecond) ist die Rate der Auftragsbestätigungen, Trades und Aktienzitate, die von der passenden Engine zum Gateway übergeben wurden. Insgesamt haben wir etwa 3.200.000 Nachrichten pro Sekunde gesehen, die durch das Netzwerk gehen. Bauen Sie es, um das Beispiel zu bauen - Mit-Austausch-Option mit configure: Um das Grafik-Tool ausführen zu können, muss man Perl-Tk installiert haben (verpackt als perl-tk auf Debian) sowie Tk :: Graph von CPAN . Laufen es Zum Beispiel haben wir folgende Netzwerktopologie, um das Beispiel auszuführen. Boxen repräsentieren einzelne Maschinen, Pfeile stellen physikalische Kabel zwischen einzelnen Netzwerkschnittstellen dar (markiert durch ihre jeweiligen IP-Adressen): Es sind 3 Boxen (test01, test02 und test03) mit dem geschalteten Netzwerk mit entsprechenden IP-Adressen von 192.168.0.1, 192.168.0.2 verbunden Und 192.168.0.3. Darüber hinaus gibt es zwei direkte Verbindungen zwischen test02 und test03. Ein Anschluss verbindet die Netzwerkschnittstelle 10.0.0.1 auf test02 mit der Netzwerkschnittstelle 10.0.0.2 auf test03. Andere verbindet die Netzwerkschnittstelle 10.1.0.1 auf test02 mit der Netzwerkschnittstelle 10.1.0.2 auf test03. Gut laufen zmqserver und statistische Komponente auf test01, passender Motor auf test02 und Gateway auf test03. Nutzen Sie eine der direkten Verbindungen zwischen test02 und test03, um Aufträge vom Gateway zum passenden Motor zu übergeben und die andere, um Bestätigungen, Trades und Anführungsstriche von passendem Motor zu Gateway zu übergeben. Zuerst starten Sie zmqserver auf test01: Danach starten Sie die statistische Komponente auf test01. Die Parameter sind die Box, in der zmqserver läuft und die Netzwerkschnittstelle, um statistische Informationen zu erhalten: Alternativ können Sie die statistischen Daten an das Grafikwerkzeug weiterleiten: Starten Sie nun die passende Engine. Versorgung zmqserver s Hostname, Schnittstelle zum Empfangen von Nachrichten auf und Schnittstelle zum Senden von Nachrichten als Parameter: Schließlich führen Sie die Gatter. Versorgungsort von zmqserver und die Anzahl der Aufträge, die pro Sekunde als Parameter gesendet werden sollen: Fazit Exchange-Beispiel ermöglicht es Ihnen, die Leistung von MQs im realen Welt-Szenario zu testen. Allerdings ist eine stabile Latenz bei hohen Durchsätzen eine schwierige Angelegenheit abhängig von der Gesamtabstimmung Ihrer Hardware, Betriebssystem, Ausführungsumgebung etc. Wenn Sie ernsthaft über Leistungstests sind, kontaktieren Sie uns, um Ihnen bei der Aufgabe zu helfen. Geschrieben: 1218019882Y. m.e Revised: 1286694428Y. m.e Wenn Sie diese Seite nützlich fanden, bitte bewerten Sie es so, dass andere es finden werden. OslashMQ ist ein Messaging-System oder Message-orientierte Middleware, wenn Sie werden. Seine verwendet in Umgebungen so vielfältig wie Finanzdienstleistungen, Spiele-Entwicklung, eingebettete Systeme, akademische Forschung und Luft-und Raumfahrt. Messaging-Systeme arbeiten grundsätzlich als Instant Messaging für Anwendungen. Eine Anwendung entscheidet sich, ein Ereignis an eine andere Anwendung (oder mehrere Anwendungen) zu kommunizieren, es sammelt die zu sendenden Daten, trifft auf die Sende-Taste und da wir gomdashthe Messaging-System kümmert sich um den Rest. Im Gegensatz zu Instant Messaging, obwohl Messaging-Systeme haben keine GUI und übernehmen keine Menschen an den Endpunkten in der Lage, intelligente Intervention, wenn etwas schief geht. Messaging-Systeme müssen also sowohl fehlertolerant als auch viel schneller sein als herkömmliche Instant Messaging. OslashMQ wurde ursprünglich als ein ultra-schnelles Messaging-System für den Aktienhandel konzipiert und so war der Fokus auf extreme Optimierung. Im ersten Jahr des Projekts wurde die Benchmarking-Methodik entwickelt und versucht, eine möglichst effiziente Architektur zu definieren. Später, etwa im zweiten Jahr der Entwicklung, verlagerte sich der Fokus auf die Bereitstellung eines generischen Systems für den Aufbau verteilter Anwendungen und die Unterstützung von beliebigen Messaging-Mustern, verschiedene Transportmechanismen, willkürliche Sprachbindungen usw. Im dritten Jahr lag der Schwerpunkt vor allem auf der Verbesserung der Usability Und Abflachen der Lernkurve. Weve nahm die BSD Sockets API, versuchte, die Semantik der einzelnen Messaging-Muster aufzuräumen, und so weiter. Hoffentlich wird dieses Kapitel einen Einblick geben, wie die drei Ziele oben in die interne Architektur von OslashMQ übersetzt wurden, und bieten einige Tipps für diejenigen, die mit den gleichen Problemen kämpfen. Seit seinem dritten Jahr hat OslashMQ seine Codebasis überholt, es gibt eine Initiative zur Standardisierung der verwendeten Drahtprotokolle und eine experimentelle Implementierung eines OslashMQ-ähnlichen Messaging-Systems im Linux-Kernel usw. Diese Themen werden in diesem Buch nicht behandelt. Allerdings können Sie Online-Ressourcen für weitere Details zu überprüfen: 250bpmconcepts. Group. googlegroupsp-diskutieren-gruppe Und 250bpmhits. 24.1. Anwendung vs. Bibliothek OslashMQ ist eine Bibliothek, kein Messaging-Server. Es dauerte mehrere Jahre an AMQP-Protokoll arbeiten, eine Finanzindustrie versuchen, die Draht-Protokoll für Business MessagingMdashwriting eine Referenz-Implementierung für sie und die Teilnahme an mehreren großen Projekten stark auf Messaging technologymdashto erkennen, dass theres etwas falsch mit dem klassischen Clientserver-Modell Von Smart Messaging Server (Broker) und dumb Messaging Clients. Unser Hauptanliegen war damals mit der Leistung: Wenn theres ein Server in der Mitte ist, muss jede Nachricht das Netzwerk zweimal übergeben (vom Absender zum Broker und vom Broker zum Empfänger), was eine Strafe in Bezug auf die Latenz verursacht Und Durchsatz. Darüber hinaus, wenn alle Nachrichten durch den Broker geleitet werden, irgendwann ist es verpflichtet, der Engpass zu werden. Eine sekundäre Besorgnis war im Zusammenhang mit großflächigen Einsätzen: Wenn die Bereitstellung organisatorische Grenzen überschreitet, gilt das Konzept einer zentralen Behörde, die den gesamten Nachrichtenfluss verwaltet, nicht mehr. Kein Unternehmen ist bereit, die Kontrolle an einen Server in verschiedenen Unternehmen abzutreten gibt es Geschäftsgeheimnisse und theres gesetzliche Haftung. Das Ergebnis in der Praxis ist, dass theres ein Messaging-Server pro Unternehmen, mit handgeschriebenen Brücken, um es mit Messaging-Systeme in anderen Unternehmen zu verbinden. Das ganze Ökosystem ist also stark zersplittert, und die Aufrechterhaltung einer großen Anzahl von Brücken für jedes Unternehmen beteiligt macht die Situation nicht besser. Um dieses Problem zu lösen, benötigen wir eine vollständig verteilte Architektur, eine Architektur, in der jede Komponente möglicherweise von einer anderen Geschäftseinheit regiert werden kann. Da die Verwaltungseinheit in der Server-basierten Architektur der Server ist, können wir das Problem lösen, indem wir für jede Komponente einen separaten Server installieren. In einem solchen Fall können wir das Design weiter optimieren, indem wir den Server und die Komponente die gleichen Prozesse teilen. Was wir am Ende haben, ist eine Messaging-Bibliothek. OslashMQ wurde gestartet, als wir eine Idee hatten, wie man Messaging-Arbeit ohne einen zentralen Server macht. Es musste das gesamte Konzept der Messaging auf den Kopf stellen und das Modell eines autonomen zentralisierten Films von Nachrichten in der Mitte des Netzwerks mit einem intelligenten Endpunkt, einer dummen Netzwerkarchitektur, die auf dem End-to-End-Prinzip basiert, ersetzen. Die technische Konsequenz dieser Entscheidung war, dass OslashMQ von Anfang an eine Bibliothek war, keine Anwendung. Mittlerweile konnten wir beweisen, dass diese Architektur sowohl effizienter (niedrigere Latenz, höherer Durchsatz) als auch flexibler ist (es ist einfach, beliebige komplexe Topologien zu erstellen, anstatt an klassisches Hub-und-Speichen-Modell gebunden zu sein). Einer der unbeabsichtigten Konsequenzen war jedoch, dass die Entscheidung für das Bibliotheksmodell die Benutzerfreundlichkeit des Produkts verbessert hat. Immer wieder äußern sich die Nutzer über die Tatsache, dass sie keinen eigenständigen Messaging-Server installieren und verwalten müssen. Es stellt sich heraus, dass nicht mit einem Server eine bevorzugte Option ist, da es die Betriebskosten senkt (keine Notwendigkeit, einen Messaging-Server-Admin zu haben) und verbessert die Time-to-Market (keine Notwendigkeit, die Notwendigkeit zu verhandeln, um den Server mit dem Client zu führen Management oder das operative Team). Die Lektion gelernt ist, dass beim Start eines neuen Projektes, sollten Sie für die Bibliothek Design, wenn überhaupt möglich zu entscheiden. Es ist ziemlich einfach, eine Anwendung aus einer Bibliothek zu erstellen, indem sie es aus einem trivialen Programm aufruft, aber es ist fast unmöglich, eine Bibliothek aus einer vorhandenen ausführbaren Datei zu erstellen. Eine Bibliothek bietet den Nutzern viel mehr Flexibilität und schont ihnen gleichzeitig einen nicht-trivialen Verwaltungsaufwand. 24.2. Global State Globale Variablen spielen nicht gut mit Bibliotheken. Eine Bibliothek kann mehrmals in den Prozess geladen werden, aber auch dann gibt es nur einen einzigen Satz von globalen Variablen. Abbildung 24.1 zeigt eine OslashMQ-Bibliothek, die aus zwei verschiedenen und unabhängigen Bibliotheken verwendet wird. Die Anwendung verwendet dann beide Bibliotheken. Abbildung 24.1: OslashMQ wird von verschiedenen Bibliotheken verwendet Wenn eine solche Situation auftritt, greifen beide Instanzen von OslashMQ auf dieselben Variablen zu, was zu Racebedingungen, seltsamen Fehlern und undefiniertem Verhalten führt. Um dieses Problem zu vermeiden, hat die OslashMQ-Bibliothek keine globalen Variablen. Stattdessen ist ein Benutzer der Bibliothek verantwortlich für die Erstellung des globalen Zustands explizit. Das Objekt, das den globalen Zustand enthält, heißt Kontext. Während aus dem Benutzer Perspektive Kontext sieht mehr oder weniger wie ein Pool von Worker-Threads, aus OslashMQs Perspektive ist nur ein Objekt, um jeden globalen Zustand, den wir brauchen, um zu speichern. Im obigen Bild hätte libA einen eigenen Kontext und libB würde auch seine eigenen haben. Es wäre kein Weg für einen von ihnen, den anderen zu brechen oder zu untergraben. Die Lektion hier ist ziemlich offensichtlich: Verwenden Sie nicht den globalen Status in Bibliotheken. Wenn du es tust, ist die Bibliothek wahrscheinlich zu brechen, wenn es geschieht, zweimal im selben Prozess instanziiert zu werden. 24.3. Leistung Wenn OslashMQ gestartet wurde, war es vorrangig, die Leistung zu optimieren. Die Leistung von Messaging-Systemen wird mit zwei Metriken ausgedrückt: throughputmdashhow viele Nachrichten können während einer bestimmten Zeitspanne und Latencymdashhow übergeben werden, lange dauert es eine Nachricht, um von einem Endpunkt zum anderen zu kommen. Welche Metrik sollten wir konzentrieren auf Was ist die Beziehung zwischen den beiden Isnt es offensichtlich Führen Sie den Test, teilen Sie die Gesamtzeit des Tests durch die Anzahl der Nachrichten übergeben und was Sie erhalten, ist Latenz. Teilen Sie die Anzahl der Nachrichten nach der Zeit und was Sie bekommen, ist Durchsatz. Mit anderen Worten, Latenz ist der umgekehrte Wert des Durchsatzes. Trivial, rechts Anstatt sofort mit der Codierung zu beginnen, haben wir einige Wochen damit verbracht, die Performance-Metriken detailliert zu untersuchen und wir haben herausgefunden, dass die Beziehung zwischen Durchsatz und Latenz viel subtiler ist, und oft sind die Metriken ganz kontraintuitiv. Stellen Sie sich vor, dass Sie Nachrichten an B senden (siehe Abbildung 24.2.) Die Gesamtzeit des Tests beträgt 6 Sekunden. Es sind 5 Nachrichten vergangen. Daher beträgt der Durchsatz 0,83 msgs (56) und die Latenzzeit beträgt 1,2 Sek. (65), rechts Schau mal das Diagramm an. Es dauert eine andere Zeit für jede Nachricht von A nach B: 2 Sek., 2,5 Sek., 3 Sek., 3.5 Sek., 4 Sek. Der Durchschnitt ist 3 Sekunden, die ziemlich weit von unserer ursprünglichen Berechnung von 1,2 Sekunden entfernt ist. Dieses Beispiel zeigt die Missverständnisse, die Menschen intuitiv dazu neigen, über Performance-Metriken zu machen. Schauen Sie jetzt den Durchsatz an. Die Gesamtzeit des Tests beträgt 6 Sekunden. Allerdings dauert es bei A nur noch 2 Sekunden, um alle Nachrichten zu senden. Von der Perspektive ist der Durchsatz 2,5 msgs (52). Bei B dauert es 4 Sekunden, um alle Nachrichten zu empfangen. Also aus Bs Perspektive ist der Durchsatz 1,25 msgssec (54). Keiner dieser Zahlen entspricht unserer ursprünglichen Berechnung von 1,2 msgssec. Um eine lange Geschichte kurz, Latenz und Durchsatz sind zwei verschiedene Metriken, die viel ist offensichtlich. Das Wichtigste ist, den Unterschied zwischen den beiden und ihrer gegenseitigen Beziehung zu verstehen. Latenz kann nur zwischen zwei verschiedenen Punkten im System gemessen werden. Es gibt keine Latenz an Punkt A. Jede Nachricht hat ihre eigene Latenz. Sie können die Latenzen von mehreren Meldungen aber durchschnittlich nicht so latenz wie ein Stream von Nachrichten. Der Durchsatz dagegen kann nur an einem einzigen Punkt des Systems gemessen werden. Theres ein Durchsatz am Absender, theres ein Durchsatz am Empfänger, theres ein Durchsatz an jedem Zwischenpunkt zwischen den zwei, aber theres kein solches Gesamtdurchsatz des Gesamtsystems. Und Durchsatz sinnvoll nur für eine Reihe von Nachrichten theres keine solche Sache wie Durchsatz einer einzigen Nachricht. Was die Beziehung zwischen Durchsatz und Latenz anbelangt, so stellt sich heraus, dass es wirklich eine Beziehung gibt, aber die Formel beinhaltet Integrale und wir werden es hier nicht besprechen. Für weitere Informationen, lesen Sie die Literatur auf Warteschlange Theorie. Es gibt viele weitere Fallstricke bei der Benchmarking der Messaging-Systeme, die wir nicht weiter gehen in. Der Stress sollte eher auf die gelernte Lektion gestellt werden: Vergewissern Sie sich, dass Sie das Problem, das Sie lösen, verstehen. Sogar ein Problem, das so einfach ist, wie es schnell ist, kann viel Arbeit nehmen, um richtig zu verstehen. Was ist mehr, wenn Sie das Problem nicht verstehen, sind Sie wahrscheinlich implizite Annahmen und populäre Mythen in Ihren Code zu bauen, so dass die Lösung entweder fehlerhaft oder zumindest viel komplexer oder viel weniger nützlich als es möglich sein könnte. 24.4. Critical Path Wir haben während des Optimierungsprozesses entdeckt, dass drei Faktoren einen entscheidenden Einfluss auf die Leistung haben: Anzahl der Speicherzuweisungen Anzahl der Systemaufrufe Gleichzeitigkeitsmodell Allerdings hat nicht jede Speicherzuteilung oder jeder Systemaufruf die gleiche Wirkung auf die Leistung. Die Leistung, die wir an Messaging-Systemen interessieren, ist die Anzahl der Nachrichten, die wir zwischen zwei Endpunkten während einer bestimmten Zeitspanne übertragen können. Alternativ können wir auch daran interessiert sein, wie lange es dauert, bis eine Nachricht von einem Endpunkt zum anderen kommt. Angesichts der Tatsache, dass OslashMQ für Szenarien mit langlebigen Verbindungen konzipiert ist, ist die Zeit, die es braucht, um eine Verbindung herzustellen oder die Zeit, die benötigt wird, um einen Verbindungsfehler zu behandeln, grundsätzlich irrelevant. Diese Ereignisse passieren sehr selten und ihre Auswirkungen auf die Gesamtleistung sind vernachlässigbar. Der Teil einer Codebasis, die sehr häufig verwendet wird, immer und immer wieder, heißt die kritische Pfadoptimierung sollte sich auf den kritischen Pfad konzentrieren. Lasst uns ein Beispiel ansehen: OslashMQ ist in Bezug auf Speicherzuweisungen nicht extrem optimiert. Zum Beispiel, wenn man Strings manipuliert, gibt es oft eine neue Zeichenfolge für jede Zwischenphase der Transformation. Allerdings, wenn wir streng auf die kritische pathmdashthe tatsächliche Nachricht passingmdashwell finden heraus, dass es fast keine Speicherzuweisungen verwendet. Wenn die Meldungen klein sind, ist nur eine Speicherzuweisung pro 256 Meldungen (diese Meldungen werden in einem einzigen großen zugeordneten Speicher-Chunk gehalten). Wenn außerdem der Nachrichtenstrom stetig ist, ohne große Verkehrsspitzen, sinkt die Anzahl der Speicherzuweisungen auf den kritischen Pfad auf Null (die zugeteilten Speicherblöcke werden nicht an das System zurückgegeben, sondern wieder und wieder verwendet) . Lektion gelernt: optimieren, wo es den Unterschied macht. Die Optimierung von Code-Teilen, die nicht auf dem kritischen Pfad sind, ist verschwendete Anstrengung. 24.5. Zuweisung von Speicher Unter der Annahme, dass alle Infrastruktur initialisiert wurde und eine Verbindung zwischen zwei Endpunkten aufgebaut wurde, gibt es nur eine Sache, die beim Senden einer Nachricht zuzuordnen ist: die Nachricht selbst. Um also den kritischen Weg zu optimieren, mussten wir untersuchen, wie die Nachrichten vergeben und den Stack hin - und hergeschoben werden. Sein gemeinsames Wissen im leistungsstarken Netzwerkbereich, dass die beste Leistung erzielt wird, indem die Kosten der Nachrichtenvergabe sorgfältig ausgeglichen werden und die Kosten für das Nachrichtenkopieren (z. B. hal. inria. frdocs00292831PDFOpen-MX-IOAT. pdf) Kleine, mittlere und große Nachrichten). Für kleine Nachrichten ist das Kopieren viel günstiger als das Speichern von Speicher. Es ist sinnvoll, keine neuen Speicherblöcke zuzuordnen und stattdessen die Nachricht an den vorab zugewiesenen Speicher zu kopieren, wann immer es benötigt wird. Bei großen Meldungen dagegen ist das Kopieren viel teurer als die Speicherzuweisung. Es ist sinnvoll, die Nachricht einmal zuzuordnen und einen Zeiger auf den zugewiesenen Block zu übergeben, anstatt die Daten zu kopieren. Dieser Ansatz heißt null-Kopie. OslashMQ behandelt beide Fälle transparent. Eine OslashMQ-Nachricht wird durch einen undurchsichtigen Griff dargestellt. Der Inhalt von sehr kleinen Nachrichten wird direkt im Handle codiert. So macht eine Kopie des Griffs tatsächlich die Meldungsdaten. Wenn die Nachricht größer ist, wird ihr in einem separaten Puffer zugewiesen und der Handle enthält nur einen Zeiger auf den Puffer. Das Erstellen einer Kopie des Handles führt nicht zum Kopieren der Meldungsdaten, was sinnvoll ist, wenn die Nachricht megabyte lang ist (Abbildung 24.3). Es ist anzumerken, dass im letzteren Fall der Puffer Referenzzähler ist, so dass er von mehreren Griffen referenziert werden kann, ohne dass die Daten kopiert werden müssen. Lektion gelernt: Wenn man über die Leistung nachdenkt, geht man nicht davon aus, dass es eine einzige beste Lösung ist. Es kann vorkommen, dass es mehrere Unterklassen des Problems gibt (z. B. kleine Nachrichten gegen große Nachrichten), die jeweils einen eigenen optimalen Algorithmus haben. 24.6 Batching Es wurde bereits erwähnt, dass die schiere Anzahl von Systemaufrufen in einem Messaging-System zu einem Performance-Engpass führen kann. Eigentlich ist das Problem viel generischer als das. Theres eine nicht-triviale Performance-Strafe im Zusammenhang mit der Durchquerung der Call-Stack und damit bei der Erstellung von High-Performance-Anwendungen, seine klug, um so viel Stapel-Traversierung wie möglich zu vermeiden. Siehe Abbildung 24.4. Um vier Meldungen zu senden, musst du den gesamten Netzwerkstapel viermal durchqueren (d. H. OslashMQ, glibc, userkernel Raumgrenze, TCP-Implementierung, IP-Implementierung, Ethernet-Schicht, die NIC selbst und den Stapel wieder). Wenn Sie sich jedoch entscheiden, diese Nachrichten zu einem einzigen Batch zu machen, würde es nur einen Traversal des Stapels geben (Abbildung 24.5). Die Auswirkung auf den Nachrichtendurchsatz kann überwältigend sein: bis zu zwei Größenordnungen, besonders wenn die Meldungen klein sind und Hunderte von ihnen in einer einzigen Charge verpackt werden können. Auf der anderen Seite kann das Batching negative Auswirkungen auf die Latenz haben. Nehmen wir zum Beispiel den bekannten Nagles-Algorithmus, wie er in TCP implementiert ist. Es verzögert die ausgehenden Nachrichten für eine gewisse Zeit und fügt alle akkumulierten Daten in ein einzelnes Paket zusammen. Offensichtlich ist die End-to-End-Latenz der ersten Nachricht im Paket viel schlechter als die Latenz des letzten. So ist es üblich für Anwendungen, die eine gleichbleibend geringe Latenz benötigen, um den Nagles-Algorithmus auszuschalten. Es ist sogar üblich, das Batching auf allen Ebenen des Stapels auszuschalten (z. B. NICs unterbrechen die Koaleszenzfunktion). Aber auch hier bedeutet kein Batching ein umfangreiches Durchqueren des Stapels und führt zu einem geringen Meldungsdurchsatz. Wir scheinen in einem Durchsatz gegen Latenz Dilemma gefangen zu werden. OslashMQ versucht, konsequent niedrige Latenzen in Verbindung mit hohem Durchsatz mit der folgenden Strategie zu liefern: Wenn der Nachrichtenfluss spärlich ist und die Netzwerk-Stapel-Bandbreite nicht überschreitet, macht OslashMQ alle Batch-Offs, um die Latenz zu verbessern. Der Kompromiss hier ist etwas höher CPU-Auslastung müssen noch den Stapel häufig durchqueren. Allerdings ist das nicht in den meisten Fällen ein Problem. Wenn die Meldungsrate die Bandbreite des Netzwerkstapels übersteigt, müssen die Meldungen im Speicher hochgeladen werden, bis der Stack bereit ist, sie zu akzeptieren. Queuing bedeutet, dass die Latenz wächst. Wenn die Nachricht eine Sekunde in der Warteschlange verbringt, wird die End-to-End-Latenz mindestens eine Sekunde lang sein. Was noch schlimmer ist, wenn die Größe der Warteschlange wächst, werden die Latenzen allmählich zunehmen. Wenn die Größe der Warteschlange nicht gebunden ist, kann die Latenz überschritten werden. Es wurde beobachtet, dass, obwohl der Netzwerkstapel für eine möglichst geringe Latenz abgestimmt ist (der Nagles-Algorithmus ausgeschaltet ist, die NIC-Interrupt-Koaleszenz ausgeschaltet usw.). Die Latenzen können trotz der Warteschlangeneffekte, wie oben beschrieben, immer noch düster sein. In solchen Situationen ist es sinnvoll, aggressiv zu starten. Es gibt nichts zu verlieren, da die Latenzen sowieso schon hoch sind. Auf der anderen Seite verbessert die aggressive Batching den Durchsatz und kann die Warteschlange der anstehenden Meldungen entfernen, was wiederum bedeutet, dass die Latenz allmählich sinkt, wenn die Warteschlangenverzögerung abnimmt. Sobald es keine herausragenden Meldungen in der Warteschlange gibt, kann die Batchierung ausgeschaltet werden, um die Latenz noch weiter zu verbessern. Eine weitere Beobachtung ist, dass die Batching nur auf der obersten Ebene erfolgen sollte. Wenn die Meldungen dort gebootet werden, haben die unteren Ebenen sowieso nichts zu batch, und so haben alle Batch-Algorithmen darunter nichts als zusätzliche Latenz. Lektion gelernt: Um einen optimalen Durchsatz zu erzielen, kombiniert mit einer optimalen Reaktionszeit in einem asynchronen System, schalten Sie alle Batching-Algorithmen auf den niedrigen Schichten des Stapels und Batch auf der obersten Ebene aus. Batch nur, wenn neue Daten schneller ankommen, als sie verarbeitet werden können. 24.7 Architekturübersicht Bis zu diesem Punkt haben wir uns auf generische Prinzipien konzentriert, die OslashMQ schnell machen. Von nun an sehen wir uns die eigentliche Architektur des Systems an (Abbildung 24.6). Der Benutzer interagiert mit OslashMQ mit so genannten Sockets. Sie sind ziemlich ähnlich wie TCP-Sockets, der Hauptunterschied ist, dass jeder Socket kann die Kommunikation mit mehreren Peers, ein bisschen wie ungebunden UDP-Sockets zu behandeln. Das Socket-Objekt lebt im User-Thread (siehe die Diskussion der Threading-Modelle im nächsten Abschnitt). Abgesehen davon führt OslashMQ mehrere Worker-Threads aus, die den asynchronen Teil der Kommunikation behandeln: Daten aus dem Netzwerk lesen, Nachrichten migrieren, eingehende Verbindungen akzeptieren usw. Es gibt verschiedene Objekte, die in den Worker-Threads leben. Jedes dieser Objekte gehört zu genau einem übergeordneten Objekt (das Eigentumsrecht wird durch eine einfache Vollzeile im Diagramm gekennzeichnet). Das Elternteil kann in einem anderen Faden leben als das Kind. Die meisten Objekte sind direkt im Besitz von Steckdosen, aber es gibt paar Fälle, in denen ein Objekt im Besitz eines Objekts ist, das im Besitz der Steckdose ist. Was wir bekommen, ist ein Baum von Objekten, mit einem solchen Baum pro Sockel. Der Baum wird während des Herunterfahrens benutzt Kein Objekt kann sich schließen, bis es alle seine Kinder schließt. Auf diese Weise können wir sicherstellen, dass der Shutdown-Prozess wie erwartet beispielsweise funktioniert, dass ausstehende ausgehende Nachrichten vor dem Beenden des Sendevorgangs an das Netzwerk gedrückt werden. Grob gesprochen gibt es zwei Arten von asynchronen Objekten gibt es Objekte, die nicht in Nachrichtenübergabe beteiligt sind und es gibt Objekte, die sind. Erstere müssen vor allem mit dem Verbindungsmanagement arbeiten. Beispielsweise hört ein TCP-Listener-Objekt auf eingehende TCP-Verbindungen und erstellt für jede neue Verbindung ein Enginesession-Objekt. Ähnlich versucht ein TCP-Connector-Objekt, eine Verbindung zum TCP-Peer herzustellen, und wenn es ihm gelingt, erzeugt es ein Enginesession-Objekt, um die Verbindung zu verwalten. Wenn eine solche Verbindung fehlschlägt, versucht das Connector-Objekt, es wiederherzustellen. Letztere sind Objekte, die die Datenübertragung selbst abwickeln. Diese Objekte bestehen aus zwei Teilen: Das Session-Objekt ist für die Interaktion mit der OslashMQ-Sockel verantwortlich und das Motorobjekt ist für die Kommunikation mit dem Netzwerk verantwortlich. Theres nur eine Art des Session-Objekts, aber theres ein anderer Motortyp für jedes zugrunde liegende Protokoll OslashMQ unterstützt. Thus, we have TCP engines, IPC (inter-process communication) engines, PGM engines (a reliable multicast protocol, see RFC 3208), etc. The set of engines is extensiblemdashin the future we may choose to implement, say, a WebSocket engine or an SCTP engine. The sessions are exchanging messages with the sockets. There are two directions to pass messages in and each direction is handled by a pipe object. Each pipe is basically a lock-free queue optimized for fast passing of messages between threads. Finally, theres a context object (discussed in the previous sections but not shown on the diagram) that holds the global state and is accessible by all the sockets and all the asynchronous objects. 24.8. Concurrency Model One of the requirements for OslashMQ was to take advantage of multi-core boxes in other words, to scale the throughput linearly with the number of available CPU cores. Our previous experience with messaging systems showed that using multiple threads in a classic way (critical sections, semaphores, etc.) doesnt yield much performance improvement. In fact, a multi-threaded version of a messaging system can be slower than a single-threaded one, even if measured on a multi-core box. Individual threads are simply spending too much time waiting for each other while, at the same time, eliciting a lot of context switching that slows the system down. Given these problems, weve decided to go for a different model. The goal was to avoid locking entirely and let each thread run at full speed. The communication between threads was to be provided via asynchronous messages (events) passed between the threads. This, as insiders know, is the classic actor model . The idea was to launch one worker thread per CPU coremdashhaving two threads sharing the same core would only mean a lot of context switching for no particular advantage. Each internal OslashMQ object, such as say, a TCP engine, would be tightly bound to a particular worker thread. That, in turn, means that theres no need for critical sections, mutexes, semaphores and the like. Additionally, these OslashMQ objects wont be migrated between CPU cores so would thus avoid the negative performance impact of cache pollution (Figure 24.7 ). This design makes a lot of traditional multi-threading problems disappear. Nevertheless, theres a need to share the worker thread among many objects, which in turn means there has to be some kind of cooperative multitasking. This means we need a scheduler objects need to be event-driven rather than being in control of the entire event loop we have to take care of arbitrary sequences of events, even very rare ones we have to make sure that no object holds the CPU for too long etc. In short, the whole system has to become fully asynchronous. No object can afford to do a blocking operation, because it would not only block itself but also all the other objects sharing the same worker thread. All objects have to become, whether explicitly or implicitly, state machines. With hundreds or thousands of state machines running in parallel you have to take care of all the possible interactions between them andmdashmost importantlymdashof the shutdown process. It turns out that shutting down a fully asynchronous system in a clean way is a dauntingly complex task. Trying to shut down a thousand moving parts, some of them working, some idle, some in the process of being initiated, some of them already shutting down by themselves, is prone to all kinds of race conditions, resource leaks and similar. The shutdown subsystem is definitely the most complex part of OslashMQ. A quick check of the bug tracker indicates that some 30--50 of reported bugs are related to shutdown in one way or another. Lesson learned: When striving for extreme performance and scalability, consider the actor model its almost the only game in town in such cases. However, if you are not using a specialised system like Erlang or OslashMQ itself, youll have to write and debug a lot of infrastructure by hand. Additionally, think, from the very beginning, about the procedure to shut down the system. Its going to be the most complex part of the codebase and if you have no clear idea how to implement it, you should probably reconsider using the actor model in the first place. 24.9. Lock-Free Algorithms Lock-free algorithms have been in vogue lately. They are simple mechanisms for inter-thread communication that dont rely on the kernel-provided synchronisation primitives, such as mutexes or semaphores rather, they do the synchronisation using atomic CPU operations, such as atomic compare-and-swap (CAS). It should be understood that they are not literally lock-freemdashinstead, locking is done behind the scenes on the hardware level. OslashMQ uses a lock-free queue in pipe objects to pass messages between the users threads and OslashMQs worker threads. There are two interesting aspects to how OslashMQ uses the lock-free queue. First, each queue has exactly one writer thread and exactly one reader thread. If theres a need for 1-to - N communication, multiple queues are created (Figure 24.8 ). Given that this way the queue doesnt have to take care of synchronising the writers (theres only one writer) or readers (theres only one reader) it can be implemented in an extra-efficient way. Second, we realised that while lock-free algorithms were more efficient than classic mutex-based algorithms, atomic CPU operations are still rather expensive (especially when theres contention between CPU cores) and doing an atomic operation for each message written andor each message read was slower than we were willing to accept. The way to speed it upmdashonce againmdashwas batching. Imagine you had 10 messages to be written to the queue. It can happen, for example, when you received a network packet containing 10 small messages. Receiving a packet is an atomic event you cannot get half of it. This atomic event results in the need to write 10 messages to the lock-free queue. Theres not much point in doing an atomic operation for each message. Instead, you can accumulate the messages in a pre-write portion of the queue thats accessed solely by the writer thread, and then flush it using a single atomic operation. The same applies to reading from the queue. Imagine the 10 messages above were already flushed to the queue. The reader thread can extract each message from the queue using an atomic operation. However, its overkill instead, it can move all the pending messages to a pre-read portion of the queue using a single atomic operation. Afterwards, it can retrieve the messages from the pre-read buffer one by one. Pre-read is owned and accessed solely by the reader thread and thus no synchronisation whatsoever is needed in that phase. The arrow on the left of Figure 24.9 shows how the pre-write buffer can be flushed to the queue simply by modifying a single pointer. The arrow on the right shows how the whole content of the queue can be shifted to the pre-read by doing nothing but modifying another pointer. Lesson learned: Lock-free algorithms are hard to invent, troublesome to implement and almost impossible to debug. If at all possible, use an existing proven algorithm rather than inventing your own. When extreme performance is required, dont rely solely on lock-free algorithms. While they are fast, the performance can be significantly improved by doing smart batching on top of them. 24.10. API The user interface is the most important part of any product. Its the only part of your program visible to the outside world and if you get it wrong the world will hate you. In end-user products its either the GUI or the command line interface. In libraries its the API. In early versions of OslashMQ the API was based on AMQPs model of exchanges and queues. (See the AMQP specification .) From a historical perspective its interesting to have a look at the white paper from 2007 that tries to reconcile AMQP with a brokerless model of messaging. I spent the end of 2009 rewriting it almost from scratch to use the BSD Socket API instead. That was the turning point OslashMQ adoption soared from that point on. While before it was a niche product used by a bunch of messaging experts, afterwards it became a handy commonplace tool for anybody. In a year or so the size of the community increased tenfold, some 20 bindings to different languages were implemented, etc. The user interface defines the perception of a product. With basically no change to the functionalitymdashjust by changing the APImdashOslashMQ changed from an enterprise messaging product to a networking product. In other words, the perception changed from a complex piece of infrastructure for big banks to hey, this helps me to send my 10-byte-long message from application A to application B. Lesson learned: Understand what you want your project to be and design the user interface accordingly. Having a user interface that doesnt align with the vision of the project is a 100 guaranteed way to fail. One of the important aspects of the move to the BSD Sockets API was that it wasnt a revolutionary freshly invented API, but an existing and well-known one. Actually, the BSD Sockets API is one of the oldest APIs still in active use today it dates back to 1983 and 4.2BSD Unix. Its been widely used and stable for literally decades. The above fact brings a lot of advantages. Firstly, its an API that everybody knows, so the learning curve is ludicrously flat. Even if youve never heard of OslashMQ, you can build your first application in couple of minutes thanks to the fact that you are able to reuse your BSD Sockets knowledge. Secondly, using a widely implemented API enables integration of OslashMQ with existing technologies. For example, exposing OslashMQ objects as sockets or file descriptors allows for processing TCP, UDP, pipe, file and OslashMQ events in the same event loop. Another example: the experimental project to bring OslashMQ-like functionality to the Linux kernel turned out to be pretty simple to implement. By sharing the same conceptual framework it can re-use a lot of infrastructure already in place. Thirdly and probably most importantly, the fact that the BSD Sockets API survived almost three decades despite numerous attempts to replace it means that there is something inherently right in the design. BSD Sockets API designers havemdashwhether deliberately or by chancemdashmade the right design decisions. By adopting the API we can automatically share those design decisions without even knowing what they were and what problem they were solving. Lesson learned: While code reuse has been promoted from time immemorial and pattern reuse joined in later on, its important to think of reuse in an even more generic way. When designing a product, have a look at similar products. Check which have failed and which have succeeded learn from the successful projects. Dont succumb to Not Invented Here syndrome. Reuse the ideas, the APIs, the conceptual frameworks, whatever you find appropriate. By doing so you are allowing users to reuse their existing knowledge. At the same time you may be avoiding technical pitfalls you are not even aware of at the moment. 24.11. Messaging Patterns In any messaging system, the most important design problem is that of how to provide a way for the user to specify which messages are routed to which destinations. There are two main approaches, and I believe this dichotomy is quite generic and applicable to basically any problem encountered in the domain of software. One approach is to adopt the Unix philosophy of do one thing and do it well. What this means is that the problem domain should be artificially restricted to a small and well-understood area. The program should then solve this restricted problem in a correct and exhaustive way. An example of such approach in the messaging area is MQTT. Its a protocol for distributing messages to a set of consumers. It cant be used for anything else (say for RPC) but it is easy to use and does message distribution well. The other approach is to focus on generality and provide a powerful and highly configurable system. AMQP is an example of such a system. Its model of queues and exchanges provides the user with the means to programmatically define almost any routing algorithm they can think of. The trade-off, of course, is a lot of options to take care of. OslashMQ opts for the former model because it allows the resulting product to be used by basically anyone, while the generic model requires messaging experts to use it. To demonstrate the point, lets have a look how the model affects the complexity of the API. What follows is implementation of RPC client on top of a generic system (AMQP): On the other hand, OslashMQ splits the messaging landscape into so-called messaging patterns. Examples of the patterns are publishsubscribe, requestreply or parallelised pipeline. Each messaging pattern is completely orthogonal to other patterns and can be thought of as a separate tool. What follows is the re-implementation of the above application using OslashMQs requestreply pattern. Note how all the option tweaking is reduced to the single step of choosing the right messaging pattern ( REQ ): Up to this point weve argued that specific solutions are better than generic solutions. We want our solution to be as specific as possible. However, at the same time we want to provide our customers with as wide a range of functionality as possible. How can we solve this apparent contradiction The answer consists of two steps: Define a layer of the stack to deal with a particular problem area (e. g. transport, routing, presentation, etc.). Provide multiple implementations of the layer. There should be a separate non-intersecting implementation for each use case. Lets have a look at the example of the transport layer in the Internet stack. Its meant to provide services such as transferring data streams, applying flow control, providing reliability, etc. on the top of the network layer (IP). It does so by defining multiple non-intersecting solutions: TCP for connection-oriented reliable stream transfer, UDP for connectionless unreliable packet transfer, SCTP for transfer of multiple streams, DCCP for unreliable connections and so on. Note that each implementation is completely orthogonal: a UDP endpoint cannot speak to a TCP endpoint. Neither can a SCTP endpoint speak to a DCCP endpoint. It means that new implementations can be added to the stack at any moment without affecting the existing portions of the stack. Conversely, failed implementations can be forgotten and discarded without compromising the viability of the transport layer as a whole. The same principle applies to messaging patterns as defined by OslashMQ. Messaging patterns form a layer (the so-called scalability layer) on top of the transport layer (TCP and friends). Individual messaging patterns are implementations of this layer. They are strictly orthogonalmdashthe publishsubscribe endpoint cant speak to the requestreply endpoint, etc. Strict separation between the patterns in turn means that new patterns can be added as needed and that failed experiments with new patterns wont hurt the existing patterns. Lesson learned: When solving a complex and multi-faceted problem it may turn out that a monolithic general-purpose solution may not be the best way to go. Instead, we can think of the problem area as an abstract layer and provide multiple implementations of this layer, each focused on a specific well-defined use case. When doing so, delineate the use case carefully. Be sure about what is in the scope and what is not. By restricting the use case too aggressively the application of your software may be limited. If you define the problem too broadly, however, the product may become too complex, blurry and confusing for the users. 24.12. Conclusion As our world becomes populated with lots of small computers connected via the Internetmdashmobile phones, RFID readers, tablets and laptops, GPS devices, etc. mdashthe problem of distributed computing ceases to be the domain of academic science and becomes a common everyday problem for every developer to tackle. The solutions, unfortunately, are mostly domain-specific hacks. This article summarises our experience with building a large-scale distributed system in a systematic manner. It focuses on problems that are interesting from a software architecture point of view, and we hope that designers and programmers in the open source community will find it useful. Back to top Back to The Architecture of Open Source Applications .

No comments:

Post a Comment