具体Tsung工具的应用是,模拟用户对某平台的访问,其中可以产生自定义数量的虚拟用户,当Tsung start启动后,虚拟用户产生,模拟访问测试的平台,得到压力数据,在平台生产和设计过程中查漏补缺,具体如下:
Tsung压力测试工具环境搭建
环境:
系统:CentOS 7
版本(软件包):tsung-1.4.2.tar.gz otp_src_R14B04.tar.gz Template-Toolkit-2.24.tar.gz
安装软件之前确保环境中存在以下工具:
yum install gcc -y
yum install perl -y
yum install unixODBC
yum install unixODBC-devel
下载并安装erlang
# wget http://www.erlang.org/download/otp_src_R14B04.tar.gz
# tar -zxvf otp_src_R14B04.tar.gz
# cd otp_src_R14B04
# ./configure --prefix=/usr/local/erlang
# make
# make install
若出现"configure:error: No curses library functions found "错误,则需安装以下工具
yum install -y ncurses-devel
下载并安装Tsung
# wget http://tsung.erlang-projects.org/dist/tsung-1.4.2.tar.gz
# tar -zxvf tsung-1.4.2.tar.gz
# cd tsung-1.4.2
# ./configure --prefix=/usr/local/tsung --with-erlang=/usr/local/erlang
# make
# make install
下载并安装perl Template,用于生成报告模板
# wget http://cpan.org/modules/by-module/Template/Template-Toolkit-2.24.tar.gz
# tar -zxvf Template-Toolkit-2.24.tar.gz
# cd Template-Toolkit-2.24
# perl Makefile.PL
# make
# make install
若在perl Makefile.PL处发生错误如下:
则安装perl-devel即可 yum install -y perl-devel
下载并安装gnuplot ,用于聊天生成
yum install -y gnuplot gd libpngzlib
完成安装后把erlang tsung加入到环境变量中
# vim /etc/profile
export PATH=$PATH:$JAVA_HOME/bin:/usr/local/erlang/bin:/usr/local/tsung/bin:/usr/local/nginx/sbin:$PATH(修改自己实际变量)
保存,退出
# source /etc/profile
不报错则成功
# tsung -v 查看Tsung版本
# erl -v 查看erlang版本
测试
使用并生成报表
1.在root下创建.tsung目录,用于存放log和xml配置文件,测试文件参考/usr/local/tsung/share/doc/tsung/examples/http_simple.xml文件。
mkdir ~/.tsung
cp/usr/local/tsung/share/doc/tsung/examples/http_simple.xml ~/.tsung/tsung.xml
2.运行tsung,默认执行脚本~/.tsung/tsung.xml配置文件
tsung start
此时生成log文件夹及其他文件,进入log目录查看生成的报表信息
cd /root/.tsung/log/20160215-2151
进入需要生成图像报表的log目录,如上面20160215-2151,执行命令
/usr/local/tsung/lib/tsung/bin/tsung_stats.pl
ls -a出现以下文件及目录
把20160215-2151目录打包下载到windows系统中,打开里面的report.html文件即可查看。
report.html文件各参数说明
request:每个请求的反应时间
page:每一系列请求的反应时间(a page是一组不包含think-time的一组请求)
connect:连接建立用的时间
reconnect:重新连接的次数
size_rcv:反应的大小(单位是byte)
size_sent:请求的大小(单位是byte)
session:用户会话时间
users:同步用户数
connected:同步连接用户数
补充强调:
tsung 采用了巧妙的 proxy 方式来“录制”测试脚本。具体来说,就是建立一个本机的 http proxy 默认使用 8090 端口,在配好 firefox 使用 localhost 8090 作为代理之后(推荐 foxyproxy 插件),所有“流经”这个 proxy 的 http 动作都会被记录下来,测试时可以“回放”这些步骤来产生请求。
tsung-recorder在安装目录/usr/local/tsung/bin/下,此文件为可执行文件,查看文件内容
tsung rocorder
tsung stop_recorder
“录制”完了,会得到一个 ~/.tsung/tsung_recorderXXXXXXXXXX.xml 文件,这就是测试时回回放的脚本。
将这个脚本加到 tsung.xml 之中
gedit ~/.tsung/tsung.xml
就像这样
<!DOCTYPEtsungSYSTEM"/usr/share/tsung/tsung-1.0.dtd" [
<!ENTITYmysession1SYSTEM"/home/yourname/.tsung/tsung_recorderXXXXXXXXXX.xml">
]>
...
<sessions>
&mysession1;
</sessions>
对配置稍作调整
<monitoring>
<monitorhost="localhost"type="erlang"></monitor>
</monitoring>
<!-- 需要配置到 localhost 无须密码的 ssh 登录(ssh via rsa_key),开启了这个配置可以,获得目标机器的 cpu 和 ram 消耗情况 -->
<load>
<arrivalphasephase="1"duration="1"unit="minute">
<usersinterarrival="2"unit="second"></users>
</arrivalphase>
</load>
<!-- 第1阶段1分钟(你可以自己多搞几个阶段),其中每2秒新建一个用户,每个用户都会完整执行 session 的测试脚本,最高并发约为 30 个,个人认为这个“逐渐加压”的方法比 ab xxxx 的“突然加压”要慢一些,但更科学一点 -->
运行
准备好了,加压运行。
tsung start
运行完,在 ~/.tsung/log 目录会生成一个以时间命名的目录,进入这个目录
cd ~/.tsung/log/xxxxx
/usr/lib/tsung/bin/tsung_stats.pl
生成 html 的压力测试报告
Tsung下配置文件Tsung.xml文件各语句含义
<?xmlversion="1.0"?>
<!DOCTYPE tsung SYSTEM"/usr/local/share/tsung/tsung-1.0.dtd">
<!-- dumptraffic是调试模式,如果为true,就会打印详细的请求返回信息,一般设置为false, -->
<tsung loglevel="notice"dumptraffic="false" version="1.0">
<!-- tsung所在的服务器,maxusers就是tsung产生的最大用户数 -->
<clients>
<clienthost="localhost" use_controller_vm="true" maxusers="100000" />
</clients>
<!-- 被测服务器的ip和端口号,type一般设为tcp ->
<servers>
<server host="@server"port="@port" type="tcp"/>
</servers>
<!-- tsung产生的压力 -->
<load>
<!-- phase="1" 第一阶段;duration:测试持续时间;unit:单位秒 -->
<arrivalphasephase="1" duration="@duration" unit="second">
<!-- maxnumber:最大用户数;arrivalrate:每秒新增用户数;unit:单位秒-->
<users maxnumber="@maxuser"arrivalrate="@user" unit="second"/>
</arrivalphase>
</load>
<!-- 外部变量 -->
<options>
<!-- 引入一个外部文件,类型为file_server,变量名为userfile,文件路径:/tmp/users-->
<!-- 文件是以逗号分隔的csv文件 -->
<optionname="file_server" id="userfile"value="/tmp/users"/>
</options>
<!-- 会话,每个用户都按照sessions中的配置发送请求 -->
<sessions>
<!--probability=“100”:这个session的请求概率是100%,如果要同时测多个api,可以设置请求概率;请求类型为http -->
<sessionname="test" probability="100" type="ts_http">
<!-- 请求次数,to是最大请求数,如果设为100,就是每个用户请求100次-->
<forfrom="1" to="@loop" incr="1"var="counter">
<!-- 解析前面引入的外部文件,以逗号做为分隔符,随机读取 -->
<setdynvarssourcetype="file" fileid="userfile" delimiter=","order="random">
<varname="user_id" />
<varname="passwd" />
<varname="auth_token" />
</setdynvars>
<!-- 返回随机小数,变量名为decimal,code中可以写erlang函数-->
<setdynvarssourcetype="eval" code="fun({Pid,DynVars}) ->random:uniform() end.">
<varname="decimal" />
</setdynvars>
<!-- 返回随机数,从1到10000 -->
<setdynvarssourcetype="random_number" start="1"end="10000">
<varname="int_1_10000" />
</setdynvars>
<!-- 返回随机字符串,长度为10-->
<setdynvarssourcetype="random_string" length="10">
<varname="string_10" />
</setdynvars>
<!-- subst="true":如果在request中使用变量,需要设置subst -->
<requestsubst="true">
<!-- url:被测试的url;method:GET、POST等;contents:POST请求的参数-->
<httpurl="@api" method="@method" contents="@contents"version="1.1">
<!-- http header,可以添加Authorization、Cookie等,注意变量的使用格式:%%_xxx%% -->
<http_headername="Authorization" value="111"/>
<http_headername="Cookie" value="authToken=%%_auth_token%%;Path=/"/>
<!-- content-Type:POST请求参数的格式,如果是json格式可以这样写 -->
<http_header name="Content-Type"value="application/json"/>
</http>
</request>
<!-- thinktime:两次请求之间的间隔时间,一般小于10s -->
<thinktimevalue="1"/>
</for>
</session>
</sessions>
</tsung><span></span>
如果被测接口需要登录跳转,可以指明跳转条件:
<!-- if need login, http 302 will be return -->
<request subst="true">
<dyn_variablename="redirect1" re="Location: ((http|https)://.*)\r"/>
<http url="@api"method="@method" contents="@contents"version="1.1"></http>
</request>
<if var="redirect1"neq="">
<request subst="true">
<!-- 这里可以使用xpath提取页面中的元素值 -->
<dyn_variable name="lt"xpath="//input[@name='lt']/@value"/>
<dyn_variable name="s_uuid"xpath="//input[@name='s_uuid']/@value"/>
<dyn_variable name="eventId"xpath="//input[@name='_eventId']/@value"/>
<http url="%%_redirect1%%"method="GET"></http>
</request>
<request subst="true">
<dyn_variablename="redirect2" re="Location: (http://.*)\r"/>
<http url="%%_redirect1%%"method="POST"contents="username=%%_username%%&password=%%_password%%&lt=%%_lt%%&s_uuid=%%_s_uuid%%&_eventId=%%_eventId%%&j_captcha_response=''"></http>
</request>
<request subst="true">
<dyn_variablename="redirect3" re="Location: (http://.*)\r"/>
<http url="%%_redirect2%%"method="GET"></http>
</request>
<request subst="true">
<httpurl="%%_redirect3%%" method="@method"contents="@contents"></http>
</request>
</if>
通过shell控制tsung
如果每次使用tsung start 运行tsung,那么每次修改测试接口或者压力改变都需要修改tsung.xml,非常麻烦,写个shell脚本替换以@开头的变量
#!/bin/bash
defaultTestFile="$HOME/tsung_test.xml"
defaultUser=20
defaultDuration=100
# s
defaultThinktime=1
defaultServer="tomcat1"
defaultPort=9000
defaultApi="/test"
defaultMethod="POST"
defaultLoopCount=50
defaultMaxuser=5000
while [ $# -gt 0 ]; do
case "$1" in
-f|--testFile)
testFile=$2
shift
shift ;;
-u|--user)
user=$2
shift
shift ;;
-d|--duration)
duration=$2
shift
shift ;;
-t|--thinktime)
thinktime=$2
shift
shift ;;
-s|--server)
server=$2
shift
shift ;;
-p|--port)
port=$2
shift
shift ;;
-a|--api)
api=$2
shift
shift ;;
-m|--method)
method=$2
shift
shift ;;
-l|--loopCount)
loopCount=$2
shift
shift ;;
-x|--maxuser)
maxuser=$2
shift
shift ;;
-h|--help)
echo "-f | --testFile: tsung test file xml,default $defaultTestFile"
echo "-u | --user: user number per second, default $defaultUser"
echo "-x | --maxuser: max user number, default $defaultMaxuser"
echo "-d | --duration: times used to generate user,default$defaultDuration s"
echo "-t | --thinktime: the inteval time between two request,default$defaultThinktime s"
echo "-l | --loopCount: Each user's request number,default$defaultLoopCount"
echo "-s | --server: play server,default $defaultServer"
echo "-p | --port: play server http port,default $defaultPort"
echo "-a | --api: api, default $defaultApi"
echo "-m | --method: POST/GET,default $defaultMethod"
echo "-h | --help: print this help"
shift
exit 1
;;
--)
shift
break
;;
*)
echo "wrong input:$1,use -h or --help see how to use" 1>&2
exit 1
;;
esac
done
processName="tsung"
pid=`ps aux | grep $processName | grep -v grep | awk '{print $2}'`
#convert from string to array
pid=($pid)
if [ ${#pid
} -gt 3]; then
echo "warning!!! a $processName process is running,please wait"
exit 1
fi
#env
#set default parameters
testFile=${testFile:=$defaultTestFile}
user=${user:=$defaultUser}
duration=${duration:=$defaultDuration}
thinktime=${thinktime:=$defaultThinktime}
server=${server:=$defaultServer}
port=${port:=$defaultPort}
api=${api:=$defaultApi}
method=${method:=$defaultMethod}
loopCount=${loopCount:=$defaultLoopCount}
maxuser=${maxuser:=$defaultMaxuser}
#key of params is nodname intusng_test.xml file
declare -A params
params=( \
["user"]=$user\
["maxuser"]=$maxuser\
["duration"]=$duration\
["thinktime"]=$thinktime\
["server"]=$server\
["port"]=$port\
["api"]=$api\
["method"]=$method\
["loopCount"]=$loopCount\
)
reportPath="$HOME/.tsung/log"
currentTest=`date +%Y%m%d-%H%M`
reportPath="$reportPath/$currentTest"
mkdir -p $reportPath
#deal with jmx file
cp $testFile$reportPath
currentTestFile="$reportPath/tsung_test.xml"
function replace(){
echo "$1:$2" | tee -a"$reportPath/test.env"
#change / to \/ forsed
local val=${2//\//\\\/}
sed -i "s/@${1}/${val}/" $currentTestFile
}
for key in ${!params
}
do
replace $key${params[$key]}
done
#start tsung
tsung -f $currentTestFile start&
wait %1
cd $reportPath
/usr/local/lib/tsung/bin/tsung_stats.pl
有不足地方还待改进。。