Linux三剑客实战2-性能分析与脚本编写

标题

课程价值

  • 掌握Linux的性能统计相关命令
  • 掌握基本的bash脚本编写与调试方法
  • 可以应对大多数公司的linux技能面试题

大纲

  • 性能统计
  • 脚本编写
  • 应用

ppt

作业

perf_avg

分析阿里云盾进程的cpu与mem,每秒统计一次,统计20s并给出一个cpu与mem的平均值

需要注意的几个事项

  • ps与top在获取cpu数据上的区别, ps aux的cpu是累积平均cpu,不是实时cpu。实时cpu其实是top
  • top -b 输出用于批处理的数据格式,并且使用了grep的时候要加上–line-buffered
  • aliyundun有2个进程,需要使用aliyundun$去精准匹配
perf_avg(){
#todo: 
}


perf_avg
cpu mem
10 5
8 5
...

avg
9 5

答案

[00534760@shell.ceshiren.com ~]$ top -b -n 5 -d 1 | grep --line-buffered -i aliyundun$ | awk 'BEGIN{OFS="\t";print "cpu", "mem"}{print $9, $10;cpu+=$9;mem+=$10}END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}'
cpu	mem
0.0	1.1
1.0	1.1
0.0	1.1
1.0	1.1
1.0	1.1

avg
0.60	1.10


perf_avg ()
{
    top -b -n 5 -d 1 | grep --color=auto --line-buffered -i aliyundun$ | awk 'BEGIN{OFS="\t";print "cpu", "mem"}{print $9, $10;cpu+=$9;mem+=$10}END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}'
}

vs code格式化

perf_avg() {
    top -b -n 5 -d 1 |
        grep --color=auto --line-buffered -i aliyundun$ |
        awk '
    BEGIN{OFS="\t";print "cpu", "mem"}
    {print $9, $10;cpu+=$9;mem+=$10}
    END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}
    '
}

netstat作业: connections_summary

统计每个网络端口对应的不同状态的网络连接数

connections_summary

port  status count
22 CLOSE_WAIT 3
22 ESTABLISHED 30

