ディスクに書き込むことなく、プロセスのスワップされたメモリをすべてスワップからすばやく引き出すにはどうすればよいでしょうか。
質問を必要とする体系的な問題は他の当事者によって処理されているため、この問題のコンテキストは些細なものです。ただし、現在、ロードとIO待機が非常に高いときに、OpenVZノードのスワップスペースを頻繁に解放しなければならないという問題があります。
スワップは、多くの場合、個々のコンテナで実行されている少数のMySQLおよびclamdプロセスによって主に消費されます。これらのサービスを再起動すると、スワップが解放され、ノードの問題が解決されますが、明らかな理由から望ましくありません。
ノードが過負荷になっていて、現在の方法よりも高速なものが必要なときに、これらのプロセスからスワップをすばやく解放する方法を探しています。
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
このコアダンプはすべてのRAMにアクセスを強制するため、スワップからRAMを引き出す役割を果たしますが、ファイルへの書き込みを回避する方法はまだ見つかりません。また、現在スワップされているアドレス範囲を分離し、その部分を/ dev/nullにダンプできれば、プロセスは速くなるようですが、それを行う方法はまだ見つかりません。
これは巨大なノードであるため、通常のスワップオフ/スワポン方式は非常に時間がかかります。また、ノードの構成は私の制御下にないため、根本原因の修正はこの質問の一部ではありません。ただし、何も強制終了/再開せずにスワップのかなりの部分をすばやく解放する方法についての洞察をいただければ幸いです。
環境:CentOS 6.7/OpenVZ
後でこれにつまずく可能性のある人のための更新:
Jlongの入力を使用して、次の関数を作成しました。
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;};
少し遅いですが、それ以外の場合はここで要求されたとおりに動作します。スワップで最大のアドレス範囲のみを見つけ、ごくわずかな領域の反復を省略することで、おそらく速度を向上させることができますが、前提は適切です。
実例:
#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
スワップされたメモリの大きなチャンクだけをバルクダンプするための最終的な解決策:
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
この方法がプロセスまたはシステムの正常性にリスクをもたらすかどうか、特に複数のプロセスを同時にループする場合は、まだ判断できていません。これがプロセスやシステムに与える可能性のある潜在的な影響について誰かが洞察を持っている場合は、コメントしてください。
GDBの「dumpmemory」コマンドを使用して同じ結果を達成し、/ dev/nullに書き込むことができます。
/ proc/$ PID/smapsでスワップを解除する必要のある領域を見つける必要があります。/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
次に、-batchモードを使用してgdbコマンドを実行し、関数で使用できるようにします。
[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