当 CPU/内存使用率过高时,Bash 脚本会自动终止进程

当 CPU/内存使用率过高时,Bash 脚本会自动终止进程

我创建了一个脚本,如果 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)。您还可以考虑更改这些进程的调度程序优先级(使用nicerenice),或者更彻底地使用sched_setscheduler将策略更改为SCHED_IDLE

如果您需要更多控制,请查看控制组 (cgroup)。根据您运行的内核,您实际上可以限制整组进程共同消耗的 CPU 时间、内存、I/O 等量。对照组相当灵活;他们很可能可以做你想做的任何事情,没有任何脆弱的缺陷。 Arch Linux Wiki 有cgroup 简介值得一读,因为Neil Brown 的 cgroups 系列在LWN。

答案2

问题:

  • 对数字字段进行排序时,您可能需要使用选项-nsort -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 commandps -eo pid,pcpu,command
  • 有一个空else子句。这看起来总是应该被处理,但并不是出于某种未知的原因。

答案3

我创建了一个脚本,终止进程,如果 CPU 使用率在 YY 秒内大于 XX%,则会终止数组中列出的某些进程,或者终止运行时间超过 ZZ 秒的进程。

  • 您可以在文件顶部设置 XX、YY、ZZ。
  • 您可以使用 ps 或 top 检查进程。
  • 还有一个试运行模式,可以检查但不能杀死。
  • 最后,如果某些进程被终止,脚本会发送一封电子邮件。

笔记:这是我在 Github 上的存储库:https://github.com/padosoft/kill-process

这是一个屏幕截图:

         1号

参考

脚本的基本部分(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这里

另请注意,“进程使用的内存”是一个模糊的概念,因为存在共享库、可执行文件,甚至部分数据区域。人们可以通过向每个用户收取一小部分已用空间来得出一些数字,但即使将其加起来,也实际上并不能给出“已使用的内存”(甚至更少的“如果进程消失则释放的内存”,共享的部分仍然存在)在后面)。

相关内容