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


11

我创建了一个脚本,该脚本可以在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

3
您是否尝试过运行脚本?while [ 1 ]让我想知道仅此脚本将消耗多少CPU。另外,kill -9在脚本中有3个调用持续运行吗?这让我发冷...
rahmu

1
无论如何,都是不错的头像,@ rahmu他sleep 1在循环中
雏菊

1
该月的第一个星期一,我的电脑正在检查(慢速)RAID6集。CPU负载很容易达到8以上的峰值,因为它一直在等待来自此RAID集的磁盘IO。没错,系统仍然非常灵敏。您的脚本将杀死我的firefox,它仅使用可用400%的3.6%。只是说您可能正在使用此脚本寻找鬼魂。顺便说一句:您的系统不会因为高负载而受损,并且当内存用完时,内核将对要终止的进程进行半有根据的猜测。
jippie

然后基于负载的终止进程会很好吗????
Ketan Patel

在我的用例中,不需要杀死它。
jippie 2013年

Answers:


11

猜想您要解决的问题是您的计算机上正在运行某些进程,该进程有时行为不当,并且永远挂在一个核心上。

您要做的第一件事是尝试修复疯狂的程序。到目前为止,这是最好的解决方案。我将假设这是不可能的,或者您需要快速熟悉一下才能使盒子继续运行直到修复。

至少,您希望将脚本限制为只运行您所关注的一个程序。最好是,权限是这样限制您的脚本的(例如,您的脚本以用户X的身份运行,以X身份运行的唯一其他东西就是程序)。

更好的办法是使用类似的方法ulimit -t来限制程序可以使用的总CPU时间。同样,如果它消耗了所有内存,请检查ulimit -v。内核强制执行这些限制。有关详细信息,请参见bash联机帮助页(内置的shell)和setrlimit(2)联机帮助页。

如果问题不是一个正在运行的进程,而是正在运行的太多进程,则实施某种形式的锁定,以防止运行多个X(或者-这应该变得很熟悉- ulimit -u)。您还可以考虑更改这些进程的调度程序优先级(使用nicerenice),或者甚至更剧烈地使用sched_setscheduler,将策略更改为SCHED_IDLE

如果您需要更多控制权,请查看控制组(cgroups)。实际上,根据运行的内核,您可以限制整个进程组一起消耗的CPU时间,内存,I / O等。对照组非常灵活。他们可能会做任何您想做的事情,而不会产生任何脆弱的后果。Arch Linux Wiki有一个值得一读的cgroup简介Nil Brown在LWN 的cgroups系列也值得一读。


3

问题:

  • 在对数字字段进行排序时,您可能需要使用-n选项:sort -nrk 2。否则,%CPU值5.0 的行最终将比值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选项:ps -eo pid -eo pcpu -eo commandps -eo pid -o pcpu -o command(原样ps -eo pid,pcpu,command)相同。
  • 有一个空else子句。这看起来总是好像应该处理,但并非出于未知的原因。

2

杀死占用大量CPU /内存的进程会带来麻烦:只需查看一下它们现在在您的计算机上所处的位置(当前是firefox,systemd(ini​​t),Xorg,gnome-terminal,一组内核线程,xemacs;都不是必须的)。例如,在此处查看如何调整Linux的OOM杀手。

还要注意,“进程使用的内存”是一个模糊的概念,因为存在共享库,共享可执行文件,甚至部分数据区域。可以通过向每个用户收取一部分已用空间来算出一些数字,但是即使加起来,实际上也不会给出“已用内存”(甚至更少的“如果进程消失则释放了内存”),这些部分共享在一起背后)。


1

我创建了一个脚本kill-process,如果CPU使用率在YY秒内大于XX%,或者杀死正在运行的ZZ秒以上的进程,则会杀死阵列中列出的某些进程。

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

注意:这是我在Github上的仓库:https : //github.com/padosoft/kill-process

这是屏幕截图:

         ss#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]

似乎sort应该是sort -k9nr。不加n,将得到5.9 29.4
lk_vc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.