Tsung源码分析(二):Tsung压力生成过程

上一篇讲到ts_config_server:newbeams通过ts_launcher:launchts_launcher_static:launch启动本地和远程结点压力客户端,其中ts_launcher用于随机生成用户ts_launcher_static主要用于静态生成用户。这一篇详细的说明压力客户端是如何启动的。

         说明:压力客户端是指一个tsung应用,见TUNG_ROOT/src/tsung/tsung.erl

 

         newbeams会通过gen_server:cast/2调用回调函数ts_config_server:handle_cast/2,代码见下:

 

handle_cast({newbeams, HostList}, State=#state{logdir   = LogDir,
                                               hostname = LocalHost,
                                               config   = Config}) ->
    LocalVM  = Config#config.use_controller_vm,
    GetLocal = fun(Host)-> is_vm_local(Host,LocalHost,LocalVM) end,
    {LocalBeams, RemoteBeams} = lists:partition(GetLocal,HostList),
    case local_launcher(LocalBeams, LogDir, Config) of
        Id0 ->
            Seed=Config#config.seed,
            Args = set_remote_args(LogDir, Config#config.ports_range),
            {BeamsIds, LastId} = lists:mapfoldl(fun(A,Acc) -> {{A, Acc}, Acc+1} end, Id0, RemoteBeams),
            Fun = fun({Host,Id}) -> remote_launcher(Host, Id, Args) end,
            RemoteNodes = ts_utils:pmap(Fun, BeamsIds),
            ?LOG("All remote beams started, sync ~n",?NOTICE),
            global:sync(),
            StartLaunchers = fun(Node) ->
                                     ts_launcher_static:launch({Node,[]}),
                                     ts_launcher:launch({Node, [], Seed})
                             end,
            lists:foreach(StartLaunchers, RemoteNodes),
            {noreply, State#state{last_beam_id = LastId}}
end;

 

参数说明:

HostList代表要启动的压力客户端,这个主要由tsung配置文件中的clients段配置。client配置项中有一个cpu属性,当声明这个属性时,会根据cpu的数量生成多个压力客户端。比如:

 

<clients><client host="memphis" weight="3" maxusers="600"/><clients>
 

只会生成一个压力客户端,而

 

 

<clients><client host="memphis" weight="3" maxusers="600" cpu=”2”/><clients>
 

则会生成两个压力客户端。

 

在调用local_laucher之前,GetLocal函数会将压力客户端分成LocalBeamsRemoteBeams,区分这二者的关键是use_controller_vm这个选项,只有这个选项为true时,GetLocal函数才会把与启动tsung结点相同的结点看作是LocalBeams,并通过local_launcher函数在启动tsungErlang虚拟机上,再启动一个压力客户端。否则,即使Host在启动tsung的结点上,也会被认为是RemoteBeam

set_remote_args设置用于启动远程压力客户端的参数,参数内容跟上一篇中tsung.sh使用的启动命令相似。

remote_launcher完成的功能很简单:通过slave:start/3启动远程压力客户端。slave:start/3函数通过Erlangport机制ssh到远程结点,并运行通过set_remote_args构建的命令来启动远程压力客户端。在erlangslave手册中,有如下描述:

The user must be allowed to rsh to the remote hosts without being prompted for a password.

这也是为什么在tsung用户手册的依赖那一节中,有如下要求:

for distributed tests, you need an ssh access to remote machines without password.

 

global:sync函数调用后,远程压力客户端算是启动完毕,但是实际的压力还没有生成。ts_launcher:launchts_launcher_static:launch启动实际的压力。这里只分析ts_launcher的实现。

ts_launcher:launch的代码如下: 

 

launch({Node, Arrivals, Seed}) ->
    ?LOGF("starting on node ~p~n",[[Node]], ?INFO),
    gen_fsm:send_event({?MODULE, Node}, {launch, Arrivals, Seed})

       Node:代表要启动的远程结点主机名;

       Arrivals:代码中传递的是空数组;

       Seed:随机数种子,默认是当前时间;

       gen_fsm:send_event调用会将事件发送到远程结点上,然后在远程结点上启动会话进程。

 

launch函数的调用栈:wait->wait_static->launcher

最终launcher通过调用do_launcher启动一个会话进程。do_launcher先通过ts_config_server:get_next_session拿到用户的session信息,然后通过ts_client_sup:start_c hild启动一个会话进程(实际与测试服务器会话还要等一个timer过期会才会真正触发)

一个会话进程成功启动后,通过change_phase调用确定是在当前phase再继续启动会话进程,还是进入下一个启动phase

至于一个phase到底启动多少个会话进程,这是由tsung配置文件中load节的arrivalpahse来定义的,根据每个phase配置的每毫秒用户到达速度(两种配置方式:interarrivalarrivalrate,解析时会转换成每毫秒速度)及持续时间来确定(这个值同时受到该phase最大启动会话的限制)。但是最终启动的会话可能不会精确的与这个值相同,这主要是因为生成会话进程的过程本身也会对tsung的控制器产生压力,导致当phase的持续时间已经用完时,期望的会话进程数量还没有达到。

 

当所有phase的会话都已经启动完毕后,等待所有会话进程完成会话。

你可能感兴趣的:(erlang,tsung)