我创建了一个脚本,如果 CPU 和/或内存使用率达到 80%,该脚本会终止进程。发生这种情况时,它会创建一个已终止进程的列表。我可以做什么来改善它?
while [ 1 ];
do
echo
echo checking for run-away process ...
CPU_USAGE=$(uptime | cut -d"," -f4 | cut -d":" -f2 | cut -d" " -f2 | sed -e "s/\.//g")
CPU_USAGE_THRESHOLD=800
PROCESS=$(ps aux r)
TOPPROCESS=$(ps -eo pid -eo pcpu -eo command | sort -k 2 -r | grep -v PID | head -n 1)
if [ $CPU_USAGE -gt $CPU_USAGE_THRESHOLD] ; then
kill -9 $(ps -eo pid | sort -k 1 -r | grep -v PID | head -n 1) #original
kill -9 $(ps -eo pcpu | sort -k 1 -r | grep -v %CPU | head -n 1)
kill -9 $TOPPROCESS
echo system overloading!
echo Top-most process killed $TOPPROCESS
echo CPU USAGE is at $CPU_LOAD
else
fi
exit 0
sleep 1;
done
答案1
我是猜测您想要解决的问题是,您的盒子上运行着一些进程,这些进程有时会出现问题,并且永远固定在核心上。
您要做的第一件事就是尝试修复出现问题的程序。这是迄今为止最好的解决方案。我假设这是不可能的,或者你需要一个快速的工具来保持你的盒子运行直到它被修复。
您至少希望限制您的脚本仅命中您关心的一个程序。如果权限像这样限制您的脚本,那就最好了(例如,您的脚本以用户 X 身份运行,以 X 身份运行的唯一其他东西就是程序)。
更好的是使用诸如ulimit -t
限制程序可以使用的总 CPU 时间之类的东西。同样,如果它消耗了所有内存,请检查ulimit -v
.内核强制执行这些限制;有关详细信息,请参阅bash
联机帮助页(它是内置的 shell)和setrlimit(2)
联机帮助页。
如果问题不是进程失控,而是运行的进程过多,则实施某种形式的锁定以防止超过 X 的进程运行(或者——这应该很熟悉—— ulimit -u
)。您还可以考虑更改这些进程的调度程序优先级(使用nice
或renice
),或者更彻底地使用sched_setscheduler
将策略更改为SCHED_IDLE
。
如果您需要更多控制,请查看控制组 (cgroup)。根据您运行的内核,您实际上可以限制整组进程共同消耗的 CPU 时间、内存、I/O 等量。对照组相当灵活;他们很可能可以做你想做的任何事情,没有任何脆弱的缺陷。 Arch Linux Wiki 有cgroup 简介值得一读,因为Neil Brown 的 cgroups 系列在LWN。
答案2
问题:
- 对数字字段进行排序时,您可能需要使用选项
-n
:sort -nrk 2
。否则,值为 5.0 的行%CPU
最终将高于值为 12.0 的行。 - 根据您的
ps
实现,您可能希望使用该--no-headers
选项来摆脱grep -v
.这可以防止您丢弃包含PID
. - 我猜
echo CPU USAGE is at $CPU_LOAD
你的意思是不是echo CPU USAGE is at $CPU_USAGE
。 - 我猜您忘记删除
exit 0
在调试期间插入的内容(?)。
风格:
- 您可能希望将该
CPU_USAGE_THRESHOLD=800
行移至文件的开头,因为这是信息最丰富的内容,并且即使在脚本稳定后也很可能发生更改。 - 您正在重复该
-e
选项:与(as is )ps -eo pid -eo pcpu -eo command
相同。ps -eo pid -o pcpu -o command
ps -eo pid,pcpu,command
- 有一个空
else
子句。这看起来总是应该被处理,但并不是出于某种未知的原因。
答案3
我创建了一个脚本,终止进程,如果 CPU 使用率在 YY 秒内大于 XX%,则会终止数组中列出的某些进程,或者终止运行时间超过 ZZ 秒的进程。
- 您可以在文件顶部设置 XX、YY、ZZ。
- 您可以使用 ps 或 top 检查进程。
- 还有一个试运行模式,可以检查但不能杀死。
- 最后,如果某些进程被终止,脚本会发送一封电子邮件。
笔记:这是我在 Github 上的存储库:https://github.com/padosoft/kill-process
这是一个屏幕截图:
参考
脚本的基本部分(top命令的代码摘要):
#!/usr/bin/env bash
#max cpu % load
MAX_CPU=90
#max execution time for CPU percentage > MAX_CPU (in seconds 7200s=2h)
MAX_SEC=1800
#sort by cpu
SORTBY=9
#define a processes command name to check
declare -a KILLLIST
KILLLIST=("/usr/sbin/apache2" "/usr/bin/php5-cgi")
#iterate for each process to check in list
for PROCESS_TOCHECK in ${KILLLIST[*]}
do
#retrive pid with top command order by SORTBY
PID=$(top -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $1}')
CPU=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $9}')
TIME_STR=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $11}')
# Decode the top CPU time format [dd-]hh:mm.ss.
TIME_SEC=0
IFS="-:" read c1 c2 c3 c4 <<< "$TIME_STR"
#with top command time format is hh:mm.ss, so truncare seconds in c2
c2=${c2%%.*}
if [ -n "$c4" ]
then
TIME_SEC=$((10#$c4+60*(10#$c3+60*(10#$c2+24*10#$c1))))
elif [ -n "$c3" ]
then
if [ "$CMD" = "ps" ]; then
TIME_SEC=$((10#$c3+60*(10#$c2+60*10#$c1)))
else
TIME_SEC=$(((10#$c3*24)*60*60)+60*(10#$c2+60*10#$c1))
fi
else
if [ "$CMD" = "ps" ]; then
TIME_SEC=$((10#0+(10#$c2+60*10#$c1)))
else
TIME_SEC=$((10#0+60*(10#$c2+60*10#$c1)))
fi
fi
#check if need to kill process
if [ $CPU -gt $MAX_CPU ] && [ $TIME_SEC -gt $MAX_SEC ]; then
kill -15 $PID
fi
done
用法:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]
答案4
杀死使用大部分 CPU/内存的进程是自找麻烦:只要看看它们现在在你的机器上是什么(这里当前是 firefox、systemd (init)、Xorg、gnome-terminal、一组内核线程、xemacs;其中缺一不可)。例如,看看如何调整 Linux 的 OOM-killer这里。
另请注意,“进程使用的内存”是一个模糊的概念,因为存在共享库、可执行文件,甚至部分数据区域。人们可以通过向每个用户收取一小部分已用空间来得出一些数字,但即使将其加起来,也实际上并不能给出“已使用的内存”(甚至更少的“如果进程消失则释放的内存”,共享的部分仍然存在)在后面)。