常用参数

   -l, --listening
       Show only listening sockets.  (These are omitted by default.

[--tcp|-t]

   -p, --program
       Show the PID and name of the program to which each socket belongs.

   --numeric , -n
       Show numerical addresses instead of trying to determine symbolic host, port or user names.

常用命令

[00534760@shell.ceshiren.com ~]$ netstat -tlnp
(No info could be read for "-p": geteuid()=1929 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:9101          0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:9102            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:9009            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8887            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:44728           0.0.0.0:*               LISTEN      -
tcp        6      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      -
[00534760@shell.ceshiren.com ~]$ netstat -tnp |head -10
(No info could be read for "-p": geteuid()=1929 but you should be root.)
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 172.19.147.8:9102       39.106.113.77:38672     ESTABLISHED -
tcp        0      0 172.19.147.8:22         218.107.55.252:5109     ESTABLISHED -
tcp        0      0 172.19.147.8:22         117.10.232.185:55669    ESTABLISHED -
tcp        0      0 172.19.147.8:22         117.100.72.205:55133    ESTABLISHED -
tcp        0      0 127.0.0.1:9101          127.0.0.1:45570         TIME_WAIT   -
tcp        0      0 172.19.147.8:22         101.206.13.175:53238    ESTABLISHED -
tcp      244      0 172.19.147.8:8000       3.236.77.22:58188       CLOSE_WAIT  -
tcp        0      0 127.0.0.1:9101          127.0.0.1:45546         TIME_WAIT   -

时长

ppt

见回帖

性能统计

[00534760@shell.ceshiren.com ~]$ ps aux | head -5
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 125952  3656 ?        Ss   7月02  10:13 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
root         2  0.0  0.0      0     0 ?        S    7月02   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    7月02   0:22 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<   7月02   0:00 [kworker/0:0H]


[00534760@shell.ceshiren.com ~]$ top -b -n 1  -d 1
top - 20:23:52 up 30 days,  2:13, 36 users,  load average: 0.16, 0.06, 0.06
Tasks: 210 total,   1 running, 206 sleeping,   2 stopped,   1 zombie
%Cpu(s):  1.2 us,  0.8 sy,  0.0 ni, 97.9 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3881920 total,  1070900 free,   424112 used,  2386908 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  2943308 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
20102 root      20   0       0      0      0 S   6.2  0.0   0:00.66 kworker/0:1
23609 00534760  20   0  157700   2180   1516 R   6.2  0.1   0:00.01 top
    1 root      20   0  125952   3656   1552 S   0.0  0.1  10:13.36 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.27 kthreadd
    3 root      20   0       0      0      0 S   0.0  0.0   0:22.05 ksoftirqd/0
    5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:+


脚本编写

数组变量的用法

  • 初始化:array=(1 3 4 6) array=(ls)
  • 基于下标赋值:array[2]=“hello world”; echo ${array[2]}
  • 尾部追加:a2+=(d)
  • 遍历:for i in “${array[@]}”; do echo $i; done
  • 删除某个子元素:unset array[1]
  • 取下标:echo ${!a1[@]}
  • 数组长度:echo ${#array[@]}

课后作业 lucky()

要求

  • 支持命令行参数传递,支持从文件、从管道读取种子清单,种子清单可以自己模拟一个多行数据文件
  • echo $((RANDOM%6+1)) 模拟掷骰子 如果>3 晋级到下一轮
  • 如果此轮无人晋级,自动复活上轮选手
lucky  < name_list.txt
curl xxx | lucky
lucky a b c d e g h

第1轮: a e g h
第2轮: a g h
第3轮: a g h
第4轮: 
第5轮: a g h
第6轮: h

课后反馈

1 个赞

perf_avg(){

top -b -n 20 -d 1 | grep --line-buffered -i aliyundun | awk '{print $9, $10; totalcpu+=$9; totalmem+=$10}END{print totalcpu/20, totalmem/20}'

}

perf_avg(){
top -b -n 3 -d 1 |grep --line-buffered -i " aliyundun$"|awk 'BEGIN {cpu=0;mem=0;count=0;print "cpu","mem"} {count++;cpu=cpu+$9;mem=mem+$10;print $9,$10} END {print "\n","avg","\n"cpu/count,mem/count}'
}
[00534760@shell.ceshiren.com ~]$ top -b -n 5 -d 1 | grep --line-buffered -i aliyundun$ | awk 'BEGIN{OFS="\t";print "cpu", "mem"}{print $9, $10;cpu+=$9;mem+=$10}END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}'
cpu	mem
0.0	1.1
1.0	1.1
0.0	1.1
1.0	1.1
1.0	1.1

avg
0.60	1.10


perf_avg ()
{
    top -b -n 5 -d 1 | grep --color=auto --line-buffered -i aliyundun$ | awk 'BEGIN{OFS="\t";print "cpu", "mem"}{print $9, $10;cpu+=$9;mem+=$10}END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}'
}

vs code格式化

perf_avg() {
    top -b -n 5 -d 1 |
        grep --color=auto --line-buffered -i aliyundun$ |
        awk '
    BEGIN{OFS="\t";print "cpu", "mem"}
    {print $9, $10;cpu+=$9;mem+=$10}
    END{print "\navg";printf "%.2f\t%.2f\n",cpu/NR, mem/NR}
    '
}

netstat -tnp | awk '{print $4, $6}' | sed -r 's#172.19.147.8:##g' | sort | uniq -c | sort -nr
 netstat -tnp |awk '/[0-9]/{print $4,$6}'|awk 'BEGIN{FS="[: ]"}{print $2,$3}'|sort | uniq -c |sort -rn|awk '{print $2,$3,$1}'
1 个赞
connections_summary(){
netstat -tnp |awk '{print $4,$6}' | awk -F ":" '{print $2}' |sort | uniq -c
}

[quote=“seveniruby, post:1, topic:4332”]
分析阿里云盾进程的cpu与mem,每秒统计一次,统计20

netstat -tnp| awk 'BEGIN{OFS="\t";print "num", "port", "state"}{print $4,$6}'|sed 's/[0-9.]*://g' |sort |uniq -c
netstat -tnp | awk '{print $4,$6}' | sort | sed -e 's/:/ /g' | awk '{print $2 "\t" $3}'|uniq -c
function lucky(){
if [ $# -eq  0 ]
then
	read  currentName
else
	currentName=$@
fi
count=0
while true
do
	let count+=1
	result=""
	for name in $currentName
	do
		result+=$name":"$((RANDOM%6+1))" "
	done
	winName=`echo $result |awk 'BEGIN{FS=":";RS=" "}$2>3{print $1}'`
	winNum=`echo $result |grep -io [456] |wc -l`
	
	echo "第$count轮:"$winName
	if [ $winNum -eq 0 ]
	then
		continue
	elif [ $winNum -eq 1 ]
	then
		break
	else
		currentName=$winName
	fi
done
}
lucky() {
	rm -f round*
	seeds=$(cat name_list.txt)
	count=0
	num=0
	while (($count != 1)); do
		((num += 1))
		touch round$num.txt
		for line in $seeds; do
			if ((($RANDOM % 6 + 1) > 3)); then
				echo $line >>round$num.txt
			fi
		done
		if [ ! -s round$num.txt ]; then
			continue
		else
			seeds=$(cat round$num.txt)
		fi
		count=$(echo "$seeds" | wc -l)
	done
}
#!/bin/bash
luck(){
name=()
name_del=()
num=0
i=0
          
# 从文件中获取用户存入到数组里
for item in $(cat name_list.txt)
do       
        name[num]="$item"
        let num+=1 
done         
while [ ${#name[*]} -gt 1 ]
do
        for num in ${!name[*]}
        do
                luck_num=$((RANDOM%6+1))
                if [ $luck_num -le 3 ]
                then 
                        name_del[i]="${name[$num]}"
                        let i+=1
                        unset name[$num]
                fi
        done
        let round++
        echo "第"$round"轮:"${name[*]}
        if [ ${#name[*]} -eq 0 ]
        then
                name=(${name[*]} ${name_del[*]})
                let round++
                echo "第"$round"轮:"${name[*]}
        elif [ ${#name[*]} -eq 1 ]
        then break
        elif [ ${#name[*]} -gt 1 ]
        then
                unset name_del
                i=0
        fi
done

}
luck

抽奖脚本
抽奖名单:lucky.txt

lucky(){
#!/bin/bash
num=0
for line in `awk '{print $1}' lucky.txt `
 do
  a+=$line" "
done
echo $a
while true
do
c=0
b=""
((num++))
 for ln in  $a
 do
  if [ $((RANDOM%6+1)) -gt 3 ];then
   ((c++))
   b+=$ln" "
  fi
 done
 if [ "$b" =  "" ] ;then
  echo "第 $num 轮无人中奖";
 else
  echo "第 $num 轮中奖名单 : $b"
 fi
 if [ $c == 0 ] ;then
 continue
 elif [ $c == 1 ] ; then
 break
 else
 a=$b
 fi
done
}
lucky(){
#从name_list中读取名单到seeds
seeds=()
for name in $(cat name_list.txt)
do       
   seeds+=($name)
done
echo '种子选手名单:'${seeds[@]}

#计算出一名幸运中奖者
count=1
while true
do
   winner=()
   for i in ${seeds[@]}
   do
      if [ $((RANDOM%6+1)) -gt 3 ]
      then winner+=($i)
      fi
   done
   echo "第“$count”轮胜出的人员是:"${winner[@]}
   ((count++))	
   if [ ${#winner[@]} -eq 0 ]
   then winner=$seeds
   else seeds=$winner
   fi
   if [ ${#winner[@]} -eq 1 ]
   then break
   fi
done
echo "幸运中奖者是:"${winner[@]}
}

命令行参数传递:lucky a b c d e g h
文件获取清单: lucky XXX.txt, lucky >xxx.txt 均可
管道获取清单: echo a b c d | lucky

lucky(){
if [ $# -gt 1 ] ; then
    promotion_name=($@)
elif [ $# == 1 ] && [ -f $1 ] ; then
    num=0
    for name in $(cat $1)
    do
        promotion_name[num]="$name"
        let num+=1
    done
elif [ $# == 0 ] ; then
    num=0
    for name in $(cat)
    do
        promotion_name[num]="$name"
        let num+=1
    done
fi
eliminate_lname=()
round=0
while [ ${#promotion_name[@]} -ge 1 ]
do  
    for i in "${!promotion_name[@]}";
    do  
        if [ $((RANDOM%6+1)) -le 3 ] ; then
            eliminate_name+=(${promotion_name[$i]})
            unset promotion_name[$i]
        fi
    done    
    if [ ${#promotion_name[@]} -eq 0 ] ; then
        let round++
        echo "第"$round"轮:"${promotion_name[@]}
        promotion_name=(${eliminate_name[@]})
        unset eliminate_name
        let round++
        echo "第"$round"轮:"${promotion_name[@]}
    elif [ ${#promotion_name[@]} -eq 1 ] ; then
        let round++  
        echo "第"$round"轮获胜:" ${promotion_name[@]}
        break
    elif [ ${#promotion_name[@]} -gt 1 ] ; then
        let round++  
        echo "第"$round"轮:" ${promotion_name[@]}
        unset eliminate_name 
    fi
done
}
lucky(){
	list_name=0
	list_No=0
	list=()
	time_list=()
	time=1
	for name in $(cat name_list.txt) ; 
		do num=$((RANDOM%6+1)) ; 
			if (($num>3)); 
				then list[$list_No]=$name ;
				let list_No=list_No+1 ;
			fi ; 
		done ;
	per_round_list=${list[*]}
	per_round_list_len=${#list[*]}
	
	while [ ${#list[*]} -ge 1 ] ; 
	do
		time_list[$time]=$per_round_list ; 
		if (($per_round_list_len>0)) ; 
			then echo '第'$time'轮:'${time_list[$time]} ; 
		elif (($per_round_list_len=0})) ; 
			then echo '第'$time'轮:'${time_list[$time]} ;
			time_list[$time]=${time_list[`expr $time - 1`]}
		elif (($per_round_list_len=1})) ; 
			then echo '第'$time'轮:'${time_list[$time]} ;
	  fi ; 
	
		list_No=0
		list=()
		for name in ${time_list[$time]} ; 
		do num=$((RANDOM%6+1)) ; 
			if (($num>3)); 
				then list[$list_No]=$name ;
				let list_No=list_No+1 ;
			fi ; 
		done ;
		per_round_list=${list[*]}
		per_round_list_len=${#list[*]}
	  let time+=1
	done
}
connections_summary()
{
netstat -tnp 2>/dev/null | awk 'NR>2{print $4,$6}' | awk -F: '{print $2,$3}' | sort | uniq -c | sort -rn|awk 'BEGIN{OFS="\t";print "port", "status","count"}{print $2,$3,$1}';
}

connections_summary

port status count
22 CLOSE_WAIT 3
22 ESTABLISHED 30

 netstat -tnp 2>/dev/null | awk 'NR>2' | awk -F '[: ]+' '{print $5,$8}' | sort | uniq -c | sort -nr | awk '{print $2, $3, $1}'
  • 实战shell脚本小游戏,支持命令行参数和文件读入参数 :cactus:
    预格式化文本将缩进 4 格

–shell游戏脚本
#!/bin/bash
#掷色子游戏
#支持命令行参数传递,支持从文件、从管道读取种子清单,种子清单可以自己模拟一个多行数据文件
#游戏规则:RANDOM%6+1 模拟掷骰子 如果>3 晋级到下一轮
#如果此轮无人晋级,自动复活上轮选手
function lucky(){
#玩家
players=$@;
if [ $# -eq 0 ];then
#从文件或管道符读入
unset players;
while read line;
do
players+=( “$line” );
done
if [ ${#players[@]} -eq 0 ];then
printf “没有参赛选手,游戏自动结束!\n”;
fi
fi
#开始游戏
printf “开始游戏,现在玩家入场”;
n=1;#游戏轮次
state=0;#0-继续 、1-重玩、2-结束
while [ $state -ne 2 ]
do
printf “\n第%d轮:%s” $n “${players[]}";
temp=();#存放进入下一轮的选手
for p in ${players[@]}
do
point=$((RANDOM%6+1));
#printf “%s掷出了%d点\t” $p $point;
if [ $point -gt 3 ];then
temp+=( “$p” );#进入下一轮的选手
fi
done
#printf “\n第%d轮结束!\n” $n;
#判断游戏是否结束
if [ ${#temp[@]} -eq 0 ];then
if [ ${#players[@]} -eq 1 ];then state=2;#当前只有一位玩家,且未进入下一轮,游戏结束
else state=1;
fi
else #下一轮选手数量大于0,游戏继续
players=("${temp[@]}");
state=0;
fi
#printf “%s进入下一轮\n” "${temp[
]}”;
n=expr $n + 1;
done
printf “\n****游戏结束\n”;
}
lucky a b c d e f g #调用函数并传递参数
lucky < name_list.txt