W el c o m e Willkommen im Heim des offenen Java-Handelssystems Das Open Java Trading System (OJTS) ist eine gemeinsame Infrastruktur zur Entwicklung von Aktienhandels - systemen. Es besteht aus vier Teilen: das Sammeln von Rohdaten über das Internet die Erkennung von Handelssignalen ein Visualisierungsmodul und Module für die Verbindung zu den programmatischen Schnittstellen von Handelsplattformen wie Banken. Ziel der Projekte ist die Bereitstellung einer eigenständigen, reinen Java (plattformunabhängigen) gemeinsamen Infrastruktur für Entwickler von Handelssystemen. Einige der Aspekte, die behandelt werden sollten, sind die Bereitstellung eines gemeinsamen SQL92-konformen Datenbankschemas für die Speicherung von Finanzdaten, gemeinsamen Java-Schnittstellen für den Austausch von Daten zwischen verschiedenen Modulen, die Visualisierung von Rohdaten und Handelssignalen sowie einige andere gemeinsame Aspekte, die benötigt werden, um zu schaffen Ein abschließendes Handelssystem. Wegen meines Jobs und meiner Familie finde ich nicht die Zeit, OJTS länger zu verbessern. Ich fahre fort, den Verbindungen Abschnitt unten zu aktualisieren, der Sie zu den aktiveren Java-Quellprojekten in diesem Bereich, aber führt. In der Tat als Folge meines Interesses an der Dynamik der Aktienmärkte begann ich eine Reise in die tieferen Einzelheiten der Volkswirtschaft, um die Wechselkurse zu verstehen. Dieses Thema führt mich schließlich zu einem tieferen Studium des Geldes an sich als der metrischen Einheit, die wir in der Ökonomie verwenden, um Wert, Erfolg oder Nutzen zu messen. Dieses Thema erwies sich als äußerst interessant, aber zugleich war es sehr schwer, Informationen darüber zu finden, wie unser Geldsystem funktioniert. Gehen Sie herum und fragen Sie, woher das Geld kommt, wer es schafft und was seinen Wert bestimmt. Sie werden feststellen, dass auch die Menschen, die einen Master-Abschluss oder PhD. In der Ökonomie nicht wissen, diese Details. Oh, ja, sie werden in einigen kryptischen Fachbegriffe beantworten, aber sie werden nicht in der Lage sein, ein einfaches Diagramm zu zeichnen, das den Prozess umreißt. H. G. Wells wird berichtet, zu haben gesagt haben: Von Währung zu schreiben ist allgemein als eine anstößige, ja fast eine unanständige Praxis anerkannt. Die Redakteure werden den Schriftsteller fast weinerlich bitten, nicht über Geld zu schreiben, nicht weil es ein uninteressantes Thema ist, sondern weil es immer ein zutiefst beunruhigend war. Ich schlage vor, jede Person, die in einer demokratischen Gesellschaft zu lesen, über dieses Thema. Es beeinflusst unser Leben jeden Tag in einem Ausmaß, das nicht übertrieben werden kann Meiner Meinung nach sollte jeder Bürger eines demokratischen Landes auf dieser Welt wissen, wo unser Geld herkommt. Höchstwahrscheinlich kamen Sie zu dieser Web site, um nach Werkzeugen zu suchen, die Ihnen helfen, Ihre Geldmenge zu erhöhen. Um zu verstehen, die metrische Einheit Geld (egal ob Dollar oder Euro) wird ein wichtiger Bestandteil in Ihrem Toolkit für Geld zu verdienen. Wenn Sie wenig Zeit haben und nur sich leisten können, ein einzelnes Buch über dieses Thema zu lesen, dann schlage ich vor, dass Sie Reichtum, virtuellen Reichtum und Schuld durch Frederick Soddy lesen. Ich konnte eine gebrauchte Kopie über Amazon für 23.48 kaufen, aber es gibt auch eine Online-Version. Sie benötigen das DjVu-Plugin, um es zu lesen. Dieses Buch wurde ursprünglich im Jahr 1929 veröffentlicht, aber beschreibt noch die tatsächlichen Fakten sehr gut. Auch wenn ich nicht mit allen Schlußfolgerungen von Frederick Soddy einverstanden bin, ist seine Arbeit erfreulich erregend und führt Sie dazu, die richtigen Fragen zu stellen. N e w s Releases, Bugfixes und aktualisierte Dokumentation Kündigte die Aussetzung der aktiven Entwicklung und zusätzliche Hinweise auf Informationen über unsere Währungssysteme (DollarEuro). Hinzugefügt einen Links Abschnitt zu anderen interessanten Java-Trading-System-Projekte. Ich untersuche, wie OJTS kompatibler zu anderen Java-Trading-System-Bemühungen zu machen. Investition und Handelssystem Dokumentation Projekt auf ITSdoc. org gefunden werden. Auf der ITSdoc. org steht ein neues Wiki zur Verfügung, das sich auf die Verteilung von Wissen im Bereich der Investitions - und Handelssysteme konzentriert. Die Idee hinter ITSdoc. org ist, eine Kooperationsplattform ähnlich wikipedia zu haben, die der Gemeinschaft hilft, Wissen zu teilen. OpenJavaTradingSystem v0.13 veröffentlicht. Gestern habe ich die Version 0.13 der OpenJavaTradingSystem-Bibliothek veröffentlicht. Zu den neuen Features gehören: Datenabruf für Aktien, Fonds und Währungen von OnVista. Umsetzung der Währungsumrechnung und - umwandlungen. Portfolios werden implementiert und Sie können mit Portfolios genauso arbeiten wie mit einzelnen Sicherheitspapieren. Ein allgemeiner Rahmen für die Anwendung von Algorithmen auf Börsen-Zeitreihen wurde hinzugefügt. Wechseln von der interaktiven Shell SISCScheme zu ABCLCommonLisp und seinem Editor namens J. Hinzufügen eines allgemeinen Daten-Caching-Mechanismus zum Zwischenspeichern von Daten, die bereits über das Web im Dateisystem abgerufen wurden. Plus viele weitere kleinere Verbesserungen Wenn Sie an dieser neuen Version interessiert sind, sollten Sie an der quickstartscreenshot Abschnitt beginnen. Das Handbuch ist noch nicht aktualisiert, aber es kann Ihnen dennoch einige wertvolle Hintergrundinformationen geben, wenn Sie die Bibliothek in Ihrem Projekt verwenden möchten. Die Dokumentation sollte bald aktualisiert werden. Zurzeit gibt es nicht viel Entwicklung getan, weil ich meine Kenntnisse über bayesische Netzwerke zu aktualisieren. Siehe zum Beispiel die Liste der Bücher auf meiner Website. Zwei interessante Projekte sind WEKA und BNJ. Bald werde ich die Entwicklung fortsetzen und ich werde damit beginnen, die erste Intelligenz in das System zu integrieren. Heute habe ich die erste Version in den Dateien Abschnitt des Sourceforge Download-Bereich. Außerdem habe ich das Handbuch aktualisiert, um die interaktive Nutzung des Projekts über die SISC-Schema-Ebene zu dokumentieren. Für die ungeduldigen hier ist ein Quickstartscreenshot Abschnitt, um Sie zu gehen. D o c u m e n t a t i o n Dokumente, die die Einbauten des Projekts beschreiben. Java Data Objects and Interface Dokumentation gtgtHTML gtgtPDF Verwendungsdokumentation gtgtHTML gtgtPDF Investitions - und Handelssystem Dokumentation Projekt gtgtITSdoc. org T echnologie Third Party Building Blocks in diesem Projekt verwendet HSQL Database Engine (Lizenz: hsqldblic. txt) Die HSQLDB ist das Datenbankmodul, das mit der So dass Sie sofort mit dem OJTS arbeiten können, ohne eine Datenbank von Drittanbietern installieren zu müssen. Aber wenn Sie planen, eine andere SQL92-kompatible Datenbank zu verwenden, dann ist dies eine Konfigurationsoption. Castor (Lizenz: Die Exolab-Lizenz) Castor ist ein Open-Source-Datenbindungsrahmen für Javatm. Sein kürzester Pfad zwischen Java-Objekten, XML-Dokumenten und relationalen Tabellen. Castor bietet Java-to-XML-Bindung, Java-to-SQL-Persistenz und vieles mehr. Castor Doclet (Lizenz: GNU LGPL v2.1) Java Doclet, um sowohl Mapping-und DDL-Dateien für Castor JDO und Castor XML zu generieren. TestMaker (Lizenz: TestMaker Open-Source-Lizenz) Aus dem TestMaker-Projekt wird nur die Implementierung der Protokolle wie HTTP oder HTTPS verwendet, um Daten aus dem Web zu sammeln. JCookie (Lizenz: GNU LGPL v2.1) Die jCookie-Bibliothek ist erforderlich, damit die TestMaker-Bibliotheken funktionieren. Htmlparser (Lizenz: GNU LGPL v2.1) Die htmlparser-Bibliothek wird verwendet, um die Daten aus den Web-Ressourcen zu extrahieren. ABCLCommonLisp (Lizenz: GNU GPL v2) Mit ABCL (Armed Bear Common Lisp) wird das algorithmische Herz des Projekts in der Programmiersprache ANSI Common Lisp implementiert. JFreeChart (Lizenz: GNU LGPL v2.1) JFreeChart dient der Visualisierung von Finanzdaten als Charts. JSci (Lizenz: GNU LGPL v2.1) JSci - Eine wissenschaftliche API für Java. Joda Time (Lizenz: Eigene OpenSource-Lizenz) Joda Time ersetzt die ursprünglichen JDK-Datums - und Zeitklassen. L i n k s Links zu anderen Projekten Die JavaTraders Google-Gruppe kann der beste Eintrag für Sie sein, um sich über andere Java-basierte Handelssysteme und Tools zu informieren. L izenz Nutzungsbestimmungen Der Code des Projekts wird unter den Bedingungen der LGPL lizenziert, und alle Unterlagen, die Sie in diesem Projekt finden, werden unter den Bedingungen der FDL lizenziert. Eine vollständige Liste aller Entitäten des Systems wird in der gesamten Nächsten Abschnitten. Entitäten des Systems können in die folgenden drei Bereiche eingeteilt werden: Strategie. Sicherheit. Sicherheitsfamilie. Sicherheitsreferenz. Konto. Zuweisung. BrokerParameter. Eigentum. OrderPreference und damit verbundene Entities Diese Entities sind typischerweise unveränderlich und bilden die Grundlage für jede Handelsstrategie. Der Abschnitt 13.5, Referenzdatenmanager stellt eine GUI bereit, um Referenzdaten zu verwalten. MarketDataEvent und seine Unterklassen Tick und Bar sowie jede Art von GenericEvent Diese Entities stellen externe Ereignisse (Tick und Bar) dar, die von Marktdatenanbietern oder internen Ereignissen (Generic Events) stammen, die aus einer anderen Handelsstrategie stammen und die Basis für die Signallogik bilden Handelsstrategien. Marktdaten sind in der Regel unveränderlich und von nur momentanem Interesse für die Handelsstrategien. Auftrag. Transaktion. Position. Barguthaben. Messung. PortfolioValue und damit zusammenhängende Gesellschaften Diese Einheiten repräsentieren oder beeinflussen den Finanzstatus der Handelsstrategien. Einige von ihnen (z. B. Transaktionen und Messungen) sind unveränderlich, während andere (z. B. Positionen und Balancen) veränderlich sind und ihre Werte ändern, während Aufträge ausgeführt werden. Neben der Bereitstellung von Gettern und Setzern bieten alle Entitäten die folgenden gemeinsamen Merkmale: Die statische innere Konverterklasse kann verwendet werden, um die Entität automatisch in das entsprechende Wertobjekt zu konvertieren, siehe Abschnitt 8.4, Wertobjekt Die statische innere Factory-Klasse kann zum Erstellen neuer Instanzen verwendet werden Eines Entity Um Securities und SecurityFamilies zu aktualisieren, kann man entweder den Abschnitt 13.5, Reference Data Manager verwenden oder notwendige Informationen direkt in die Datenbank einfügen. Die Definition der Attribute der Klassen Security und SecurityFamily ist im AlgoTrader JavaDoc dokumentiert Die Klasse EasyToBorrow Enthält Informationen darüber, wie viele Verträge eines bestimmten Bestandes durch einen bestimmten Broker kurzgeschlossen werden können. SecurityReference Ist eine generische Verbindung zwischen einem Sicherheitseigentümer und einem anderen Ziel. Mit dieser Klasse ist es möglich, dass ein Wertpapier Links zu mehreren anderen Wertpapieren hat. 8.1.2.1. Security Visitors Das Visitor Pattern ist eine Möglichkeit, einen Algorithmus von einer Objektstruktur zu trennen, auf der er arbeitet. Mit diesem Muster ist es möglich, benutzerdefinierte Logik pro Entity zu implementieren, ohne den Entity-Code selbst zu verschmutzen. AlgoTrader stellt die Schnittstelle ch. algotrader. visitor. SecurityVisitor zur Verfügung, die von allen Security-Besuchern implementiert werden muss. Jeder Security-Besucher hat zwei generische Typparameter R und P. R ist der Rückkehrtyp (oder java. lang. Void), der von allen Besuchsmethoden zurückgegeben wird, und P ist ein beliebiges Parameterobjekt, das zu den Besuchsmethoden hinzugefügt werden kann. Darüber hinaus gibt es den ch. algotrader. visitor. PolymorphicSecurityVisitor, der den gesamten Vererbungsbaum aller Wertpapiere widerspiegelt. Wenn es zum Beispiel keine visitFuture-Methode gibt, ruft der PolymorphicEntityVisitor automatisch die Methode visitSecurity auf. Die Akzeptierungsmethode für jede Entität kann verwendet werden, um einen beliebigen Besucher wie folgt zu verarbeiten: In AlgoTrader stehen zwei Besucher zur Verfügung, die vom AlgoTrader-Server verwendet werden. Wird verwendet, um sicherzustellen, dass bestimmte Hibernate-Entitätsverweise initialisiert werden. Dient zur Validierung eines Tick nach Regeln, die pro Security definiert sind Abbildung 8.7. Konto Ein Konto stellt entweder ein tatsächliches Konto, eine Kontogruppe (IB-spezifisch) oder ein Zuteilungsprofil (IB-spezifisch) dar. Ein Konto ist einem bestimmten OrderServiceType (z. B. IBNATIVE oder FXCMFIX) zugewiesen. Zusätzlich das Feld sessionQualifier, das benötigt wird, um die eigentliche Sitzung zu definieren (in erster Linie für FIX Connections). Mit diesem Setup ist es möglich, mehrere Sessions (SessionQualifiers) pro OrderServiceType zu haben und mehrere Konten pro Sitzung zu haben. Aufträge, die an den Markt gesendet werden, enthalten stets Kontobezogene Informationen in adäquater Weise (z. B. als FIX-Tag 1). Auch Transaktionen, die auf einer tatsächlichen Bestellung basieren, haben eine Assoziation mit einem bestimmten Konto. Allerdings halten Positionen keine Informationen über Konten. Es ist also möglich, dass eine Position aggregierte Mengen aus mehreren externen Konten hält. Es ist auch möglich, eine Position durch auf Konto zu öffnen, aber dann durch ein anderes zu schließen. Mit diesem Setup müssen sich die Strategien nicht um die tatsächlichen Konten kümmern, in denen sich die Fonds befinden. Auf diese Weise wird eine Strategie immer nur eine Position pro Sicherheit sehen. 8.1.6. Abbildung 8.9. Position Für jede Strategie, die eine bestimmte Sicherheit besitzt, wird eine Position in der Datenbank erstellt. Selbst wenn diese Position später geschlossen wird (d. h. Menge 0), bleibt die Position in der Datenbank, da die zugehörigen Transaktionen immer noch auf sie verweisen. Grundsätzlich werden Positionswerte (zB MarketPreis MarketValue, DurchschnittPreiskosten, unrealizedPL amp realizedPL) pro tatsächlichen strategischen Position berechnet und zeigen den Preis, der gezahlt werden müsste, wenn die Position zu diesem Zeitpunkt geschlossen wurde Da einige Werte (zB marketValue) Abhängig davon, ob die Position lang oder kurz ist, können aggregierte Positionswerte für die gleiche Sicherheit (von verschiedenen Strategien) nicht nur durch Hinzufügen von Positionswerten aus den entsprechenden Strategien abgerufen werden. Beispiel: Sicherheit: VIX Dez 2012 Aktuelle Gebot: 16,50 Aktuelle Fragen: 16,60 Strategie A: Anzahl 10 - gt marketValue: 10 1000 16,50 165000 Strategie B: Menge -10 - gt marketValue: 10 1000 16,60 -166000 Die Summe der oben genannten Marktwerte wäre -1000, was offensichtlich falsch ist. Folglich bietet das PortfolioDAO Suchmethoden, die Positionen aus der gleichen Sicherheit (von verschiedenen Strategien) in der richtigen Weise aggregieren (z. B. findOpenPositionsAggregated). 8.1.8. Abonnement Das AlgoTrader DAO-Framework besteht aus mehreren Hauptkomponenten BaseEntityI repräsentiert eine abstrakte serialisierbare persistente Entität mit einem synthetischen Bezeichner vom Typ long. ReadOnlyDao repräsentiert eine Schnittstelle für allgemeine Abrufoperationen für Entitätsklassen. ReadWriteDao erweitert ReadOnlyDao und stellt eine Schnittstelle für allgemeine Abruf - und Mutationsoperationen dar. AbstractDao abstrakte Klasse dient als allgemeine Basisklasse für Datenzugriffsklassen. Es bietet die häufigsten Operationen zum Abrufen, Aktualisieren und Löschen von Entitäten sowie zum Erstellen von HQL - und nativen SQL-Abfragen. Es ist möglich, benutzerdefinierte DAOs die Plattform hinzuzufügen. Um dies zu erreichen benötigt man eine DAO-Schnittstelle, die entweder ReadOnlyDao oder ReadWriteDao erweitert. Fügen Sie benutzerdefinierte Operationen wie Entity-spezifische Sucher hinzu und erstellen Sie dann eine benutzerdefinierte DAO-Klasse, die AbstractDao erweitert und die benutzerdefinierte DAO-Schnittstelle implementiert. HL - und SQL-Abfragen, die von Alogtrader DAO-Komponenten verwendet werden, werden externalisiert und in der Datei Hibernate. hbm. xml gespeichert. Dies ermöglicht eine bessere Verwaltung und erleichtert die Wiederverwendung von Abfragen. Abfragen können von DAO-Klassen oder benutzerdefinierten Komponenten mit ihrem Namen aufgerufen werden 8.3. Services Das System basiert auf einer Service Oriented Architecture (SOA). Alle Operationen des Systems werden als Spring Services Beans bereitgestellt. Es gibt folgende Dienstleistungsgruppen: Private Services, die nur von den AlgoTrader Server Client Services genutzt werden, die von jeder Strategie (und dem AlgoTrader Server selbst) instanziiert werden. Die LMAX-Architektur In den letzten Jahren hören wir das freie Mittagessen Ist über - wir können nicht erwarten, dass Erhöhungen der individuellen CPU-Geschwindigkeit. So, um schnellen Code zu schreiben, müssen wir explizit mehrere Prozessoren mit gleichzeitiger Software verwenden. Dies ist keine gute Nachricht - schreiben gleichzeitigen Code ist sehr schwer. Schlösser und Semaphoren sind schwer zu überlegen und schwer zu testen - das heißt, wir verbringen mehr Zeit Sorgen um die Befriedigung des Computers als wir das Problem lösen Problem. Verschiedene Parallelität Modelle, wie Akteure und Software Transactional Memory, zielen darauf ab, dies zu erleichtern - aber es gibt noch eine Belastung, die Bugs und Komplexität führt. So war ich fasziniert, von einem Gespräch im QCon London im März letzten Jahres von LMAX zu hören. LMAX ist eine neue Retail-Handelsplattform. Seine Geschäftsinnovation ist, dass es eine Einzelhandelsplattform ist, die jedermann erlaubt, in einer Strecke der Finanzderivateprodukte zu handeln2. Eine Handelsplattform wie diese braucht sehr geringe Latenzzeiten - Trades müssen schnell verarbeitet werden, weil sich der Markt schnell bewegt. Eine Retail-Plattform fügt Komplexität hinzu, weil sie dies für viele Menschen tun muss. Das Ergebnis sind mehr Anwender mit vielen Trades, die alle schnell verarbeitet werden müssen.3 Angesichts des Wandels zum Multi-Core-Denken würde diese Art von anspruchsvoller Performance natürlich ein explizit gleichzeitiges Programmiermodell nahelegen - und das war auch ihre Aufgabe Startpunkt. Aber die Sache, die Völkeraufmerksamkeit bei QCon erhielt, war, daß dieses nicht war, wo sie oben lagen. In der Tat, sie am Ende, indem sie alle Business-Logik für ihre Plattform: alle Trades, von allen Kunden, in allen Märkten - auf einem einzigen Thread. Ein Thread, der verarbeitet 6 Millionen Bestellungen pro Sekunde mit Rohstoff-Hardware.4 Verarbeitung von vielen Transaktionen mit geringer Latenz und keine der Komplexität der gleichzeitigen Code - wie kann ich widerstehen, graben in die Glücklicherweise ein anderer Unterschied LMAX hat, um andere Finanzgesellschaften ist, dass Sie sind froh, über ihre technologischen Entscheidungen zu sprechen. So ist nun LMAX in Produktion für eine Weile seine Zeit, um ihre faszinierenden Design zu erkunden. Gesamtstruktur Abbildung 1: LMAXs-Architektur in drei Blobs Auf einer obersten Ebene hat die Architektur drei Teile Business Logic Processor5 Eingang Disruptor-Ausgang Disruptoren Wie der Name schon sagt, verarbeitet der Business-Logik-Prozessor alle Business-Logik in der Anwendung. Wie ich oben angeführt, es tut dies als Single-threaded Java-Programm, das reagiert auf Methodenaufrufe und produziert Ausgabeereignisse. Folglich ist es ein einfaches Java-Programm, das keine Plattform-Frameworks benötigt, um andere als die JVM selbst laufen, die es leicht in Testumgebungen ausgeführt werden kann. Obwohl der Business Logic Processor in einer einfachen Umgebung zum Testen laufen kann, gibt es eher eine Choreografie, um es in einer Produktionsumgebung laufen zu lassen. Input-Nachrichten müssen von einem Netzwerk-Gateway genommen werden und unmarshaled, repliziert und journaliert. Ausgabemeldungen müssen für das Netzwerk marshaled werden. Diese Aufgaben werden durch die Ein - und Ausgabe-Disruptoren gehandhabt. Im Gegensatz zum Business Logic Processor handelt es sich um gleichzeitige Komponenten, da es sich dabei um langsame und unabhängige IO-Operationen handelt. Sie wurden speziell für LMAX entworfen und gebaut, aber sie (wie die gesamte Architektur) sind an anderer Stelle anwendbar. Business Logic Processor Halten Sie alles im Speicher Der Business Logic Processor nimmt Eingabemails sequentiell (in Form eines Methodenaufrufs) auf, führt eine Geschäftslogik aus und gibt Ausgabeereignisse aus. Es arbeitet vollständig im Arbeitsspeicher, es gibt keine Datenbank oder einen anderen persistenten Speicher. Die Speicherung aller Daten hat zwei wichtige Vorteile. Erstens ist es schnell - es gibt keine Datenbank für langsame IO zugreifen, und es gibt auch keine transaktionalen Verhalten auszuführen, da alle die Verarbeitung erfolgt sequentiell. Der zweite Vorteil ist, dass es die Programmierung vereinfacht - theres keine objectrelational Mapping zu tun. Der gesamte Code kann mit dem Javas-Objektmodell geschrieben werden, ohne Kompromisse für die Zuordnung zu einer Datenbank zu machen. Die Verwendung einer In-Memory-Struktur hat eine wichtige Konsequenz - was passiert, wenn alles abstürzt Selbst die widerstandsfähigsten Systeme sind anfällig für jemanden, der die Energie zieht. Das Herz des Umgangs mit diesem ist Event Sourcing - was bedeutet, dass der aktuelle Zustand des Business Logic Processors vollständig durch die Verarbeitung der Eingangsereignisse ableitbar ist. Solange der Eingangsereignisstrom in einem dauerhaften Speicher (der einer der Aufträge des Eingangsdatenträgers ist) beibehalten wird, können Sie den aktuellen Zustand der Geschäftslogik durch Wiedergeben der Ereignisse jederzeit wiederherstellen. Eine gute Möglichkeit, dies zu verstehen, ist ein Versionskontrollsystem zu denken. Versionskontrollsysteme sind eine Folge von Commits, zu jeder Zeit können Sie eine Arbeitskopie erstellen, indem Sie diese Commits. VCSs sind komplizierter als der Business Logic Processor, da sie eine Verzweigung unterstützen müssen, während der Business Logic Processor eine einfache Sequenz ist. So können Sie in der Theorie immer wieder den Zustand des Business Logic Processors wiederherstellen, indem Sie alle Ereignisse aufbereiten. In der Praxis, aber das würde zu lange dauern, wenn Sie brauchen, um eine Spinne. So wie bei Versionskontrollsystemen kann LMAX Snapshots des Business Logic Processor-Status erstellen und aus den Snapshots wiederherstellen. Sie nehmen eine Momentaufnahme jede Nacht während Perioden der niedrigen Tätigkeit. Der Neustart des Business Logic Processors ist schnell, ein vollständiger Neustart - einschließlich Neustart der JVM, Laden eines aktuellen Snapshots und Wiederholen von Tagen im Wert von Zeitschriften - dauert weniger als eine Minute. Schnappschüsse machen den Start eines neuen Business Logic Processors schneller, aber nicht schnell genug, wenn ein Business Logic Processor um 14 Uhr abstürzen sollte. Als Ergebnis LMAX hält mehrere Business Logic Processors läuft die ganze Zeit6. Jedes Eingabeereignis wird von mehreren Prozessoren verarbeitet, aber alle außer einem Prozessor werden ignoriert. Sollte der Live-Prozessor ausfallen, wechselt das System zu einem anderen. Diese Fähigkeit, Failover zu behandeln, ist ein weiterer Vorteil der Verwendung von Event Sourcing. Durch das Sourcing in Repliken können sie zwischen den Prozessoren in einer Angelegenheit von Mikrosekunden wechseln. Neben Snapshots jede Nacht, starten sie auch die Business Logic Processors jede Nacht. Die Replikation ermöglicht es ihnen, dies ohne Ausfallzeiten zu tun, so dass sie weiter zu handeln 247. Für mehr Hintergrund auf Event Sourcing, sehen Sie die Entwurfsmuster auf meiner Website von ein paar Jahren. Der Artikel konzentriert sich mehr auf die Behandlung von zeitlichen Beziehungen als die Vorteile, die LMAX verwenden, aber es erklärt die Kernidee. Das Sourcing von Ereignissen ist wertvoll, weil es dem Prozessor erlaubt, vollständig im Arbeitsspeicher zu laufen, hat aber einen weiteren beträchtlichen Vorteil für die Diagnose. Wenn ein unerwartetes Verhalten auftritt, kopiert das Team die Sequenz der Ereignisse in ihre Entwicklungsumgebung und gibt sie dort erneut ab. Dies ermöglicht es ihnen, zu untersuchen, was passiert viel leichter als in den meisten Umgebungen möglich ist. Diese Diagnosefähigkeit erstreckt sich auch auf die Geschäftsdiagnose. Es gibt einige Business-Aufgaben, wie im Risikomanagement, die erhebliche Berechnungen erfordern, die nicht für die Verarbeitung von Aufträgen benötigt wird. Ein Beispiel ist eine Liste der Top-20-Kunden nach Risikoprofil basierend auf ihren aktuellen Handelspositionen. Das Team behandelt dies, indem es ein repliziertes Domänenmodell spinnt und dort die Berechnung durchführt, wo es nicht die Kernauftragsbearbeitung stört. Diese Analysedomänenmodelle können variierende Datenmodelle aufweisen, unterschiedliche Datensätze im Speicher behalten und auf verschiedenen Maschinen laufen. Tuning Leistung Bisher Ive erklärt, dass der Schlüssel für die Geschwindigkeit des Business Logic Processor alles nacheinander, im Gedächtnis zu tun. Nur dies zu tun (und nichts wirklich dumm) ermöglicht es Entwicklern, Code zu schreiben, die 10K TPS7 verarbeiten kann. Sie fanden dann, dass die Konzentration auf die einfachen Elemente der guten Code könnte dies in die 100K TPS-Bereich. Dies braucht nur gut-factored Code und kleine Methoden - im Wesentlichen dies ermöglicht Hotspot, um einen besseren Job der Optimierung zu tun und für CPUs effizienter beim Caching des Codes als seine Ausführung. Es brauchte ein bisschen mehr Klugheit, um eine andere Größenordnung hinaufzugehen. Es gibt mehrere Dinge, die das LMAX-Team hilfreich fand, um dorthin zu gelangen. Man sollte benutzerdefinierte Implementierungen der Java-Sammlungen, die entworfen wurden, um Cache-freundlich und vorsichtig mit Garbage8 zu schreiben. Ein Beispiel hierfür ist die Verwendung primitiver Java-Sequenzen als HashMap-Schlüssel mit einer speziell geschriebenen Array-gesicherten Map-Implementierung (LongToObjectHashMap). Im Allgemeinen haben sie festgestellt, dass die Wahl der Datenstrukturen oft einen großen Unterschied macht. Die meisten Programmierer greifen nur eine Liste, die sie letztes Mal verwendet haben, anstatt darüber nachzudenken, welche Implementierung die richtige für diesen Kontext ist.9 Eine andere Technik, um diese Spitzenleistung zu erreichen, ist Putting Aufmerksamkeit in Leistungstests. Ive lang beachtet, daß Leute viel über Techniken sprechen, um Leistung zu verbessern, aber die eine Sache, die wirklich unterscheidet, ist, es zu prüfen. Auch gute Programmierer sind sehr gut im Aufbau von Performance-Argumenten, die am Ende falsch liegen, so dass die besten Programmierer lieber Profiler und Testfälle zu spekulieren.10 Das LMAX-Team hat auch festgestellt, dass Schreiben Tests erste ist eine sehr effektive Disziplin für Performance-Tests. Programming-Modell Diese Art der Verarbeitung führt einige Einschränkungen in die Art und Weise Sie schreiben und organisieren die Geschäftslogik. Die erste davon ist, dass Sie jede Interaktion mit externen Diensten herausfinden müssen. Ein externer Dienstaufruf wird langsam sein, und mit einem einzigen Thread wird die gesamte Auftragsbearbeitungsmaschine stoppen. Dadurch können Sie keine Anrufe zu externen Diensten innerhalb der Geschäftslogik tätigen. Stattdessen müssen Sie diese Interaktion mit einem Ausgabeereignis beenden und auf ein anderes Eingabeereignis warten, um es wieder abholen zu können. Ill verwenden ein einfaches nicht-LMAX-Beispiel zu illustrieren. Stellen Sie sich vor, Sie machen eine Bestellung für Jelly Beans mit Kreditkarte. Ein einfaches Einzelhandels-System würde Ihre Bestellinformationen nehmen, einen Kreditkarten-Validierungsdienst verwenden, um Ihre Kreditkartennummer zu überprüfen und dann Ihre Bestellung zu bestätigen - alles in einem einzigen Vorgang. Die Thread-Verarbeitung Ihrer Bestellung würde blockieren, während das Warten auf die Kreditkarte überprüft werden, aber dieser Block wäre nicht sehr lange für den Benutzer, und der Server kann immer einen anderen Thread auf dem Prozessor laufen, während sein Warten. In der LMAX-Architektur würden Sie diese Operation in zwei Teile aufteilen. Die erste Operation würde die Auftragsinformationen erfassen und durch Ausgeben eines Ereignisses (Kreditkartenvalidierung angefordert) an das Kreditkartenunternehmen beenden. Der Geschäftslogikprozessor würde dann die Verarbeitung von Ereignissen für andere Kunden weiterverarbeiten, bis er in seinem Eingangsereignisstrom ein kreditkartengültiges Ereignis empfangen hat. Bei der Verarbeitung dieses Ereignisses würde es die Bestätigungsaufgaben für diesen Auftrag ausführen. Arbeiten in dieser Art von ereignisgesteuerten, asynchronen Stil, ist etwas ungewöhnlich - obwohl mit asynchrony, um die Reaktionsfähigkeit einer Anwendung zu verbessern, ist eine vertraute Technik. Es hilft auch die Geschäftsprozesse widerstandsfähiger, da müssen Sie expliziter im Denken über die verschiedenen Dinge, die mit der Remote-Anwendung passieren können. Ein zweites Merkmal des Programmiermodells liegt in der Fehlerbehandlung. Das traditionelle Modell von Sitzungen und Datenbank-Transaktionen bietet eine hilfreiche Fehlerbehandlung Fähigkeit. Sollte etwas schief gehen, ist es einfach, alles wegzuwerfen, was bisher in der Interaktion passiert ist. Session-Daten sind transient und können verworfen werden, auf Kosten einer Irritation für den Benutzer, wenn in der Mitte etwas kompliziert. Wenn ein Fehler auf der Datenbankseite auftritt, können Sie die Transaktion zurücksetzen. LMAXs in-Memory-Strukturen sind persistent über Eingabeereignisse, so dass, wenn es einen Fehler ist es wichtig, nicht verlassen, dass Speicher in einem inkonsistenten Zustand. Allerdings theres keine automatisierte Rollback-Anlage. Folglich legt das LMAX-Team große Aufmerksamkeit darauf, dass die Eingangsereignisse vollständig gültig sind, bevor irgendeine Mutation des persistenten Status im Speicher durchgeführt wird. Sie haben herausgefunden, dass das Testen ein Schlüsselinstrument ist, um diese Probleme vor der Produktion zu beseitigen. Ein - und Ausgabe-Disruptoren Obwohl die Geschäftslogik in einem einzigen Thread vorkommt, gibt es eine Anzahl von Aufgaben, bevor wir eine Business-Objekt-Methode aufrufen können. Die ursprüngliche Eingabe für die Verarbeitung kommt aus dem Draht in Form einer Nachricht, muss diese Nachricht in ein Formular, das für Business Logic Processor zu verwenden unmarshaled werden. Event Sourcing beruht darauf, ein dauerhaftes Journal aller Eingangsereignisse aufzubewahren, so dass jede Eingangsnachricht auf einem dauerhaften Speicher gelagert werden muss. Schließlich beruht die Architektur auf einem Cluster von Business Logic Processors, so dass wir die Eingabemeldungen in diesem Cluster replizieren müssen. Ebenso müssen ausgangsseitig die Ausgabeereignisse zur Übertragung über das Netzwerk marshaled werden. Abbildung 2: Die durch den Input Disruptor durchgeführten Aktivitäten (unter Verwendung der UML-Aktivitätsdiagramm-Notation) Der Replikator und der Journaler umfassen IO und sind daher relativ langsam. Nach allem ist die zentrale Idee von Business Logic Processor, dass es keine IO vermeidet. Auch diese drei Aufgaben sind relativ unabhängig, alle von ihnen müssen getan werden, bevor der Business Logic Processor auf eine Nachricht arbeitet, aber sie können in beliebiger Reihenfolge durchgeführt werden. So im Gegensatz zu den Business Logic Processor, wo jeder Handel den Markt für nachfolgende Trades ändert, gibt es eine natürliche Passform für Parallelität. Um diese Gleichzeitigkeit zu bewältigen, entwickelte das LMAX-Team eine spezielle Parallelitätskomponente, die sie Disruptor 11 nennen. Das LMAX-Team hat den Quellcode für den Disruptor mit einer Open-Source-Lizenz freigegeben. Auf einer groben Ebene kann man sich einen Disruptor als Multicast-Graphen von Warteschlangen vorstellen, bei denen die Produzenten Objekte darauf legen, die an alle Konsumenten zum parallelen Verbrauch durch separate Downstream-Warteschlangen gesendet werden. Wenn Sie nach innen schauen sehen Sie, dass dieses Netz von Warteschlangen wirklich eine einzelne Datenstruktur ist - ein Ringpuffer. Jeder Produzent und jeder Konsument hat einen Sequenzzähler, der angibt, welcher Slot im Puffer aktuell gerade arbeitet. Jeder Producerconsumer schreibt seinen eigenen Sequenzzähler, kann aber die anderen Sequenzzähler lesen. Auf diese Weise kann der Hersteller die Verbraucherzähler lesen, um sicherzustellen, dass der Steckplatz, den er schreiben möchte, ohne Sperren für die Zähler verfügbar ist. Ähnlich kann ein Verbraucher sicherstellen, dass er nur Nachrichten verarbeitet, sobald ein anderer Verbraucher damit fertig ist, indem er die Zähler beobachtet. Abbildung 3: Der Input Disruptor koordiniert einen Producer und vier Consumer Output-Disruptoren sind ähnlich, aber sie haben nur zwei sequentielle Consumer für Marshalling und Output.12 Output-Events sind in mehrere Themen organisiert, so dass nur an Empfänger, die interessiert sind, Nachrichten gesendet werden können in ihnen. Jedes Thema hat seinen eigenen Disruptor. Die Disruptoren Ive beschrieben werden in einem Stil mit einem Hersteller und mehrere Verbraucher verwendet, aber dies ist keine Einschränkung des Designs des Disruptors. Der Disruptor kann auch mit mehreren Herstellern arbeiten, in diesem Fall braucht er immer noch keine Schlösser.13 Ein Vorteil des Disruptor-Designs ist, dass es es den Verbrauchern erleichtert, schnell aufzuholen, wenn sie in ein Problem geraten und zurückfallen. Wenn der Unmarshaller ein Problem hat, wenn er auf Schlitz 15 arbeitet und zurückkehrt, wenn der Empfänger auf Schlitz 31 ist, kann er Daten von Schlitzen 16-30 in einer Charge lesen, um aufzuholen. Dieses Batch-Lesen der Daten von dem Disruptor macht es einfacher für rückständige Verbraucher, um schnell aufzuholen, wodurch die Gesamt-Latenz verringert wird. Ive beschrieb die Dinge hier, mit jeweils einem der Journaler, Replikator und Unmarshaler - das ist tatsächlich das, was LMAX macht. Aber das Design würde es ermöglichen, dass mehrere dieser Komponenten laufen. Wenn Sie zwei Journalisten liefen, dann würde man die geraden Schlitze nehmen und der andere Journaler würde die ungeraden Schlitze nehmen. Dies ermöglicht eine weitere Parallelität dieser IO-Operationen, falls dies erforderlich wird. Die Ringpuffer sind groß: 20 Millionen Steckplätze für Eingangspuffer und 4 Millionen Steckplätze für jeden der Ausgangspuffer. Die Sequenzzähler sind 64bit lange ganze Zahlen, die monoton zu erhöhen, auch als die Ringschlitze wrap.14 Der Puffer ist auf eine Größe, die eine Potenz von zwei, so dass der Compiler kann eine effiziente Modul-Operation zu tun, um von der Sequenz Zähler Zahl auf die Steckplatz-Nummer zu tun . Wie der Rest des Systems werden die Disruptoren über Nacht aufgeprallt. Diese Bounce ist vor allem getan, um Speicher zu wischen, so dass es weniger Chance auf eine teure Garbage Collection Event während des Handels. (Ich denke auch, dass es eine gute Angewohnheit ist, regelmäßig neu zu starten, so dass Sie proben, wie es für Notfälle zu tun.) Der Journalist Job ist es, alle Ereignisse in einer dauerhaften Form zu speichern, so dass sie wiedergegeben werden können, wenn etwas schief gehen. LMAX verwendet dafür keine Datenbank, sondern nur das Dateisystem. Sie streamen die Ereignisse auf die Festplatte. In modernen Worten, mechanische Festplatten sind schrecklich langsam für den zufälligen Zugriff, aber sehr schnell für das Streaming - daher ist die Tag-Line-Datenträger das neue Tape.15 Früher habe ich erwähnt, dass LMAX mehrere Kopien seines Systems in einem Cluster, um schnelles Failover zu unterstützen . Der Replikator hält diese Knoten synchron. Alle Kommunikation in LMAX nutzt IP Multicasting, so dass Clients nicht wissen müssen, welche IP-Adresse der Master-Knoten ist. Nur der Masterknoten hört direkt auf Eingabeereignisse zu und führt einen Replikator aus. Der Replikator sendet die Eingangsereignisse an die Slave-Knoten. Wenn der Masterknoten nach unten geht, wird sein Mangel an Herzschlag bemerkt, ein anderer Knoten wird Master, startet die Verarbeitung von Eingabeereignissen und startet den Replikator. Jeder Knoten hat seinen eigenen Eingang Disruptor und hat somit seine eigene Zeitschrift und tut seine eigene Unmarshaling. Selbst bei IP-Multicasting wird die Replikation dennoch benötigt, da IP-Nachrichten auf verschiedenen Knoten in einer anderen Reihenfolge ankommen können. Der Master-Knoten liefert eine deterministische Sequenz für den Rest der Verarbeitung. Der Unmarshaler schaltet die Ereignisdaten aus dem Draht in ein Java-Objekt, das verwendet werden kann, um Verhalten auf dem Business Logic Processor aufzurufen. Daher muss es im Gegensatz zu den anderen Konsumenten die Daten im Ringpuffer ändern, damit es dieses unmarshaled Objekt speichern kann. Die Regel hier ist, dass die Verbraucher erlaubt, in den Ringpuffer zu schreiben, aber jedes beschreibbare Feld kann nur einen parallelen Verbraucher, der erlaubt, es zu schreiben. Dies bewahrt das Prinzip, nur einen einzigen Schriftsteller zu haben. 16 Abbildung 4: Die LMAX-Architektur mit erweiterten Disruptoren Der Disruptor ist eine Allzweckkomponente, die außerhalb des LMAX-Systems verwendet werden kann. Normalerweise Finanzgesellschaften sind sehr geheimnisvoll über ihre Systeme, halten Ruhe sogar über Gegenstände, die arent germane zu ihrem Geschäft. Nicht nur hat LMAX offen über seine gesamte Architektur, sie haben Open-Sourced der Disruptor-Code - eine Handlung, die mich sehr glücklich macht. Nicht nur wird dies ermöglichen anderen Organisationen zu nutzen, die Disruptor, wird es auch für mehr Prüfung seiner Parallelität Eigenschaften zu ermöglichen. Warteschlangen und ihr Mangel an mechanischer Sympathie Die LMAX-Architektur fing Völker Aufmerksamkeit, weil seine eine ganz andere Art und Weise der Annäherung an ein Hochleistungs-System, was die meisten Menschen denken. Bisher habe ich darüber gesprochen, wie es funktioniert, aber havent tauchte zu viel in, warum es so entwickelt wurde. Diese Geschichte ist für sich interessant, weil diese Architektur nicht nur erscheinen. Es dauerte eine lange Zeit der Versuch, mehr konventionelle Alternativen, und erkennen, wo sie waren fehlerhaft, bevor das Team auf diesem ein. Die meisten Business-Systeme in diesen Tagen haben eine Kernarchitektur, die auf mehrere aktive Sitzungen über eine Transaktions-Datenbank koordiniert beruht. Das LMAX-Team war mit diesem Ansatz vertraut und zuversichtlich, dass es nicht für LMAX funktionieren würde. Diese Einschätzung wurde in den Erfahrungen von Betfair - der Muttergesellschaft, die LMAX gegründet hat - gegründet. Betfair ist eine Wett-Website, die es den Leuten erlaubt, auf Sportveranstaltungen zu wetten. Es behandelt sehr hohe Verkehrsvolumen mit einer Menge von Konkurrenz - Sportwetten neigen dazu, um bestimmte Ereignisse platzen. Um diese Arbeit haben sie eine der heißesten Datenbank-Installationen um und mussten viele unnatürliche Handlungen zu tun, damit es funktioniert. Basierend auf dieser Erfahrung wussten sie, wie schwierig es war, die Leistung von Betfairs aufrechtzuerhalten und war sicher, dass diese Art von Architektur nicht für die sehr geringe Latenz funktionieren würde, die eine Handelsstelle erfordern würde. Daher mussten sie einen anderen Ansatz finden. Ihr erster Ansatz war, zu folgen, was so viele heute sagen, dass, um hohe Leistung zu erhalten, müssen Sie explizite Parallelität zu verwenden. Für dieses Szenario bedeutet dies, dass Aufträge von mehreren Threads parallel verarbeitet werden können. Allerdings, wie es oft der Fall mit Parallelität, die Schwierigkeit kommt, weil diese Threads miteinander kommunizieren müssen. Die Bearbeitung einer Bestellung ändert die Marktbedingungen und diese Bedingungen müssen mitgeteilt werden. Der Ansatz, den sie früh erforschten, war das Schauspieler-Modell und seine Cousine SEDA. Das Actor-Modell setzt auf unabhängige, aktive Objekte mit eigenem Thread, die über Warteschlangen miteinander kommunizieren. Viele Menschen finden diese Art von Parallelität Modell viel einfacher zu behandeln, als zu versuchen, etwas auf der Grundlage von Sperren primitives tun. Das Team baute einen Prototyp-Austausch mit dem Schauspieler-Modell und führte Performance-Tests auf sie. Was sie gefunden, war, dass die Prozessoren mehr Zeit für die Verwaltung von Warteschlangen verbrachten als die reale Logik der Anwendung zu tun. Warteschlangenzugriff war ein Engpass. Wenn sie Leistung wie diese drückt, beginnt sie, wichtig zu werden, um zu berücksichtigen, wie moderne Hardware aufgebaut wird. Der Ausdruck, den Martin Thompson gern verwendet, ist mechanische Sympathie. Der Begriff kommt aus Rennwagen fahren und es spiegelt den Fahrer mit einem angeborenen Gefühl für das Auto, so können sie fühlen, wie man das Beste aus ihm zu bekommen. Viele Programmierer, und ich gestehe, ich falle in dieses Lager, haben nicht viel mechanische Sympathie für die Programmierung interagiert mit Hardware. Was ist schlimmer ist, dass viele Programmierer denken, sie haben mechanische Sympathie, aber seine auf Vorstellungen, wie Hardware verwendet, um zu arbeiten, die jetzt viele Jahre veraltet sind gebaut. Einer der dominierenden Faktoren mit modernen CPUs, die Latenz beeinflusst, ist, wie die CPU mit Speicher interagiert. Diese Tage gehen in den Hauptspeicher ist eine sehr langsame Operation in CPU-Begriffe. CPUs haben mehrere Cache-Ebenen, von denen jeder wesentlich schneller ist. So erhöhen Geschwindigkeit, die Sie Ihren Code und Daten in diesen Caches erhalten möchten. Auf einer Ebene hilft das Schauspielermodell hier. Sie können sich einen Akteur als sein eigenes Objekt, dass Cluster Code und Daten, die eine natürliche Einheit für Caching ist denken. Aber Akteure müssen kommunizieren, was sie durch Warteschlangen tun - und das LMAX-Team beobachtete, dass seine Warteschlangen, die das Caching stören. Die Erklärung läuft wie folgt: Um einige Daten auf eine Warteschlange zu stellen, müssen Sie in diese Warteschlange schreiben. Ebenso, um Daten aus der Warteschlange zu nehmen, müssen Sie in die Warteschlange schreiben, um das Entfernen durchzuführen. Dies ist Schreibkonkurrenz - mehr als ein Client muss möglicherweise auf die gleiche Datenstruktur schreiben. Um mit dem Schreibkonflikt umzugehen, verwendet eine Warteschlange oft Sperren. Wenn jedoch eine Sperre verwendet wird, kann dies einen Kontextwechsel zum Kernel verursachen. Wenn dies geschieht, wird der betreffende Prozessor wahrscheinlich die Daten in seinen Caches verlieren. Die Schlussfolgerung kam, dass, um das beste Caching-Verhalten zu erhalten, benötigen Sie ein Design, das nur ein Kern-Schreiben an jedem Speicher location17 hat. Mehrere Leser sind fein, verarbeiten Prozessoren häufig spezielle Hochgeschwindigkeitsverbindungen zwischen ihren Caches. Aber Warteschlangen scheitern das Ein-Schriftsteller-Prinzip. Diese Analyse führte das LMAX-Team zu einigen Schlussfolgerungen. Erstens führte sie zur Konstruktion des Disruptors, der entschieden dem Single-Writer-Constraint folgt. Zweitens führte es zu der Idee, die Single-Thread-Business-Logik-Ansatz zu erforschen, die Frage, wie schnell ein einziges Thread gehen kann, wenn es von Concurrency-Management befreit. The essence of working on a single thread, is to ensure that you have one thread running on one core, the caches warm up, and as much memory access as possible goes to the caches rather than to main memory. This means that both the code and the working set of data needs to be as consistently accessed as possible. Also keeping small objects with code and data together allows them to be swapped between the caches as a unit, simplifying the cache management and again improving performance. An essential part of the path to the LMAX architecture was the use of performance testing. The consideration and abandonment of an actor-based approach came from building and performance testing a prototype. Similarly much of the steps in improving the performance of the various components were enabled by performance tests. Mechanical sympathy is very valuable - it helps to form hypotheses about what improvements you can make, and guides you to forward steps rather than backward ones - but in the end its the testing gives you the convincing evidence. Performance testing in this style, however, is not a well-understood topic. Regularly the LMAX team stresses that coming up with meaningful performance tests is often harder than developing the production code. Again mechanical sympathy is important to developing the right tests. Testing a low level concurrency component is meaningless unless you take into account the caching behavior of the CPU. One particular lesson is the importance of writing tests against null components to ensure the performance test is fast enough to really measure what real components are doing. Writing fast test code is no easier than writing fast production code and its too easy to get false results because the test isnt as fast as the component its trying to measure. Should you use this architecture At first glance, this architecture appears to be for a very small niche. After all the driver that led to it was to be able to run lots of complex transactions with very low latency - most applications dont need to run at 6 million TPS. But the thing that fascinates me about this application, is that they have ended up with a design which removes much of the programming complexity that plagues many software projects. The traditional model of concurrent sessions surrounding a transactional database isnt free of hassles. Theres usually a non-trivial effort that goes into the relationship with the database. Objectrelational mapping tools can help much of the pain of dealing with a database, but it doesnt deal with it all. Most performance tuning of enterprise applications involves futzing around with SQL. These days, you can get more main memory into your servers than us old guys could get as disk space. More and more applications are quite capable of putting all their working set in main memory - thus eliminating a source of both complexity and sluggishness. Event Sourcing provides a way to solve the durability problem for an in-memory system, running everything in a single thread solves the concurrency issue. The LMAX experience suggests that as long as you need less than a few million TPS, youll have enough performance headroom. There is a considerable overlap here with the growing interest in CQRS. An event sourced, in-memory processor is a natural choice for the command-side of a CQRS system. (Although the LMAX team does not currently use CQRS.) So what indicates you shouldnt go down this path This is always a tricky questions for little-known techniques like this, since the profession needs more time to explore its boundaries. A starting point, however, is to think of the characteristics that encourage the architecture. One characteristic is that this is a connected domain where processing one transaction always has the potential to change how following ones are processed. With transactions that are more independent of each other, theres less need to coordinate, so using separate processors running in parallel becomes more attractive. LMAX concentrates on figuring the consequences of how events change the world. Many sites are more about taking an existing store of information and rendering various combinations of that information to as many eyeballs as they can find - eg think of any media site. Here the architectural challenge often centers on getting your caches right. Another characteristic of LMAX is that this is a backend system, so its reasonable to consider how applicable it would be for something acting in an interactive mode. Increasingly web application are helping us get used to server systems that react to requests, an aspect that does fit in well with this architecture. Where this architecture goes further than most such systems is its absolute use of asynchronous communications, resulting in the changes to the programming model that I outlined earlier. These changes will take some getting used to for most teams. Most people tend to think of programming in synchronous terms and are not used to dealing with asynchrony. Yet its long been true that asynchronous communication is an essential tool for responsiveness. It will be interesting to see if the wider use of asynchronous communication in the javascript world, with AJAX and node. js, will encourage more people to investigate this style. The LMAX team found that while it took a bit of time to adjust to asynchronous style, it soon became natural and often easier. In particular error handling was much easier to deal with under this approach. The LMAX team certainly feels that the days of the coordinating transactional database are numbered. The fact that you can write software more easily using this kind of architecture and that it runs more quickly removes much of the justification for the traditional central database. For my part, I find this a very exciting story. Much of my goal is to concentrate on software that models complex domains. An architecture like this provides good separation of concerns, allowing people to focus on Domain-Driven Design and keeping much of the platform complexity well separated. The close coupling between domain objects and databases has always been an irritation - approaches like this suggest a way out. if you found this article useful, please share it. I appreciate the feedback and encouragement
No comments:
Post a Comment