Bra*_*n D 10 process centos swap openvz
如何在不写入磁盘的情况下快速将进程的所有交换内存从交换中拉出?
这个问题的背景是微不足道的,因为需要这个问题的系统性问题正在由其他各方处理。但是,现在,我遇到了一个问题,我经常不得不在负载和 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
Run Code Online (Sandbox Code Playgroud)
此核心转储强制访问所有 ram,从而完成将其从交换区中拉出的工作,但我尚未找到避免将其写入文件的方法。此外,如果我可以隔离当前交换的地址范围并将该部分转储到 /dev/null,该过程似乎会更快,但我还没有找到一种方法来做到这一点。
这是一个巨大的节点,所以通常的 swapoff/swapon 方法非常耗时,而且节点的配置不在我的控制之下,所以修复根本原因不是这个问题的一部分。但是,任何有关如何在不杀死/重新启动任何东西的情况下快速释放大部分交换的见解将不胜感激。
环境: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;};
Run Code Online (Sandbox Code Playgroud)
它有点慢,但完全按照这里的要求执行。可能可以通过仅查找交换中的最大地址范围并省略微不足道的小区域的迭代来提高速度,但前提是合理的。
工作示例:
#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
Run Code Online (Sandbox Code Playgroud)
仅批量转储大块交换内存的最终解决方案:
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
Run Code Online (Sandbox Code Playgroud)
我还没有确定这种方法是否会对进程或系统的健康构成任何风险,尤其是在同时循环多个进程时。如果有人了解这可能对流程或系统产生的任何潜在影响,请随时发表评论。
小智 9
您可以通过使用 GDB 的“转储内存”命令并将其写入 /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
Run Code Online (Sandbox Code Playgroud)
然后使用 --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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1389 次 |
最近记录: |