Das Team von LMAX hat eine Präsentation darüber, wie es gelungen ist, 100.000 TPS bei einer Latenz von weniger als 1 ms zu erreichen . Sie haben diese Präsentation mit einem Blog , einem technischen Dokument (PDF) und dem Quellcode selbst unterlegt .
Martin Fowler hat kürzlich ein hervorragendes Papier zur LMAX-Architektur veröffentlicht und erwähnt, dass sie jetzt sechs Millionen Bestellungen pro Sekunde verarbeiten können, und zeigt einige der Schritte auf, die das Team unternommen hat, um die Leistung um eine Größenordnung zu steigern.
Bisher habe ich erklärt, dass der Schlüssel zur Geschwindigkeit des Business Logic Processors darin besteht, alles sequentiell im Arbeitsspeicher auszuführen. Wenn Sie dies tun (und nichts wirklich Dummes), können Entwickler Code schreiben, der 10K TPS verarbeiten kann.
Sie fanden dann heraus, dass die Konzentration auf die einfachen Elemente eines guten Codes dies in den Bereich von 100.000 TPS bringen könnte. Hierfür sind nur gut durchdachter Code und kleine Methoden erforderlich. Dies ermöglicht Hotspot im Wesentlichen eine bessere Optimierung und eine effizientere Zwischenspeicherung des ausgeführten Codes durch die CPUs.
Es bedurfte etwas mehr Geschicklichkeit, um eine weitere Größenordnung aufzusteigen. Es gibt mehrere Dinge, die das LMAX-Team hilfreich fand, um dorthin zu gelangen. Eine bestand darin, benutzerdefinierte Implementierungen der Java-Auflistungen zu schreiben, die cachefreundlich und müllschonend gestaltet wurden.
Eine andere Technik, um dieses Höchstmaß an Leistung zu erreichen, besteht darin, den Leistungstests Aufmerksamkeit zu widmen. Ich habe lange bemerkt, dass die Leute viel über Techniken zur Verbesserung der Leistung sprechen, aber das einzige, was wirklich einen Unterschied macht, ist es, sie zu testen
Fowler erwähnte, dass es mehrere Dinge gibt, die gefunden wurden, aber er erwähnte nur ein paar.
Gibt es andere Architekturen, Bibliotheken, Techniken oder "Dinge", die hilfreich sind, um ein solches Leistungsniveau zu erreichen?
quelle
Antworten:
Es gibt alle Arten von Techniken für die Hochleistungstransaktionsverarbeitung, und die in Fowlers Artikel beschriebene ist nur eine von vielen, die derzeit auf dem neuesten Stand sind. Anstatt eine Reihe von Techniken aufzulisten, die auf die Situation eines Menschen anwendbar sind oder nicht, ist es meines Erachtens besser, die Grundprinzipien und die Art und Weise, wie LMAX eine große Anzahl von Techniken anspricht, zu diskutieren.
Für ein umfangreiches Transaktionsverarbeitungssystem möchten Sie so viel wie möglich tun:
Minimieren Sie den Zeitaufwand in den langsamsten Speicherebenen. Von der schnellsten zur langsamsten auf einem modernen Server haben Sie: CPU / L1 -> L2 -> L3 -> RAM -> Festplatte / LAN -> WAN. Der Sprung von der schnellsten modernen Magnetplatte zum langsamsten Arbeitsspeicher beträgt mehr als das 1000-fache für sequentiellen Zugriff. Zufallszugriff ist noch schlimmer.
Minimieren oder eliminieren Sie Wartezeiten . Dies bedeutet, dass Sie so wenig Status wie möglich freigeben und explizite Sperren nach Möglichkeit vermeiden , wenn der Status freigegeben werden muss .
Verteilen Sie die Arbeitslast. CPUs sind in den letzten Jahren nicht viel schneller geworden, aber sie sind kleiner geworden, und 8 Kerne sind auf einem Server ziemlich verbreitet. Darüber hinaus können Sie die Arbeit sogar auf mehrere Computer verteilen. Dies ist der Ansatz von Google. Das Tolle daran ist, dass es alles skaliert , einschließlich I / O.
Laut Fowler verfolgt LMAX bei jedem dieser Punkte den folgenden Ansatz:
Halten Sie alle Zustand in Erinnerung an allen Zeiten. Die meisten Datenbank-Engines tun dies ohnehin, wenn die gesamte Datenbank in den Arbeitsspeicher passt, aber sie möchten nichts dem Zufall überlassen, was auf einer Echtzeit-Handelsplattform verständlich ist. Um dies zu erreichen, ohne ein großes Risiko einzugehen, mussten sie eine Reihe leichter Backup- und Failover-Infrastrukturen aufbauen.
Verwenden Sie eine sperrfreie Warteschlange ("Disruptor") für den Stream von Eingabeereignissen. Im Gegensatz zu herkömmlichen dauerhaften Nachrichtenwarteschlangen, die definitiv nicht frei von Sperren sind und in der Regel schmerzhaft langsam verteilte Transaktionen beinhalten .
Nicht viel. LMAX wirft dieses unter den Bus auf der Grundlage, dass die Workloads voneinander abhängig sind. Das Ergebnis des einen ändert die Parameter für die anderen. Dies ist eine kritische Einschränkung, auf die Fowler ausdrücklich hinweist. Sie machen einige Verwendung von Parallelität , um Failover - Funktionen zur Verfügung zu stellen, aber alle der Business - Logik auf einem verarbeiteten einzigen Thread .
LMAX ist nicht der einzige Ansatz für hochskaliertes OLTP. Und obwohl es in seinem eigenen Recht ziemlich brillant, man nicht bleeding-edge - Techniken , um dieses Niveau der Leistung abziehen verwenden müssen.
Von allen oben genannten Prinzipien ist # 3 wahrscheinlich das wichtigste und effektivste, da Hardware ehrlich gesagt billig ist. Wenn Sie die Arbeitslast ordnungsgemäß auf ein halbes Dutzend Kerne und mehrere Dutzend Computer verteilen können, ist der Himmel die Grenze für konventionelle Parallel-Computing- Techniken. Sie wären überrascht, wie viel Durchsatz Sie mit nur ein paar Nachrichtenwarteschlangen und einem Round-Robin-Verteiler erzielen können. Es ist offensichtlich nicht so effizient wie LMAX - eigentlich nicht einmal in der Nähe -, aber Durchsatz, Latenz und Kosteneffizienz sind getrennte Aspekte, und hier geht es speziell um den Durchsatz.
Wenn Sie die gleichen speziellen Anforderungen wie LMAX haben, insbesondere einen geteilten Zustand, der einer geschäftlichen Realität entspricht, im Gegensatz zu einer voreiligen Designwahl, dann würde ich vorschlagen, ihre Komponente auszuprobieren, da ich nicht viel gesehen habe sonst passt das zu diesen anforderungen. Aber wenn wir nur über hohe Skalierbarkeit sprechen, dann möchte ich Sie dringend auffordern, mehr über verteilte Systeme zu forschen, da dies der kanonische Ansatz ist, den die meisten Organisationen heutzutage verwenden (Hadoop und verwandte Projekte, ESB und verwandte Architekturen, CQRS, auch Fowler) Erwähnungen und so weiter).
SSDs werden auch zum Game-Changer. wohl schon. Sie können nun einen permanenten Speicher mit ähnlichen Zugriffszeiten auf den Arbeitsspeicher haben, und obwohl SSDs der Server-Klasse immer noch schrecklich teuer sind, werden sie mit zunehmender Adoptionsrate im Preis sinken. Es wurde ausgiebig recherchiert und die Ergebnisse sind ziemlich umwerfend und werden mit der Zeit immer besser, so dass das gesamte Konzept "Alles im Gedächtnis behalten" viel weniger wichtig ist als früher. Daher würde ich versuchen, mich nach Möglichkeit auf die Nebenläufigkeit zu konzentrieren.
quelle
Ich denke, die größte Lektion, die Sie daraus lernen können, ist, dass Sie mit den Grundlagen beginnen müssen:
Während des Leistungstests profilieren Sie Ihren Code, finden die Engpässe und beheben sie nacheinander.
Zu viele Leute springen direkt zum Teil "Nacheinander reparieren". Sie verbringen eine Menge Zeit damit, "benutzerdefinierte Implementierungen der Java-Sammlungen" zu schreiben, weil sie nur wissen, dass der Grund für die Langsamkeit ihres Systems in Cache-Fehlern liegt. Das mag ein Faktor sein, aber wenn Sie direkt daran arbeiten, Code auf niedriger Ebene so zu optimieren, werden Sie wahrscheinlich das größere Problem der Verwendung einer ArrayList verpassen, wenn Sie eine LinkedList verwenden sollten, oder den wahren Grund, warum Ihr System so arbeitet Langsam ist, dass Ihr ORM faul untergeordnete Elemente einer Entität lädt und somit für jede Anforderung 400 separate Fahrten zur Datenbank durchführt.
quelle
Ich werde den LMAX-Code nicht sonderlich kommentieren, da ich denke, dass dies reichlich beschrieben ist. Hier sind jedoch einige Beispiele für Dinge, die ich getan habe und die zu erheblichen messbaren Leistungsverbesserungen geführt haben.
Wie immer sind dies Techniken, die angewendet werden sollten, wenn Sie wissen, dass Sie ein Problem haben und die Leistung verbessern müssen - andernfalls führen Sie wahrscheinlich nur eine vorzeitige Optimierung durch.
Helfen Sie den JIT - Compiler mit final - machen Felder, Methoden und Klassen endgültig ermöglicht spezifische Optimierungen , die wirklich den JIT - Compiler helfen. Spezifische Beispiele:
Ersetzen Sie Auflistungsklassen durch Arrays - dies führt zu weniger lesbarem Code und ist schwieriger zu warten, ist jedoch fast immer schneller, da eine Ebene der Indirektion entfernt wird und viele nützliche Optimierungen für den Arrayzugriff vorgenommen werden. In der Regel eine gute Idee in inneren Schleifen / leistungsempfindlichem Code, nachdem Sie ihn als Engpass identifiziert haben. Vermeiden Sie dies jedoch aus Gründen der Lesbarkeit!
Verwenden Sie nach Möglichkeit Grundelemente. Grundelemente sind grundsätzlich schneller als ihre objektbasierten Entsprechungen. Insbesondere das Boxen erhöht den Overhead erheblich und kann zu unangenehmen GC-Pausen führen. Lassen Sie keine Grundelemente in ein Kästchen zu, wenn Sie Wert auf Leistung / Latenz legen.
Low-Level-Verriegelung minimieren - Schlösser sind auf niedrigem Niveau sehr teuer. Suchen Sie nach Möglichkeiten, um Sperren entweder vollständig zu vermeiden oder grobkörnig zu sperren, sodass Sie nur selten große Datenblöcke sperren müssen und der Code auf niedriger Ebene fortgesetzt werden kann, ohne sich um Sperren oder Parallelitätsprobleme kümmern zu müssen.
quelle
final
einige JITs könnte es herausfinden, andere könnten es nicht. Es hängt von der Implementierung ab (ebenso wie viele Tipps zur Leistungsoptimierung). Vereinbaren Sie die Zuteilungen - Sie müssen dies benchmarken. Normalerweise habe ich festgestellt, dass es besser ist, Zuordnungen zu entfernen, aber YMMV.Anders als bereits in einer hervorragenden Antwort von Aaronaught erwähnt, möchte ich darauf hinweisen, dass es schwierig sein kann, solchen Code zu entwickeln, zu verstehen und zu debuggen. "Während es sehr effizient ist ... ist es sehr einfach, Fehler zu machen ...", wie einer ihrer Kollegen im LMAX-Blog erwähnte .
Vor diesem Hintergrund denke ich, dass diejenigen, die Disruptor und ähnliche Ansätze wählen, besser sicherstellen, dass sie über ausreichende Entwicklungsressourcen verfügen, um ihre Lösung aufrechtzuerhalten .
Insgesamt erscheint mir der Disruptor-Ansatz recht vielversprechend. Auch wenn Ihr Unternehmen es sich nicht leisten kann, es beispielsweise aus den oben genannten Gründen zu nutzen, sollten Sie Ihr Management davon überzeugen, einige Anstrengungen in das Studium zu "investieren" (und SEDA im Allgemeinen) - denn wenn dies nicht der Fall ist, besteht die Möglichkeit, dass dies eines Tages geschieht Ihre Kunden werden sich für eine wettbewerbsfähigere Lösung entscheiden, die 4x, 8x usw. weniger Server erfordert.
quelle