Hallo, auf der Arbeit entwickele ich gerade ein System, das Produktregeln und Verfügbarkeiten checkt. Ich stehe noch am Anfang und probiere verschiedene Ansätze. Ziel ist es, 20000 Anfragen pro Sekunde von einem Server durchrechnen (plus Daten holen aus Redis) zu lassen, und das Ganze soll durch das Hinzufügen von Servern skalierbar sein. Ein Server hat 32 Kerne und 128 GB Arbeitsspeicher. Programmiersprache ist Java, ich habe einen ersten Versuch (mit einem realistischen Beispielprojekt) mit dem vert.x Framework unternommen, da komme ich auf ~8000 Anfragen pro Sekunde. Problem bei vert.x ist, dass die einzelnen Verticles über den Eventbus kommunizieren, das bedeutet jedesmal Serialisierung und Deserialisierung. Also kann ich die Arbeitspakete nicht so feingranular machen, dass alle CPU Kerne benutzt werden. Mein nächster Ansatz ist jetzt der Disruptor von lmax. Da fällt die Serialisierung weg, sollte also schneller sein. Nun liest man im Internet, dass das vor allem durch die vielen Cache Hits performant sein soll. Ich will also bei der Dimensionierung der RingBuffers prüfen, ob ich viele Cache-Hits habe. Es gibt dafür ja verschiedene Tools (perf, valgrind, perfmon unter Windows, ...). Nun meine Frage: Wer von euch hat denn schon mal eine Anwendung bezüglich ihrer Cache-Hits analysiert? Mit welchem Tool? Welche Cache-Hit Ratio konntet ihr erreichen (ist natürlich von der Problemstellung abhängig, aber mich interessieren trotzdem die Werte aus der Praxis)? Und falls jemand ein Java-Programm analysiert hat: Gibt es da Fallstricke? Muss man den Just-In-Time Compiler ausschalten? Postet doch mal bitte eure Erfahrungen! Viele Grüße! Klaus
Klaus H schrieb: > Wer von euch hat denn schon mal eine Anwendung bezüglich ihrer > Cache-Hits analysiert? Mit welchem Tool? Die Performance-Counter der CPU können bei der Analyse helfen. Zumal es bei Optimierung auf dieser Ebene noch andere Fallstricke gibt, als nur das Caching-Verhalten. So ist bei 32 Kernen und damit 64 parallelen Threads die Parallelisierung der Aufgabe von grosser Bedeutung. Aber da gibt es ein paar Fallen, die genau dies behindern können. Die Optimization Guides der CPU-Hersteller helfen etwas beim Verständnis, aber nicht alle Effekte sind dort klar beschrieben.
:
Bearbeitet durch User
Klaus H schrieb: > Muss man den Just-In-Time Compiler ausschalten? Um auf ein völlig anderes Laufzeitverhalten zu optimieren?
Betreffend JIT-Compiler: Manche Tools bieten dir Rückschlüsse auf Teile des Quelltexts, die schlechte Lokalität haben. Das funktioniert dann angeblich nicht mehr, wenn sie die Instruktionen zur Laufzeit ändern. Die von mir verwendeten Frameworks sehen einen Thread pro Kern des OS (also auch virtuelle Kerne) vor, es sollen also keine Threadwechsel stattfinden. Gegen Vert.x spricht, dass ich die Arbeit nicht so klein stückeln kann, dass alls Kerne etwas zu tun bekommen (denn dann ist der Serialisierungsaufwand größer als der Zeitgewinn durch Parallelisierung). "Perf" arbeitet ja mit den Performance Countern. Ich denke mal, ein Server erreicht da andere Zahlen als z.B. ein Shell-Script. Deswegen interessieren mich da eure Werte, sonst würde ich einfach ein paar Shell Scripte analysieren.
Klaus H schrieb: > Betreffend JIT-Compiler: Manche Tools bieten dir Rückschlüsse auf Teile > des Quelltexts, die schlechte Lokalität haben. Das funktioniert dann > angeblich nicht mehr, wenn sie die Instruktionen zur Laufzeit ändern. JIT ja m.W. heisst nicht, dass der ursprüngliche Bytecode inplace gepatcht wird, sondern irgendwo im Heap neuer nativer Binärcode erzeugt wird. Der kann dann logischerweise ein recht anderes Verhalten haben.
:
Bearbeitet durch User
Klaus H schrieb: > Die von mir verwendeten Frameworks sehen einen Thread pro Kern des OS > (also auch virtuelle Kerne) vor, es sollen also keine Threadwechsel > stattfinden. Konflikte zwischen Threads können nicht nur zwischen den Threads eines Cores auftreten, sondern auch zwischen verschiedenen Cores. Nur andere, d.h. dabei können systematische Cache-Konflikte auftreten. Verticles/Eventbus/Disruptor/... kenne ich nicht. Entscheidend für solche Konflikte ist die Frage, wie die Threads auf gemeinsamen Speicher zugreifen. Da kann es schon vorkommen, dass gemeinsamer Speicher mehr kostet als das Threading bringt und eine Optimierung über TSX kann sinnvoll werden (wenn die CPU das unterstützt).
:
Bearbeitet durch User
Das könnte ein ähnliches Tool sein, wie ich es vor einiger Zeit mal bei AMD verwendet habe. Damit liessen sich Problemstellen aller Art bis auf einzelne Befehle runterbrechen: https://software.intel.com/en-us/articles/intel-software-development-emulator
:
Bearbeitet durch User
OK, danke für die Antworten, verstehe ich dich dann richtig, dass Optimierungsversuche ohne Analyse der Performance Counter sinnlos sind? Oder gibt es noch weitere Kennzahlen, auf die ich achten muss? Zur Info: Der lmax Disruptor besteht aus einem Ringpuffer, und die einzelnen Threads arbeiten auf unterschiedlichen Positionen des Rings. Da die Daten an einem Index im Ring dann nacheinander von jedem Thread mal bearbeitet werden, soll laut Theorie ein gutes Cache-Verhalten erzielt werden. Den Ring-Puffer kann man auf beliebige 2er-Potenzen dimensionieren. Je nachdem, wie groß die Daten im Puffer sind, wird das gut mit dem Cache harmonieren oder nicht (denke ich). Also im Idealfall passen die Daten in eine Cache-Line und der Ringpuffer kann groß dimensioniert werden (8 MB L3-Cache / 32 Byte/CacheLine = 256 k Ringpuffer als Maximum). Wenn die Daten aber relativ groß sind, dann muss der Ringpuffer verkleinert werden. Ich werde es wohl einfach ausprobieren müssen :-)
Sorry, hatte in Zwischenzeit deinen Post mit dem Link zu Intels Toos nicht gesehen. Danke, werde ich mal anschauen!
Klaus H schrieb: > OK, danke für die Antworten, verstehe ich dich dann richtig, dass > Optimierungsversuche ohne Analyse der Performance Counter sinnlos sind? Es heisst, dass ich zu deiner Umgebung mit soundsoviel mir unbekannten Werkzeugen keinen zielgerichteten Kommentar abgeben kann. Wenn das Tools für parallele Programmierung sein sollten, dann wären spezielle Foren dafür der einzig sinnvolle Platz. So arg viele Mikrocontroller mit 32 Threads gibt es noch nicht, und die einzigen dieser Art haben keine Caches. > Zur Info: Der lmax Disruptor besteht aus einem Ringpuffer, und die > einzelnen Threads arbeiten auf unterschiedlichen Positionen des Rings. > Da die Daten an einem Index im Ring dann nacheinander von jedem Thread > mal bearbeitet werden, soll laut Theorie ein gutes Cache-Verhalten > erzielt werden. Dummerweise haben solche Datenstrukturen mitunter einen Engpass: die Metadaten davon (Puffer-Index etc) und die entsprechende Absicherung per Mutex/Spinlock. Bei zeitlich dichtem Zugriff darauf kann der Vorteil der Parallelität im Cache-Pingpong verloren gehen. Genau das führte letztlich zur Entwicklung von TSX.
:
Bearbeitet durch User
Die andere Frage ist ja, ob es da eine so gute Idee ist, eine die Hardware völlig abstrahierende Highlevelsprache wie Java zu nehmen. Wenn man sich über Dinge Gedanken macht, die nicht nur plattformspezifisch sind, sondern auch auf jeder CPU wieder anders laufen, dann widerspricht das doch schon der Grundidee von Java: write once, run everywhere. High-Performance-Hacks gehen damit nicht besonders gut, dazu ist Java auch nicht gedacht. Da müßte man schon C nehmen, da hat man die völlige Controlle über das Speicherlayout. Allerdings wird bei beliebigem Multithreading auf skalierbar drölfzig Kernen die Anwendung dann niemals das Entwicklungsstadium verlassen. Ich würd mir da weniger Gedanken um lowlevel-Optimierungen wie Cache-Hits machen, die sich sowieso mit jeder anderen CPU wieder anders benehmen, sondern um Optimierung auf Architektur-Ebene. Dafür ist Java doch da, da man sich nicht um den Lowlevelkram kümmert. Das bedeutet im Grundsatz schonmal das Benutzen möglichst weniger gemeinsamer Ressourcen. Algorithmische Optimierung schlägt Lowlevel-Optimierung ohnehin meistens.
@Nop: Früher hätte ich dir da Recht gegeben, aber heute sehe ich das etwas anders. Natürlich ist es Unsinn, eine Java Businessanwendung genau auf eine Hardware zuzuschneiden und es ist durch die Sprache auch nicht möglich. Aber der Java-Code kann bestimmte Eigenschaften haben, die ihn auf heutiger Server-Hardware performant macht (Benutzung von möglichst vielen Kernen, wenige Locks, wenige Threadwechsel,...).
Hier noch etwas Feedback zum Tool "Intel SDE": Es gibt keine Schwierigkeiten, das zu Installieren. Laufen lässt man dann das Programm mit dem Befehl sde -omix out.mix -ofootprint out.foot -- d:\dev\jdk8\jre\bin\java -jar d:\disruptor-1.0-SNAPSHOT.jar Wichtig ist, den Pfad zu java absolut anzugeben, das SDE ignoriert den PATH und findet dann evtl. ein JRE in der falschen Version. Die Anwendung muss terminieren, damit das tool seine Statistiken schreibt. Also beendet sich mein Projekt nach 20 Requests selbst mit System.exit(0). Das ganze ist sehr sehr sehr langsam, erstens wegen der Instrumentierung und zweitens kann SDE auch Instuktionen der CPU simulieren, man kann dem Programm damit vorgaukeln, es würde auf einer moderneren CPU laufen. Der Footprint enthält Informationen über Caches, aber da ist das Linux-Tool perf schon etwas gesprächiger. Ich hänge mal einen footprint an diesen Beitrag an, falls es jemanden interessiert. Für die Analyse von Java-Applikationen hat Intel noch eine interessante Homepage: https://software.intel.com/en-us/articles/java-applications-require-multi-level-analysis
Besorge Dir mal das Buch "Java Performance: The Definitive Guide" von Scott Oaks. Es erklärt viele Fallstricke, Dinge die man eventuell besser machen kann und alle Tuning Parameter der JVM. Es erklärt auch, wie man die Peformance von Java Programmen mit Java, Profiler und Betriebsystem Mitteln analysiert. Und besorge Dir das Buch "Effective Java" von Joshua Bloch. Auch dieses Buch erklärt einige Dinge, die sich performance verbessernd auswirken.
A. K. schrieb: > Wenn das Tools > für parallele Programmierung sein sollten, dann wären spezielle Foren > dafür der einzig sinnvolle Platz. So arg viele Mikrocontroller mit 32 > Threads gibt es noch nicht, und die einzigen dieser Art haben keine > Caches. Du bist im falschen Forum: "Programmierung auf PCs, Algorithmen, allgemeine Programmierfragen ohne direkten Mikrocontroller-Bezug."
Markus L. schrieb: > Du bist im falschen Forum: "Programmierung auf PCs, Algorithmen, > allgemeine Programmierfragen ohne direkten Mikrocontroller-Bezug." Ist mir klar. Dennoch gehe ich davon aus, dass solche Fragen besser dort aufgehoben sind, wo man Werkzeuge und Programmiertechnik für hohen Parallelisierungsgrad zum Thema hat.
:
Bearbeitet durch User
Klaus H schrieb: > Aber der Java-Code kann bestimmte Eigenschaften haben, die ihn > auf heutiger Server-Hardware performant macht (Benutzung von möglichst > vielen Kernen, wenige Locks, wenige Threadwechsel,...). Ja, das meinte ich mit meinem dritten Absatz, mit Optimierung auf Architekturebene. Da stimme ich Dir auch zu z.B. mit der Minimierung von Locks, weswegen ich ja anregte, möglichst wenige gemeinsame Ressourcen zu nutzen. Diese machen ja Locks überhaupt erst nötig.
Und Architektur ist mal wieder nicht genau definiert. Für mich ist es schon eine Optimierung auf Architekturebene, wenn ich anderen Entwicklern sagen kann: "Unsere Logik teilen wir in Arbeitspakete auf, die jeweils max. eine I/O Operation machen. Diese Arbeitspakete werden dann in einer Reihenfolge (oder bei parallelen Paketen auch Reihenfolgenagnostisch) als Consumer an den Ringpuffer gehängt. Und es gibt nur einen Producer". Auf jeden Fall vielen Dank für alle bisherigen Antworten, das hilft mir schon beim Durchdenken weiter. Wenn ich die Analyse mit "perf" mal gemacht habe gebe ich hier nochmal Feedback.
Das einfachste wäre natürlich eine CPU mit mehr Cache zu nehmen. SPARC M7 hat 32 Cores und 256 Threads. Und nicht dieses lächerliche Intel-Gehampel.
Vielleicht ist hier jemand an Feedback interessiert: Ich habe als Ausgangsbasis Benchmarks mit JMH (openJDK) erstellt. Zunächst sollte man den "comp" JustInTimeCompiler-Profiler aktivieren, und die Warmup-Interationen solange erhöhen, bis nach dem Warmup kein Code mehr kompiliert wird. In meinem Fall gab es dann noch deutliche Schwankungen des Durchsatzes der einzelnen Iterationen. Deshalb habe ich den Speicher für die JVM begrenzt (von 1 GB runter auf 320 MB). Dann läuft die GarbageCollection häufiger, aber schneller. Auf dafür bringt JMH einen Profiler mit. Am Ende hat man dann ein Artefakt, das Vergleichsmessungen ermöglicht. An dem Punkt stehe ich jetzt, jetzt muss ich die Kollegen vom Build überreden, dass sie die JMH-Tests über ein Jenkins-Plugin ausführen. Und ich werde mit dem linux-Perf die CacheHits untersuchen. Siehe auch http://www.brendangregg.com/linuxperf.html
@Klaus Dein optimierungsansatz ist zwar löblich, allerdings wird man in der Praxis einfach zwei server nehmen um den Durchsatz zu erreichen. Viel wichtiger als die Geschwindigkeit ist die Stabilität bei solchen geschäftskritischen Anwendungen. Überleg dir daher ob es sich überhaupt lohnt an der Stelle weiterzumachen oder ob man eher an der globalen Architektur arbeiten sollte um es effizienter zu bekommen..
Ist das nicht so ein Thema mit Java und Cache Misses? Da man in Java prinzipiell alles mit Referenzen zu pflastert (gibt ja keine Möglichkeit eigene Wertetypen zu definieren), liegen die Speicherbereiche weiter auseinander.
Klaus H schrieb: > Programmiersprache ist Java, ich habe einen ersten Versuch (mit einem > realistischen Beispielprojekt) mit dem vert.x Framework unternommen, da > komme ich auf ~8000 Anfragen pro Sekunde. Problem bei vert.x ist, dass > die einzelnen Verticles über den Eventbus kommunizieren, das bedeutet > jedesmal Serialisierung und Deserialisierung. Also kann ich die > Arbeitspakete nicht so feingranular machen, dass alle CPU Kerne benutzt > werden. Was sagen denn die klassischen Systemwerkzeuge {io,vm,mp}stat, top und SAR?
L1-Cache schrieb: > Ist das nicht so ein Thema mit Java und Cache Misses? Da man in Java > prinzipiell alles mit Referenzen zu pflastert (gibt ja keine Möglichkeit > eigene Wertetypen zu definieren), liegen die Speicherbereiche weiter > auseinander. Ist nur ein Thema, wenn die referenzierten Daten wesentlich kleiner als eine Cache-Line sind (64 Bytes), und deshalb eine Art Fragmentierung auftritt. Bei Cache-Lines selbst ist unerheblich, ob die nebeneinander liegen, oder weit entfernt.
Klaus H schrieb: > auf der Arbeit entwickele ich gerade ein System, das Produktregeln und > Verfügbarkeiten checkt. Ich stehe noch am Anfang und probiere > verschiedene Ansätze. Ziel ist es, 20000 Anfragen pro Sekunde von einem > Server durchrechnen (plus Daten holen aus Redis) zu lassen wäre es nicht auch ein Ansatz, diese Produktregeln und Verfügbarkeiten zumindest teilweise vorzuberechnen und in einer Datenbank abzulegen? Gerade wenn sich die Daten nur seltener ändern, dafür aber oft abgefragt werden, ist sowas oft eine effiziente Möglichkeit die Abfragen zu beschleunigen.
Toll, dass hier noch ein paar Beiträge kommen! Die Vorberechnung von Produktregeln ist keine Option, die Daten müssen mindestens tagesaktuell sein. Da sich durch Kombinatorik so viele Möglichkeiten ergeben, müßte die Vorberechnung so schnell sein, dass das keinen Vorteil gegenüber einer Live-Berechnung bietet. Zum Thema Cache-Misses und Java: Durch die Referenzen liegen die Objekte verstreut im Speicher. Für die Cache-Lines ist das, wie A.K. schon gesagt hat, egal. Aber für die Cache-Lokalität ist es besser, wenn die Objekte nah beieinanderliegen, weil die CPU dann schon spekulativ angrenzende Speicherbereiche in den Cache legt. Dafür gibt es meines Wissens 2 Optimierungsmöglichkeiten: - Arbeiten mit binären Arrays, in denen die Daten stecken. Um die Arrays kann man sich noch Wrapper mit Getter/Setter legen. - Einmalige Erzeugung von Objekten in einer Schleife. Ohne Garantie kann man darauf hoffen, dass so erzeugte Objekte nah beieinander im Speicher liegen. Die zu verarbeitenden Daten werden dann in Objekte aus diesem Pool kopiert. Ist halt immer ein Kompromiss :-). Deshalb will ich erstmal messen, ob meine Anwendung beim Caching Performance verschenkt, bevor ich etwas optimiere. @TestX: ja, es werden im Moment schon 2 Server eingesetzt, und es kann weiter skaliert werden. Aber was sind schon die Kosten eines Entwicklers gegen Hardware und nötige Lizenzen. Vor allem, wenn die Firma noch im Budgetdenken feststeckt und dann die nötige Hardware erst in einem Jahr beschafft werden kann.
Klaus H. schrieb: > Aber was sind schon die Kosten eines Entwicklers gegen > Hardware und nötige Lizenzen. Machst du Witze?
Klaus H. schrieb: > Die Vorberechnung von > Produktregeln ist keine Option, die Daten müssen mindestens tagesaktuell > sein. Da sich durch Kombinatorik so viele Möglichkeiten ergeben, müßte > die Vorberechnung so schnell sein, dass das keinen Vorteil gegenüber > einer Live-Berechnung bietet. Ja, komplett vorberechnen funktioniert meist nicht. Aber kann man nicht evtl. teilweise vorberechnen? Also z.B. Gruppen bilden und dann deren Teilergebnisse vorberechnen und speichern. Dann muss die Live-Abfrage nur noch die vorberechneten Gruppen abfragen und kombinieren anstatt immer von Adam und Eva an neu zu berechnen. > ja, es werden im Moment schon 2 Server eingesetzt, und es kann weiter > skaliert werden. Aber was sind schon die Kosten eines Entwicklers gegen > Hardware und nötige Lizenzen. Vor allem, wenn die Firma noch im > Budgetdenken feststeckt und dann die nötige Hardware erst in einem Jahr > beschafft werden kann. Das wäre mal ne Aufgabe die Du an Deinen Chef vergeben kannst: hier die Strukturen anpassen und auf die Höhe der Zeit bringen. Dynamisch Rechenleistung bei Bedarf anzufordern (entweder aus dem eigenen RZ oder zugemietet bei Dienstleistern) und zuzuschalten ist da eigentlich Stand der Technik (und deren Organisation). Nen Jahr für die Entscheidung für nen neuen Rechner zu brauchen war schon im letzten Jahrzehnt nicht mehr zeitgemäß.
Hier nochmal für Interessierte ein Link auf eine Klasse, die "etwas" optimiert wurde. Ist auch gut kommentiert, warum das so gemacht wurde. http://hg.openjdk.java.net/code-tools/jmh/file/cde312963a3d/jmh-core/src/main/java/org/openjdk/jmh/logic/BlackHole.java
Klaus H schrieb: > auf der Arbeit entwickele ich gerade ein System, das Produktregeln und > Verfügbarkeiten checkt. Ich stehe noch am Anfang und probiere > verschiedene Ansätze. Ziel ist es, 20000 Anfragen pro Sekunde von einem > Server durchrechnen (plus Daten holen aus Redis) zu lassen, und das > Ganze soll durch das Hinzufügen von Servern skalierbar sein. Vielleicht liege ich falsch, aber nach dem, was ich auf die Schnelle über vert.x und LMAX' Disruptor gelesen habe, dienen diese beiden Werkzeuge der Kommunikation zwischen verschiedenen Threads und Prozessen. Leider weiß ich zu wenig über Deinen Anwendungsfall, aber möglicherweise könnten Ansätze aus dem Distributed Computing wie zum Beispiel Apache Spark oder Apache Storm die Forderung nach horizontaler Skalierung besser erfüllen.
Die horizontale Skalierung läuft über Redis. Die Arbeitspakete werden in eine Redis-Queue gePUSHt (blödes Wort), und und somit können beliebig viele Instanzen, die nichts voneinander wissen, die Arbeitspakete abarbeiten. Hat sich voll bewährt, Redis ist sehr schnell (Zugriffszeiten bei Datenpakenten von 1 kB: < 1ms), nur bei der Serialisierung/Deserialisierung muss man sich etwas Gedanken machen. Wenn die Redis-Performance nicht mehr ausreicht, dann kann die Queue immer noch nach Produkttyp auf mehrere Redis-Instanzen verteilt werden. Ich weiß nicht, ob hier im Forum noch mehr Diskussion gewünscht wird, denn im Moment habe ich keine Fragen mehr. Ich kann halt, falls gewünscht, Erfahrungen posten: Der LMAX Disruptor funktioniert analog zu einer CPU-Pipeline. Ich teile mein Arbeitspaket in mehrere Teilschritte auf, und jedes Element im Ringpuffer durchläuft dann jeden Teilschritt (voneinander unabhängige Teilschritte können auch Out-of-Order durchlaufen werden). Wie bei einer Pipeline bestimmt dann der längste Teilschritt den "Takt". Also muss immer wieder der längste Teilschritt bestimmt werden, und dann entweder optimiert oder weiter aufgeteilt werden (wobei die max. Anzahl der Teilschritte wiederum durch die Anzahl der CPUs begrenzt wird). Mein längster Teilschritt (mit I/O über einen lokalen TCP-Socket) liegt im Moment bei 900 ns, die kürzesten bei ~100 ns. Mein Ziel ist es, dass die Teilschritte < 500 ns dauern. Dazu habe ich auch ein paar Ideen...
Klaus H. schrieb: > Die horizontale Skalierung läuft über Redis. Klar, aber das betrifft ja nur den Speicher. Meine Idee zielte eher darauf ab, auch die CPU-Last horizontal zu skalieren. Welchen Redis-Client benutzt Du denn in Java?
Ich benutze Jedis. Die Arbeitspakete liegen in einer Redis-Queue, und an diese Queue kann man dann beliebig viele Instanzen hängen, die die Arbeitspakete abarbeiten. Ist es das, was du mit "horizontaler Skalierung" meinst? Die Consumer am Ringpuffer laufen jeweils in einem eigenen Thread, damit wird pro Teilschritt eine CPU verwendet. Wenn es keinen Stau im Ringpuffer gibt, als die Teilschritte gleich schnell sind, dann ergibt sich eine optimale CPU-Auslastung. Nehmen wir an, der Prozess braucht 8 CPUs, und der Server hat 32. Dann werden mit Hilfe von Docker 2 Container deployed, die zusammen 16 CPUs belegen. Oder, je nach Last, können auch 4 Container deployed werden. Oder auch 8 Container auf 2 Servern.
--- schrieb: > Das einfachste wäre natürlich eine CPU mit mehr Cache zu nehmen. > SPARC M7 hat 32 Cores und 256 Threads. > Und nicht dieses lächerliche Intel-Gehampel. Je größer der Cache, desto langsamer der Cache. Je länger der Tag, desto mehr erzählt Larry.
Larry schrieb: >> Und nicht dieses lächerliche Intel-Gehampel. > > Je größer der Cache, desto langsamer der Cache. Unabhängig vom Wahrheitsgehalt dieser Aussage: SPARC M7: 16KB L1 Cache pro Core Intel: 64KB L1 Cache pro Core
Klaus H. schrieb: > Ich benutze Jedis. > Die Arbeitspakete liegen in einer Redis-Queue, und an diese Queue kann > man dann beliebig viele Instanzen hängen, die die Arbeitspakete > abarbeiten. Du meinst eine Redis "List", an die ein Provider mit RPUSH Elemente anhängt, die Deine Consumer sich dann mit BLPOP abholen? > Ist es das, was du mit "horizontaler Skalierung" meinst? Mit "horizontaler Skalierung" meine ich eine Skalierung, die über die Anzahl der Maschinen skaliert, im Gegensatz zu einer vertikalen Skalierung, welche über den Austausch von vorhandenen über größere Maschinen skaliert. > Die Consumer am Ringpuffer laufen jeweils in einem eigenen Thread, damit > wird pro Teilschritt eine CPU verwendet. Mir ist noch nicht ganz klar, wozu Du den Ringpuffer benötigst.
Technisch gesehen eine Redis List, aber nach dem "Reliable Queue" Pattern von Redis: https://redis.io/commands/rpoplpush Der Ring-Puffer soll Objekte, die "nebeneinander" im Speicher liegen, beinhalten. Das begint, dass nicht jedes Mal ein neues Objekt erzeugt wird, sondern bestehende werden wiederverwendet. Da bietet sich ein Ringpuffer an.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.