linux模拟消耗带宽脚本

  baikapala

    最近在性能测试的时,遇到了一个测试场景,需要去模拟测试业务在带宽压力较大的情况下的TPS和响应时间情况。

    首先想到的方法是带上其他的业务一起压测,但是后来发现并没有特别消耗带宽的一些业务。

    然后想到在weblogic上放上静态资源例如图片或者大文件,准备好之后,从压力机开始多并发下载这个文件,但是效果却也没有达到预期,最多也只有消耗约50MB左右,仔细研究了下也没有发现具体原因(后来觉得可能是应用的限制吧),也只好作罢。


    最后想到利用脚本实现多进程在主机之间通过SFTP或者SCP来传输文件来消耗带宽。

    有了这个想法之后,开始着手写脚本,好了,问题又来了,发现不管是通过SFTP还是SCP来实现文件传输都需要途中输入主机密码,这个有交互的东西在shell脚本里确实不好写,之前也解决过这种问题,但是是通过expect命令的,也比较麻烦。

    百度了下,发现免密登录实现其实比较简单,于是照着脚本来了一遍,其中因为有好几个教程写的并不详细,出了很多岔子,最后还好都算解决了:



    分别在两台主机上执行:ssh-keygen -t rsa
    生成的密匙和公匙文件默认是在~/.ssh文件夹中,如果没有这个文件夹则手动创建
    执行命令过程中一直按确认就可以了。
    生成的文件为:id_rsa  id_rsa.pub  ,前者为秘钥文件,后者为公钥文件。
    在~/.ssh目录分别执行命令 cp id_rsa.pub authorized_keys
    然后分别把对方的id_rsa.pub文件中的内容复制到对方机器中的authorized_keys文件中,注意源文件中内容是一行,手动复制之后可能变成三行,这个注意下就行了。
    最后重启下ssh服务  service sshd restart就行了。两台主机就能免密登录了。
    

    最后是脚本内容:


    #!/bin/bash
    #利用多线程和scp来消耗主机带宽
    #两个主机之间必须可以免密登录
    ######################################################
    trap "exit_out" 2 3 15
    
    if [ $# != 1 ]
    then
    	echo "The parameters you enter is not correct !";
      exit -1;
    fi
    thread=$1 # 此处定义线程数
    max_thread=500 #最大的线程数
    
    #scp数据
    r_host="188.18.28.19"  #远程主机ip
    r_username="root"  #远程主机登录名
    r_dir="/home/test0208/tmp" #远程主机文件路径
    r_file="$r_dir/ddfile2m" #远程主机文件名
    l_dir="/home/yangjuying/tmp" #本地存放文件路径
    l_file="$l_dir/ddfile2m" #本地存放文件名
    
    #带宽日志
    network_log="./net.log"
    
    #各进程详细日志
    thread_detail="./kill_network_detail_log/thread.log"
    
    stop_flag=1
    
    ######################################################
    exit_out(){
    stop_flag=0
    echo "请等待所有传输任务完成...、"
    }
    
    a_sub()
    {
        thread_detail_thread=$thread_detail_$1
        network_log_thread=$network_log_$1
        # 此处定义一个函数,作为一个线程(子进程)
        echo "$string is running...."
        while [ $stop_flag -eq 1 ]
    		do
    		echo "----------$(date +%Y%m%d-%H%M%S)----------" >>$thread_detail_thread
    		start_t="$(date +%s)"
    		scp -P22 -o connecttimeout=10 -o GSSAPIAuthentication=no $r_username@$r_host:$r_file $l_file >>$thread_detail_thread 2>&1
    		rc="$?"
    		if [ "$rc" -eq 0 ];then
    		    stop_t="$(date +%s)"
    		    file_stat="$(stat $l_file)"
    		    file_ctime="$(echo "$file_stat" | awk -F "[ .]" 'FNR==5{print $2,$3}' | sed 's/[- :]/ /g')"
    		    file_ct="$(awk -v t="$file_ctime" 'BEGIN{print mktime(t)}')"
    		    file_size="$(du -sm $l_file | cut -f1)"
    		    rm "$l_file"
    		else
    		    stop_t=""
    		fi
    		if [ -n "$stop_t" ];then
    		    connect_t=$(($file_ct-$start_t))
    		    transfer_t=$(($stop_t-$file_ct))
    		    all_t=$(($stop_t-$start_t))
    		    speed="$(echo "scale=3;$file_size/$transfer_t" | bc)"
    		    echo "size:${file_size}MB, all_time:$all_t, connect_time:$connect_t, transfer_time:$transfer_t, speed:${speed}MB/s" >>$thread_detail_thread
    		    echo "${speed}" > $network_log_thread
    		else
    		    echo "scp error!" >>$thread_detail_thread
    		    echo "0" > $network_log_thread
    		fi
    		done
    }
    
    show_all_speed(){
    while [ $stop_flag -eq 1 ]
    do
    all_speed=0
    for ((i=0;i<$thread;i++))
    do
    
    if [ -f $network_log_$i ]
    then
    curr_speed=`cat $network_log_$i`
    all_speed=`echo "${all_speed}+${curr_speed}"|bc`
    fi
    
    done
    echo $all_speed
    sleep 2
    done
    }
    
    
    ######################################################
    rm -rf ${network_log}*
    rm -rf ${thread_detail}*
    rm -rf thread.lock
    echo "THREAD=$thread start..."
    
    
    if [ $max_thread -le $thread ]
    then
    thread=$max_thread
    fi
    
    if [ ! -d ./kill_network_detail_log ]
    then
    mkdir ./kill_network_detail_log
    fi
    
    #############################################################
    tmp_fifofile=$$.fifo
    mkfifo $tmp_fifofile      # 新建一个fifo类型的文件
    exec 6<>$tmp_fifofile      # 将fd6指向fifo类型
    
    for ((i=0;i<$thread;i++))
    do
        echo
    done >&6 # 事实上就是在fd6中放置了$thread个回车符
    
    for ((i=0;i<$max_thread;i++))
    do #max_thread次循环,可以理解为max_thread个主机,或其他 
        read -u 6 #一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行, 
        #fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制 
        { # 此处子进程开始执行,被放到后台 
            a_sub $i
            #echo>&6
        } & #当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个
    done
    show_all_speed
    wait # 等待所有的后台子进程结束 
    
    exec 6>&- #关闭df6 
    rm -f $tmp_fifofile
    rm -rf ${network_log}*
    
    echo "进程运行完毕,脚本已退出!"


    最后想说的是,其实这个方法在scp的过程中也是可能占用一点CPU和内存资源,另外对IO也是有影响的,在实际的测试中,需要自己把握。