在压力测试过程中,对被测试的服务器进行监控,观测其负载的相关数据,能更好的帮助我们找到程序的瓶颈。
Tsung默认支持erlang,snmp,munin三种监控方式,这里重点介绍erlang的监控方式。
使用erlang作为监控,其配置为:
<monitoring> <monitor host="hncscwc" type="erlang"/> </monitoring>host: 待监控的目标服务器
type: 使用的监控方式
测试完成后, 在生成的图表中,可以看到目标服务器的相关信息,包括CPU,内存,数据包收发情况等。
注: 使用erlang作为监控的方式时,目标机器上必须要安装同样版本的erlang/otp,另外,ssh免密码登陆也需要先配置好。
很多时候,我们希望客户端发送的请求带有不同的参数,或者同样的请求带有不同的消息内容,这样能更加真实的模拟实际的使用场景。Tsung的动态替换能很好的帮助我们完成这样的测试。
Tsung中最常用的方式是将动态产生的内容保存在一个变量中,后续需要用到的地方引用这个变量完成动态替换。例如:
<setdynvars sourcetype="random_number" start="3" end="100"> <var name="id" /> </setdynvars> <request subst="true"> <http url="/push?id=%%_id%%" version="1.1" method="POST" /> </request>setdynvars元素及相关属性指定动态内容产生的方式,子元素var指定变量的名称,变量用于存储产生的动态内容,供后续使用替换。在request中使用这个变量完成动态替换,注意使用变量的方式是:下划线加变量名,并且包含在一对%%中。另外,request必须指定为需要进行动态替换(即subst="true"),否则不会进行动态替换。
上面的例子中在3到100中随机产生一个数字,并保存在变量id中,请求URL的参数中使用这个变量达到每次请求带有随机的参数。
除了产生随机的数字,还可以产生随机的字符串,或者自己编写函数产生随机的内容,甚至从文件中获取。
随机产生长度为10的字符串:
<setdynvars sourcetype="random_string" length="10"> <var name="param" /> </setdynvars>从函数中获取随机内容:
<setdynvars sourcetype="erlang" callback="ts_user_server:get_unique_id"> <var name="uid" /> </setdynvars>从文件中获取:
<options> <option name="file_server" id="userdb" value="./user.csv" /> </options> <setdynvars sourcetype="file" fileid="userd" delimiter=";"> <var name="user" /> <var name="passwd" /> </setdynvars> <request subst="true"> <http url="login?user=%%_user%%&passwd=%%_passwd%%" version="1.1" method="GET" > </request> =====以下为user.csv文本的内容===== Curry;123456; Park;123; Paul;111;除了上面所说的方式,我们还可以将服务器响应的信息保存下来,在后续的请求中完成动态替换。例如:
<request> <dyn_variable name="date" header="date" /> <http url="/test" method="GET" version="1.1" /> </request> <request subst="true"> <http url="/home/?date=%%_date%%" method="GET" version="1.1" /> </request>在第一个请求中,从服务器响应信息的http头部中取出date对应的内容,保存在名为date的变量中,在下一个请求的参数中完成动态替换。
我们还可以使用正则表达式,XPATH,JSONPATH对响应消息的内容进行匹配获取我们所需要的数据。
<request> <dyn_variable name="mytitlevar" re=<title>(.*)</title>"/> <http url="/testtsung.html" method="GET" version="1.0" /> </request> <request> <dyn_variable name="title" xpath="/html/head/title/text()" /> <http url="/testtsung.html" method="GET" version="1.0" /> </request> <request> <dyn_variable name="title" jsonpath="field.array[3].value" /> <http url="/testtsung.html" method="GET" version="1.0" /> </request>
for循环:
<for from="2" to="10" incr="2" var="counter"> ... <request subst="true"> <http url="/page/?id=%%_counter%%" /> </request> ... </for>repeat重复:
<repeat name="myloop" max_repeat="40"> <request> <dyn_variable name="result" re="Result:(.*)" /> <http url="/random" method="GET" version="1.1" /> </request> ... <until var="result" eq="5" /> </repeat>重复请求/random,返回值保存在result变量中,当返回值内容等于5时,停止请求,最多请求40次。
if判断:
<request> <dyn_variable name="result" re="Result: (.*)" /> <http url="/random" method="GET" version="1.1" /> </request> <if var="result" eq="3"> <request><http url="/foo" /></request> <request><http url="/bar" /></request> </if>如果"/random"请求的结果为3,则再次请求"/foo","/bar"。
Tsung主要由tsung_controller和tsung两个application共同完成压力测试,其中tsung_controller主要负责配置文件的解析,监控数据的统计,日志的记录等;tsung主要负责压力的产生,并完成与服务器的通信。两个应用一些关键的进程及进程树如下图所示:
Tsung运作的大概流程是:
1) 启动tsung_controller应用,初始化相关进程,然后由ts_config_server完成配置文件的解析
2) 根据配置需要启动对服务器的监控
3) 根据配置在不同节点上创建erlang虚拟机进程,并启动tsung应用,然后由ts_launcher进程和ts_launcher_static进程开始产生压力,这两个进程会不断创建出ts_client进程,最终在ts_client进程中模拟用户的行为完成与服务器的通信。
相关通信流程大致如下图所示:
ts_launcher_static和ts_launcher进程向ts_config_server进程请求压力阶段配置的相关信息,ts_client向ts_session_cache请求会话动作配置的相关信息,ts_session_cache转向ts_config_server请求并缓存。
压测过程中ts_client向ts_mon_cache进程异步发送采样数据,ts_mon_cache进程定时将统计信息发送至相关的状态统计进程。
tsung默认支持amqp,mysql,http,jabber等协议。在会话动作配置中类型指定为对应的类型,如ts_amqp,ts_mysql,ts_http等。实际上,指定的类型就是对应的内部模块的名称,在运行过程中调用这些模块的相关接口,完成配置的解析,请求的数据编码,服务器响应数据的解析等。了解了这些后我们能比较方便的编写插件模块来支持自家的协议。
所有的插件模块(不管是内部的ts_amqp,ts_http模块,还是自己编写的模块,我们统称为插件模块)都必须符合ts_plugin行为模式,这个行为模式指定了必须实现的导出函数。
在解析配置的时候调用对应插件魔窟开的session_defaults,parse_config函数,在与服务器通信时(ts_client进程中)会调用其他的函数。
插件模块通常放置在tsung-Version/src/tsung目录下,重新编译安装tsung就可以使用了,当然也可以单独进行编译,然后将编译后的beam文件放到对应的目录下即可。另外,编写插件通常会在配置文件中引入新的配置项,我们还需要同步修改dtd文件,保证新增的配置项是可被正确解析的。
tsung中采用了erlang/otp自带的xmerl模块完成xml的解析。该模块使用较简单,调用xmerl_scan的string函数或者file函数完成xml的解析,解析后的内容是一个xmlelement的record,里面包含了所有的元素,对应的属性等信息。从中获取我们需要的信息即可。
tsung中多台物理机共同完成压力测试,或者是通过erlang的方式对服务器进行监控。最终都是由ts_config_server进程远程到对应的物理机上,创建一个erlang虚拟机进程,然后进行rpc调用完成相应的控制。这个过程具体实现是调用了slave:start(Host, Name, Args)完成的。
slave模块默认使用rsh(remote shell)的方式登录到Host指定的目标机器上,运行erlang虚拟机进程。我们也可以在启动时带上-rsh参数切换使用的登录方式,例如"-rsh ssh"表示使用ssh的方式远程登录到目标机器(tsung默认使用的方式是ssh)。
因此,为什么所有机器都必须安装erlang/otp,为什么要搞定ssh免密码登录,为什么多台物理机同时模拟用户开始压测时只需要在其中一台上面执行命令,所有这些都可以解释清楚了。