
Wir betreiben unser Java-System seit über 2 Jahren, ohne dass es jemals zu einem Systemabsturz gekommen wäre. Wir haben 2 physische Server, auf denen ähnliche Java-Software läuft (2 JVMs auf jedem Server), die einen Cluster bilden. Soweit ich weiß, begannen die Abstürze erst, als wir Core-Pinning und Mappedbus.io für den gemeinsamen Speicherzugriff zwischen 2 JVMs auf einem der Server einführten. Der Systemabsturz ist in 2 Wochen nur 4 Mal aufgetreten, und zwar immer nur auf der Maschine, auf der wir Core-Pinning und den speicherabgebildeten Dateizugriff zwischen den JVMs konfiguriert hatten. Wir haben diese Konfiguration deaktiviert, sodass wir die Kerne nicht auf Spin beim Lesen der speicherabgebildeten Dateien fixieren und unseren primären App-Thread nicht fixieren. Beachten Sie, dass wir mit „fixieren“ auch den Thread meinen, der auf diesem fixierten Kern läuft.
Das ist allerdings rein anekdotisch. Da das System nicht jeden Tag hängt, kann ich nicht mit Sicherheit sagen, ob es etwas mit Core Pinning oder dem Zugriff auf den gemeinsamen Speicher zu tun hat. Wenn Pinning (und Busy Spin) jedoch deaktiviert ist und wir in einer Schleife mit LockSupport.parkNanos(5000) auf den gemeinsamen Speicher zugreifen, scheint es bei uns keine Systemabstürze zu geben.
Die Latenz ist für uns von entscheidender Bedeutung, daher ist diese „Nicht-Ausgelastet“-Konfiguration nur eine vorübergehende Lösung.
Bitte beachten Sie auch, dass ich die Anwendung auf einen identischen Server verschoben habe und dort ebenfalls diesen vollständigen Systemabsturz erlebt habe. Ich kann mir also nicht vorstellen, dass es sich hier um einen Hardwarefehler handelt.
Wenn ich also vor oder nach einem Absturz in den Protokollen herumstöbere, scheint mir dies relevant zu sein. Es gibt mehrere dieser Stapel. Ich poste hier nur den ersten (ich glaube also nicht, dass dies irgendetwas mit Postgres selbst zu tun hat).
kernel: [25738.874778] INFO: task postgres:2155 blocked for more than 120 seconds.
kernel: [25738.874833] Not tainted 5.4.0-050400-generic #201911242031
kernel: [25738.874878] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: [25738.874928] postgres D 0 2155 2056 0x00004000
kernel: [25738.874931] Call Trace:
kernel: [25738.874942] __schedule+0x2e3/0x740
kernel: [25738.874948] ? __wake_up_common_lock+0x8a/0xc0
kernel: [25738.874951] schedule+0x42/0xb0
kernel: [25738.874957] jbd2_log_wait_commit+0xaf/0x120
kernel: [25738.874961] ? wait_woken+0x80/0x80
kernel: [25738.874965] jbd2_complete_transaction+0x5c/0x90
kernel: [25738.874969] ext4_sync_file+0x38c/0x3e0
kernel: [25738.874974] vfs_fsync_range+0x49/0x80
kernel: [25738.874977] do_fsync+0x3d/0x70
kernel: [25738.874980] __x64_sys_fsync+0x14/0x20
kernel: [25738.874985] do_syscall_64+0x57/0x190
kernel: [25738.874991] entry_SYSCALL_64_after_hwframe+0x44/0xa9
kernel: [25738.874993] RIP: 0033:0x7f96dc24b214
kernel: [25738.875002] Code: Bad RIP value.
kernel: [25738.875003] RSP: 002b:00007fffb2abd868 EFLAGS: 00000246 ORIG_RAX: 000000000000004a
kernel: [25738.875006] RAX: ffffffffffffffda RBX: 00007fffb2abd874 RCX: 00007f96dc24b214
kernel: [25738.875007] RDX: 00005635889ba238 RSI: 00005635889a1490 RDI: 0000000000000003
kernel: [25738.875009] RBP: 00007fffb2abd930 R08: 00005635889a1480 R09: 00007f96cc1e1200
kernel: [25738.875010] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
kernel: [25738.875011] R13: 0000000000000000 R14: 000056358899c5a0 R15: 0000000000000001
PS: Dies geschah auch unter 16.04 und Kernel 4.15. Das Upgrade auf 18.04 und 5.0 war ein Versuch, das Systemproblem zu beheben, hat aber keinen Unterschied gemacht.
Außerdem habe ich mir überlegt, dass diese Spur vielleicht nur ein Symptom und nicht das Problem ist. Das heißt, meine Anwendung hat den Server blockiert und andere Prozesse bei der E/A blockiert und diese Fehler erhalten. Da der Server jedoch vollständig einfriert, kann ich den Status meiner Anwendung zu diesem Zeitpunkt nicht ermitteln.
Zusätzliche Informationen als Antwort auf Kommentare
Zunächst möchte ich es noch einmal wiederholen: Ich habe keine soliden Beweise dafür, dass die Kombination aus Core-Pinning und gemeinsam genutztem Speicher der Tropfen ist, der das Fass zum Überlaufen bringt. Auf Grundlage des Änderungsverlaufs und der Ausfälle ist dies jedoch meine beste Vermutung.
Das CPU-Modell ist Intel(R) Xeon(R) CPU E5-2620 v4 @ 2,10 GHz mit Turbo-Boost. Davon gibt es zwei im Server. Ich fixiere die CPU-Nummern 2, 4 und 6, von denen ich annehme, dass sie sich auf derselben physischen CPU befinden. Hyperthreading ist EIN.
Das Setup sieht folgendermaßen aus: JVM-A hat einen fixierten Busy-Spin-Thread, der in die speicherabgebildete Datei X schreibt und aus der speicherabgebildeten Datei Y liest. JVM-B hat einen fixierten Busy-Spin-Thread, der aus der speicherabgebildeten Datei X liest und zurück in die speicherabgebildete Datei Y schreibt. In JVM-B veröffentlicht der fixierte Lese-Thread die Nachricht dann in einem Disruptor-Ringpuffer mit einem fixierten Busy-Spin-Worker. Die Nachricht ist eine Bestellanweisung, die schließlich über diesen Worker an den Markt gesendet wird. Dies ist eine Handelsplattform mit geringer Latenz.
Dieser Beitrag bietet eine bessere Erkundung von LockSupport.parkNanos als ich es hier kannhttps://hazelcast.com/blog/locksupport-parknanos-under-the-hood-and-the-curious-case-of-parking/
Ich habe 2 10.000-U/min-Festplatten in RAID 1 mit integriertem RAID-Controller.
Was die Ziellatenz betrifft, könnten wir theoretisch die beiden JVMs zu einer zusammenführen und diesen Memory Mapped File Channel vollständig loswerden. Davor müssen jedoch noch andere Überlegungen angestellt werden, möchte ich mich zunächst auf das Verständnis dieses technischen Problems konzentrieren.
Schließlich läuft Postgres auf diesem Server nur im Wiederherstellungsmodus, es ist nicht der primäre Server. Außerdem führt unser System überhaupt nicht viel Datenbank-E/A aus. Es wird eigentlich nur zum Bootstrapping und für den Tagesbeginn verwendet und speichert die Handelsaktivität des Tages über Nacht. Einer der Abstürze ereignete sich zu einem Zeitpunkt, als es fast keine Datenbank-E/A gegeben hätte.
Antwort1
„Blockiert“ bedeutet in diesem Fall, dass hung_task_timeout_secs
sich eine Aufgabe so lange im unterbrechungsfreien Zustand D befand. 120 Sekunden sind eine ziemlich außergewöhnliche Zeitspanne für E/A-Vorgänge.
Starten Sie eine Überwachung, die Messdaten von diesem Host abrufen kann.Netzdatenist dafür gut geeignet, da es jede Sekunde eine Menge Zeug im Speicher sammelt, also nicht viel Festplatten-E/A. Und hat schöne Grafiken.
Überprüfen Sie die Festplattenlatenz, z. B. mit iostat -xz 1
. Wartezeiten über einstellige Millisekunden sind nicht gut. Teilen Sie mit, um welchen Speicher es sich handelt: Spindeln, Solid State, SAN-LUNs.
Was das Spinning und Pinning betrifft, habe ich den Verdacht, dass Sie den Scheduler zum Aushungern zwingen. Teilen Sie uns das betreffende CPU-Modell mit und welche Kerne Sie für was pinnen. Wie wird das LockSupport.parkNanos()
umgesetzt?
Überprüfung : Es ist nicht gut, vmstat 1
wenn sich viele Aufgaben ständig im Ausführungs- r
oder nicht unterbrechungsfreien Zustand befinden.b
Erwägen Sie die Installation von BPF und die Verwendung von Skripts zum Sammeln von Taskdiagnosen.runqslower
zeigt wartende Aufgaben über einem bestimmten Schwellenwert an. Sehr schnell ist ideal. Beachten Sie, dass die Schwellenwerteinheiten Mikrosekunden sind.
Machen Sie einen Moment Abstand und betrachten Sie das Design dieses Dings.
Was genau ist das Latenzziel, was soll wie schnell ausgeführt werden?
Gibt es einen Grund, warum Postgres auf demselben Host ausgeführt wird? Wenn es remote wäre und über TCP aufgerufen würde, wäre seine E/A kein Problem für die JVM-Anwendung.
Antwort2
Ok, also war das Problem letztendlich ganz einfach. Bei meinen isolierten Tests konnte die Maschine nie abstürzen, weil mir dieses eine Element in meinem Testcode fehlte. Das Problem hat an und für sich nichts mit dem gemeinsamen Speicher oder der Kernfixierung zu tun. Es ist nur so, dass die Isolierung der Kerne die verfügbare gemeinsame Ressource leicht reduzierte, bis zu dem Punkt, an dem der Scheduler ausgehungert werden konnte, weil ...
Beide JVMs wurden mit Echtzeitpriorität eingestellt unter Verwendung von
sudo renice -n -20 $!
sudo chrt -r -a -p 99 $!
Die gesamte JVM wurde hochgestuft, sodass insgesamt fast 300 Threads die höchste Priorität hatten. Kontextwechsel über 150.000/s, selbst bei relativ geringer CPU-Auslastung.
Wir haben die Nettigkeit verlassen und die Echtzeitänderung entfernt. Dies scheint das Problem behoben zu haben. Das ursprüngliche Ziel der alten RT-Einstellung kann erreicht werden, indem wir ändern, wie wir Busyspin/Pinning/C-States/P-States usw. verwenden.