一個“指令碼執行夯死”問題的分析

weixin_34208283發表於2018-08-02

問題現象:

使用一個指令碼命令分發執行的指令碼,在執行時出現夯死,無法繼續進行

[root@yj01 cluster]# sh clustercmd.sh "ls -l /tmp"

問題分析

  • 於是使用指令碼除錯的方式,執行結果如下:
[root@yj01 cluster]# sh -x clustercmd.sh  "ls -l /tmp"
+ R_CMD='ls -l /tmp'
+ G_CURRENT_PATH=
+ G_LIB_SCRIPT=cluster_lib.sh
+ G_REMOTE_SCRIPT=remote.sh
+ G_CONF_FILE=cluster.ini
+ G_CONF_FILE_TMP=cluster.ini.tmp.645182
+ G_RESULT=0
+ G_HOSTS_ARRAY=()
+ G_PASSWDS_ARRAY=()
+ '[' /usr/bin/sh '!=' /bin/bash ']'
+ bash clustercmd.sh 'ls -l /tmp'

結果顯示在執行bash clustercmd.sh 'ls -l /tmp'時,長時間夯死,不再繼續進行。

  • 繼續使用strace命令檢視指令碼執行情況:

      [root@yj01 cluster]# strace  sh  clustercmd.sh  "ls -l /tmp"
      execve("/usr/bin/sh", ["sh", "clustercmd.sh", "ls -l /tmp"], [/* 32 vars */]) = 0
      brk(0)                                  = 0xa17000
      mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0c603f0000
      ......
      rt_sigaction(SIGINT, {0x43e5e0, [], SA_RESTORER, 0x7f0c5fa16670}, {SIG_DFL, [], SA_RESTORER, 0x7f0c5fa16670}, 8) = 0
      
      // 在執行到此處時,較長時間夯住,後續丟擲Can't allocate memory異常
      
      ****wait4(-1, clustercmd.sh: fork: Cannot allocate memory*****
    

此處表示,新fork出一個程式進行命令操作,在等待的過程中,丟擲“Can't allocate memory”異常

  • 檢視OS記憶體情況以及最大程式數

      // OS的記憶體是充足的
      [root@yj01 cluster]# free -g
                total        used        free      shared  buff/cache   available
      Mem:             31           9          17           0           4          21
      Swap:             3           0           3
      // OS的最大程式數是充足的
      [root@yj01 cluster]# sysctl kernel.pid_max
      kernel.pid_max = 798720
      [root@yj01 cluster]# ps -eLf | wc -l
      711
      [root@yj01 cluster]# 
    

從OS資訊來看,記憶體充足,程式數遠遠小於最大的限制. 因此懷疑在夯住的時間內,產生大量程式,os記憶體被大量佔用,最後出現了上述中的“Cannot allocate memory”

  • 再次執行 sh -x clustercmd.sh "ls -l /tmp" 同時檢視OS的記憶體使用以及啟動程式數
// os可用記憶體記憶體大量減少
[root@yj01 ~]# free -g
          total        used        free      shared  buff/cache   available
Mem:             31           9          17           0           4          21
Swap:             3           0           3
[root@yj01 ~]# free -g 
              total        used        free      shared  buff/cache   available
Mem:             31          10          16           0           4          20
Swap:             3           0           3
[root@yj01 ~]# free -g 
              total        used        free      shared  buff/cache   available
Mem:             31          12          14           0           4          18
Swap:             3           0           3

//程式被大量建立
[root@yj01 ~]# ps -eLf | wc -l
9984
[root@yj01 ~]# ps -eLf | wc -l
10452
[root@yj01 ~]# ps -eLf | wc -l
10981
[root@yj01 ~]# ps -eLf | wc -l
11463

於是懷疑指令碼bug引發啟動大量的程式將OS資源耗完,最後程式執行失敗退出。

  • 指令碼分析

檢視指令碼可以看出指令碼中強制使用bash來解析執行,但是在執行bash時可能使用到的不是/bin/bash從而導致程式進入死迴圈。

#!/bin/bash
....
if [ "$BASH" != "/bin/bash" ]; then
   bash $0 "$@"
   exit $?
fi

檢視環境發現如下:

執行which bash 發現使用的是/usr/bin/bash
[root@yj01 cluster]# which bash
/usr/bin/bash
//檢視環境變數發現 /usr/bin在/bin前面
[root@yj01 cluster]# echo $PATH
/usr/local/openssh-7.4p1/sbin:/usr/local/openssh-7.4p1/bin:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/openssh-7.4p1/bin:/root/bin:/root/bin
[root@yj01 cluster]# 

可以看出在執行bash $0 "$@"時,使用的是/usr/bin/bash 因此程式進入死迴圈

解決方案

修改if判斷條件if [ ${BASH:0-4} != "bash" ]; 只要執行的是bash命令,即可通過

相關文章