CPULoad高的故障发生后,可以通过哪些命令简单高效的排查出是哪些线程哪种状态导致的高负载呢?一起来统计下R状态和D状态吧!
脚本工具
输出R和D状态的进程
1 2
| #!/bin/sh ps -e -L h o state,ucmd | awk '{if($1=="R"||$1=="D"){print $0}}' | sort | uniq -c | sort -k 1nr
|
列出RD状态的进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #!/bin/bash
set -o errtrace trap 'status=$?;echo -e "Param is err.\n";show_usage;exit $status' ERR
function show_usage() { echo "param is -r -d -s -h." }
running='' disksleep='' summary=''
getopt_info=$(getopt -q -o 'rdsh' -l 'running,disksleep,summary,help' eval set while [ $1 != '--' ] do case $1 in -r| running='true' ;; -d| disksleep='true' ;; -s| summary='true' ;; -h| show_usage exit 0 ;; *) ;; esac shift done
if [[ -n $summary ]];then if [[ -n $running && -z $disksleep ]];then ps -e -L h o state,ucmd | awk '{if($1=="R"){print $0}}' | wc -l elif [[ -z $running && -n $disksleep ]];then ps -e -L h o state,ucmd | awk '{if($1=="D"){print $0}}' | wc -l else ps -e -L h o state,ucmd | awk '{if($1=="R"||$1=="D"){print $0}}' | wc -l fi else if [[ -n $running && -z $disksleep ]];then ps -e -L h o state,ucmd | awk '{if($1=="R"){print $0}}' | sort | uniq -c | sort -k 1nr elif [[ -z $running && -n $disksleep ]];then ps -e -L h o state,ucmd | awk '{if($1=="D"){print $0}}' | sort | uniq -c | sort -k 1nr else ps -e -L h o state,ucmd | awk '{if($1=="R"||$1=="D"){print $0}}' | sort | uniq -c | sort -k 1nr fi fi
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #!/bin/bash
set -o errtrace trap 'status=$?;echo -e "Param is err.\n";show_usage;exit $status' ERR
function show_usage() { echo "param is -r -d -s -h." }
running='' disksleep='' summary=''
getopt_info=$(getopt -q -o 'rdsh' -l 'running,disksleep,summary,help' eval set while [ $1 != '--' ] do case $1 in -r| running='true' ;; -d| disksleep='true' ;; -s| summary='true' ;; -h| show_usage exit 0 ;; *) ;; esac shift done if [[ -n $summary ]];then if [[ -n $running && -z $disksleep ]];then ps -e -L h o state,pid,cmd | awk '{if($1=="R"){print $0}}' | wc -l elif [[ -z $running && -n $disksleep ]];then ps -e -L h o state,pid,cmd | awk '{if($1=="D"){print $0}}' | wc -l else ps -e -L h o state,pid,cmd | awk '{if($1=="R"||$1=="D"){print $0}}' | wc -l fi else if [[ -n $running && -z $disksleep ]];then ps -e -L h o state,pid,cmd | awk '{if($1=="R"){print $0}}' | sort | uniq -c | sort -k 1nr elif [[ -z $running && -n $disksleep ]];then ps -e -L h o state,pid,cmd | awk '{if($1=="D"){print $0}}' | sort | uniq -c | sort -k 1nr else ps -e -L h o state,pid,cmd | awk '{if($1=="R"||$1=="D"){print $0}}' | sort | uniq -c | sort -k 1nr fi fi
|
查看CPU使用率高的线程(和load不是一回事)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/bash LANG=C PATH=/sbin:/usr/sbin:/bin:/usr/bin interval=2 length=10 for i in $(seq 1 $(expr ${length} / ${interval})) do date LANG=C ps -eT -o%cpu,pid,tid,ppid,comm | grep -v CPU | sort -n -r | head -20 date LANG=C cat /proc/loadavg { LANG=C ps -eT -o%cpu,pid,tid,ppid,comm | sed -e 's/^ *//' | tr -s ' ' | grep -v CPU | sort -n -r | cut -d ' ' -f 1 | xargs -I{} echo -n "{} + " && echo ' 0'; } | bc -l sleep ${interval} done fuser -k $0
|
处于D状态的原因
以下引用自:https://mp.weixin.qq.com/s/Jl1Fr81FfBbz6He6Pqf6Gg 供分析提供思路。
缺页中断
Linux为了提高内存利用率,会比较投机,比如说著名的LRU回收。举例子来说,如果进程的page已经被回收并交换的swap分区上,那么进程访问到页面的时候开始,就要陷入uninterruptible状态,一直到页面被加载到内存中;如果运气比较差,内存比较紧张,还需要先回收一些page才行。
io等待
磁盘速度是计算机的最大瓶颈。多个进程都要访问磁盘的话,势必有进程要处于uninterruptible状态排队,直到数据被读到内存。运气差一些的话,如果操作系统的内存偏少,还需要先回收一些内存才能把数据读进内存来。
网络
平常写的socket,大家放心,不会让进程进入到uninterruptible状态的。但是,如果是nfs或者cifs呢,再或者iscsi映射的块设备呢?如果发生了网络波动,读写就会陷入uninterruptible了。(nfs和cifs作者实验过,是会陷入uninterruptible状态的。iscsi没有实验过,这个算是作者偷懒了)。作者实验了一下,在使用nfs的情况下,server端使用iptables DROP掉2409的包,client端访问nfs目录的时候,果然发生了load average增高的情况。当然,这个是符合预期的。
内存紧张
原因上面已经解释过了,这里强调一下,是为了说明,free memory越少,越容易让load average增高!swap的内存越多,load average也越容易增高。