首页> 自动化运维> 提高Linux Shell 的运行效率

[文章]提高Linux Shell 的运行效率

收藏
0 817 0

提高Linux Shell 的运行效率

【摘要】

以日常管理蓝鲸平台为例,如果只是蓝鲸平台只是3台(社区版)或者是5台(企业版)的话,在一些简单的的场景的话,哪怕一台台进行手动敲命令也是可以的。但是如果在一些比较庞大的场景(5台服务器以上)的话,对于同样的命令还要一台台ssh 过去敲的话,那就很耗费时间,会导致工作效率拉低。那么,这时就需要高效地执行一些shell 命令。

【正文】

方法一:for 循环

比如,在部署蓝鲸平台时,一些通用的先决条件,就可以使用SSH远程执行命令的方式进行,而没必要每台都登陆,然后进行执行命令。如下:

  IP=$(cat /data/install/install.config | awk '{print $1}')
for i in $IP
do
ssh $i "SHELL CMD"
done

使用这种 for 循环的方式,就可以在中控机上把所有的命令都通过SSH远程执行的方式进行,这样就可以避免人工去登陆到每台服务器上去执行。

方法二:for + jobs 后台运行

但是,第一种方法的话,只是简单的用 for 循环代替了人工SSH而已,在执行效率上依然是一台台的去执行,那么在10台以上的场景中,方法一就会略显笨拙,因为这10台服务器并没有绝对的先后关系。比如说,我每台服务器都要安装 wget 这个工具,但是如果使用第一种方式的话,从第一台到最后一台,每一台服务器安装 wget 所花的时间都要加上上一台服务器所花费的时间。这样的效率是很低的,因为前一台安装 wget 的失败与否以及跟后一台服务器没任何关系,那么这种情况下,就可以同时并发式的对每一台服务器都执行同样的操作。

  • 首先,先用方法一进行对照实验

  IP=$(cat /data/install/install.config | awk '{print $1}')
for i in $IP
do
ssh $i "sleep 5s"  # 计时5秒
done


  • 可以使用 time + [COMMAND] 进行查看脚本运行的总时间。

    可以看到,由于每一台服务器都按顺序的执行 sleep 5s 的命令,然后再返回结果,这里脚本执行的时间就是所有服务器运行完的时间叠加:


  • 现在就对脚本稍微的进行修改,使其达到一个并发式的执行:

  IP=$(cat /data/install/install.config | awk '{print $1}')
for i in $IP
do
  {
ssh $i "sleep 5s"  # 计时5秒
}&  # 后台执行
done
wait # 最后结果返回



  • 这里就只作了简单的修改,不等待命令的结果返回,而是把命令丢到后台运行,之后再返回结果。

    从这里所花费的时间就可以看出,跟使用方法一的对照组相比,效率提升了至少5倍,因为命令几乎同一时间在所有服务器上运行,然后只需要等待花费最长的那一台服务器运行完即可返回。

    注:使用这种方式,结果的返回是无序的。


方法三:限制线程数量

方法二虽然高效,但所适用的场景是多台服务器并发执行,但是如果并发的作业是在同一台服务器上的,用方法二的话就可能会把服务器的资源都耗尽。

这里,使用方法二进行批量ping获取可用IP进行对照实验:

  • 有时候我们可能需要通过 ping 来获取某个网段内的所有可用的IP,如果是方法二,如下:

  #!/bin/bash
for i in {1..254}
do
{
       addr=192.168.163.$i
       ping=`ping -c 1 $addr | grep -Eo '[0-9] received'`
       if [ "$ping" == "0 received" ];
       then
      echo $addr not be used.
       fi
}&
done
wait
echo "Done"


  • 执行后,可以看到结果是并发式的出来。


  • 然后执行完255个 ping 作业所花费的时间是 10 秒左右。因为这是等于在一台服务器上同时开 255 个进程同时在ping。


  • 使用 ps -ef 进行统计一下运行时的进程数,可以看到会有 255 个进程在运行。


  • 如果命令还有其它比如结果输出的,这样的进程还会加倍。


  • 这个如果在一些性能比较差的服务器上,或者进程并且较大的脚本(1000以上)的话,就会很可能把服务器的CPU资源给占满。这样就需要对线程的数量进行限制一下。

使用有名管道进行限制进程数量:

  [ -e /tmp/snow ] || mkfifo /tmp/snow   # 创建有名管道                                                                               
exec 3<> /tmp/snow # 创建文件描述符
rm -rf /tmp/snow                                                
for ((i=1;i<=20;i++))  # 限制进程最大为20
do                              
   echo >&3  # &3代表引用文件描述符3
done                            
                               
for i in {1..254}              
do                              
read -u3  # 代表从管道中读取一个令牌  
  {                          
   sleep 3;                    
   addr=192.168.163.$i        
   ping=`ping -c 1 $addr|grep -Eo '[0-9] received'`
   if [ "$ping" == "0 received" ];then
       echo  $addr not be used.
   fi                          
   echo >&3  # 命令执行到最后,把令牌放回管道
  }&                          
done                            
wait                            
                               
exec 3<&-   # 关闭文件描述符的读    
exec 3>&- # 关闭文件描述符的写


  • 这样脚本在运行时的进程数最多就为20个:


  • 这样运行完整个脚本虽然比使用方法二的时间要长一些,但是可以确认服务器的资源不会被占满,同时又比方法一的时间要快。

    

自动化运维
最近热帖
{{item.Title}} {{item.ViewCount}}
近期热议
{{item.Title}} {{item.PostCount}}