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.
gdb
Instanzen starten kann, wenn der einzutauschende Prozess viele ausgetauschte Fragmente enthält. Das Skript startet eine paralleregdb
Instanz für jedes ausgetauschte (große) Fragment für die 20 größten Prozesse. Ich denke, man sollte zumindest| tail -n20
nach demawk
Übergeben der Ergebnisse einewhile
Schleife hinzufügen , um die maximale Anzahl von Parallelprozessen auf 400 zu begrenzen.Antworten:
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:
Verwenden Sie dann den --batch-Modus, um den Befehl gdb auszuführen, damit Sie ihn in Ihrer Funktion verwenden können:
quelle