Den gesamten ausgelagerten Speicher eines Prozesses aus dem Swap ziehen


8

Wie würde man schnell den gesamten ausgelagerten Speicher eines Prozesses aus dem Auslager ziehen, ohne auf die Festplatte zu schreiben?

Der Kontext zu diesem Thema ist trivial, da das systemische Problem, das die Frage erfordert, von anderen Parteien behandelt wird. Im Moment habe ich jedoch ein Problem, bei dem ich häufig Swap-Speicherplatz auf einem OpenVZ-Knoten freigeben muss, während das Laden und das Warten auf E / A extrem hoch sind.

Der Swap wird häufig hauptsächlich von einer kleinen Handvoll MySQL- und Clamd-Prozessen verwendet, die auf einzelnen Containern ausgeführt werden. Durch einen Neustart dieser Dienste wird der Austausch freigegeben und das Problem auf dem Knoten gelöst, dies ist jedoch aus offensichtlichen Gründen unerwünscht.

Ich suche nach einer Möglichkeit, den Swap schnell von diesen Prozessen zu befreien, während der Knoten überlastet ist und etwas schnelleres als meine aktuelle Methode benötigt:

unswap(){ [[ $1 && $(ls /proc/$1/maps) ]]  && ((gcore -o /tmp/deleteme $1 &>/dev/null; rm -fv /tmp/deleteme.$1)&) 2>/dev/null  || echo "must provide valid pid";};unswap

Dieser Core-Dump erzwingt den Zugriff auf alle RAMs und erledigt somit die Aufgabe, ihn aus dem Swap herauszuziehen, aber ich habe noch keinen Weg gefunden, um das Schreiben in eine Datei zu vermeiden. Außerdem scheint der Prozess schneller zu sein, wenn ich die derzeit ausgetauschten Adressbereiche isolieren und diesen Teil einfach in / dev / null ausgeben könnte, aber ich habe noch keinen Weg gefunden, dies zu tun.

Dies ist ein riesiger Knoten, daher ist die übliche Swapoff / Swapon-Methode unerschwinglich zeitaufwändig, und auch hier ist die Konfiguration des Knotens nicht unter meiner Kontrolle, sodass die Behebung der Grundursache nicht Teil dieser Frage ist. Jeder Einblick, wie ich einen signifikanten Teil des Swaps schnell freigeben könnte, ohne etwas zu beenden oder neu zu starten, wäre jedoch willkommen.

Umgebung: CentOS 6.7 / OpenVZ

Update für alle, die später darauf stoßen könnten:

Mit Jlongs Eingabe habe ich die folgende Funktion erstellt:

unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;};

Es ist etwas langsam, macht aber genau das, was hier sonst angefordert wurde. Könnte wahrscheinlich die Geschwindigkeit verbessern, indem nur die größten Adressbereiche im Swap gefunden werden und die Iterationen für die trivial kleinen Bereiche weggelassen werden, aber die Prämisse ist solide.

Arbeitsbeispiel:

#Find the process with the highest swap use
[~]# grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n1 | while read line; do fp=$(echo $line | cut -d: -f1); echo $line" "$(stat --format="%U" $fp)" "$(grep -oP "(?<=NameS).*" $fp); done | column -t
/proc/6225/status:VmSwap:   230700  kB  root  mysqld

#Dump the swapped address ranges and observe the swap use of the proc over time
[~]# unswap(){ (awk -F'[ t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; unswap 6225; while true; do grep VmSwap /proc/6225/status; sleep 1; done
VmSwap:   230700 kB
VmSwap:   230700 kB
VmSwap:   230676 kB
VmSwap:   229824 kB
VmSwap:   227564 kB
... 36 lines omitted for brevity ... 
VmSwap:     9564 kB
VmSwap:     3212 kB
VmSwap:     1876 kB
VmSwap:       44 kB
VmSwap:        0 kB

Endgültige Lösung für das Bulk-Dumping nur der großen Teile des ausgetauschten Speichers:

unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>1000{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n20 | cut -d/ -f3 | while read line; do unswap $line; done;echo "Dumps Free(m)"; rcount=10; while [[ $rcount -gt 0 ]]; do rcount=$(ps fauxww | grep "dump memory" | grep -v grep | wc -l); echo "$rcount        $(free -m | awk '/Swap/{print $4}')"; sleep 1; done 

Ich muss noch feststellen, ob diese Methode ein Risiko für den Zustand des Prozesses oder Systems darstellt, insbesondere wenn mehrere Prozesse gleichzeitig durchlaufen werden. Wenn jemand einen Einblick in mögliche Auswirkungen auf die Prozesse oder das System hat, kann er dies gerne kommentieren.


Ich gehe davon aus, dass die "endgültige Lösung" eine große Anzahl von parallelen gdbInstanzen starten kann, wenn der einzutauschende Prozess viele ausgetauschte Fragmente enthält. Das Skript startet eine parallere gdbInstanz für jedes ausgetauschte (große) Fragment für die 20 größten Prozesse. Ich denke, man sollte zumindest | tail -n20nach dem awkÜbergeben der Ergebnisse eine whileSchleife hinzufügen , um die maximale Anzahl von Parallelprozessen auf 400 zu begrenzen.
Mikko Rantalainen

Antworten:


8

Sie können das gleiche Ergebnis erzielen, indem Sie den GDB-Befehl 'dump memory' verwenden und ihn in / dev / null schreiben lassen.

Sie müssen nur die Regionen in / proc / $ PID / smaps finden, die nicht ausgetauscht werden müssen. Beispiel aus / proc / $ PID / smaps:

02205000-05222000 rw-p 00000000 00:00 0 
Size:              49268 kB
Rss:               15792 kB
Pss:                9854 kB
Shared_Clean:          0 kB
Shared_Dirty:      11876 kB
Private_Clean:         0 kB
Private_Dirty:      3916 kB
Referenced:          564 kB
Anonymous:         15792 kB
AnonHugePages:         0 kB
Swap:              33276 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

Verwenden Sie dann den --batch-Modus, um den Befehl gdb auszuführen, damit Sie ihn in Ihrer Funktion verwenden können:

[root@nunya ~]# swapon -s ; gdb --batch --pid 33795 -ex "dump memory /dev/null 0x02205000 0x05222000" ;swapon -s
Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7808096 -1

[Thread debugging using libthread_db enabled]

Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7796012 -1

Gute Idee, ich habe es etwas später verbessert, dann haben andere Leute es im Laufe der Jahre noch weiter verbessert, und es wurde github.com/wiedemannc/deswappify-auto
kubanczyk
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.