一方面,分析Tsung的架构及实现,另一方面,也是一个学习Erlang的过程,所以如果有碰到不了解的东西,也会记录下来。
(该分析系统基于Tsung 1.4.2,涉及到Erlang源码的部分会以R15B为基础)
Tsung由tsung.sh(默认位置:/usr/bin/tsung)来启动。调用tsung.sh后,会进入到start()函数中,然后调用默认的erl命令来启动一个Erlang运行时系统。完整命令如下:
$ERL $ERL_OPTS $ERL_RSH -noshell $PROTO_DIST $NAMETYPE $CONTROLLER -setcookie $COOKIE $BOOT_OPT \ -pa $TSUNGPATH -pa $CONTROLLERPATH \ -tsung_controller smp_disable $SMP_DISABLE \ -tsung_controller debug_level $DEBUG_LEVEL \ -tsung_controller warm_time $WARM_TIME \ -tsung_controller config_file \"$CONF_OPT_FILE\" -tsung_controller $LOG_OPT -tsung_controller $MON_FILE
捡几个重要的参数说明一下:
1) $ERL_RSH:指定Erlang要使用的rsh程序,用于启动slave结点,具体见slave模块说明。配置文件中的值为:-rsh ssh,也就是通过ssh命令启动slave。在Tsung中,主控结点要启动压力客户端时,要使用这种程序;
2) $NAMETYPE $CONTROLLER -setcookie $COOKIE:值为-sname tsung_controller –setcookie tsung,用于指定当前启动Erlang结点的名称以及结点的cookie。共享同一个cookie的Erlang节点才可以进行通信;
3) $BOOT_OPT:值为-boot $INSTALL_DIR/lib/tsung_controller-$VERSION/priv/tsung_controller,这个参数指定在erl命令启动时,加载tsung_controller.boot。boot文件中详细说明了应该如何启动应用。而boot文件本身是由script脚本生成,script脚本又是根据.app及.rel文件生成(可见script说明)。rel文件称为发布资源文件,详细说明该发布的名称、版本、ERTS的版本、包含的应用(application)。app文件称为应用的资源文件,详细说明该应用的版本、包含的模块,启动阶段等。在这里只要知道最终启动是的tsung_controller.erl,然后要注意到tsung_controller.app中定义的启动阶段为:{start_phases, [{load_config, []},{start_os_monitoring,[{timeout,30000}]},{start_clients,[]}]}。
其它的-tsung_controller只是通过命令行的形式向tsung_controller应用传递参数。
(下文中的模式是指OTP行为包中预先定义的常用模式:主要有application,supervisor,gen_server,gen_fsm)
=> TSUNG_ROOT/src/tsung_controller/tsung_controller.erl:(application)
erl命令按照boot文件启动后,会调用tsung_controll:start。start函数完成的功能很简单:在用户的home目录下创建.tsung/log/20111222-1630(时间)目录,然后创建[email protected]文件,用于记录tsung的启动过程及后面的压力生成过程。文件创建成功后,会将控制转移到ts_controller_sup:start_link函数。
当然根据application模式的定义,start函数需要返回顶层监控进程的进程标识符,ts_controller_sup:start_link会返回这个标识符。
=> TSUNG_ROOT/src/tsung_controller/ts_controller_sup.erl:(supervisor)
该模式的主要任务就是监控他的子进程,并且基于一些预设的规则,当子进程终止时采取行动。
ts_controller_sup:start_link会调用supervisor:start_link,该函数会启动一个监控进程,用来调用ts_controller_sup :init函数,该函数会返回监控进程的设置以及该监控进程下的子进程的列表。
ts_controller_sup的监控设置:{one_for_one, 4, 10},代表该监控进程会重新启动终止的子进程,并且在10秒内最多可以重启子进程4次。
ts_controller_sup返回的子进程列表如下表所示:
进程名称 |
角色 |
描述 |
ts_config_server: start_link |
工作进程 |
配置的加载 |
ts_mon:start |
工作进程 |
统计日志 |
ts_stats_mon:start |
工作进程 |
|
ts_stats_mon: start(request) |
工作进程 |
session中request统计 |
ts_stats_mon: start(page) |
工作进程 |
session中page统计 |
ts_stats_mon: start(connection) |
工作进程 |
session中connection统计 |
ts_stats_mon: start(transaction) |
工作进程 |
session中transaction统计 |
ts_match_logger: start |
工作进程 |
匹配日志(match) |
ts_os_mon_sup: start_link(erlang) |
监控进程 |
通过Eralng方式监控服务器消耗 |
ts_os_mon_sup: start_link(munin) |
监控进程 |
通过Munin方式监控服务器消耗 |
ts_os_mon_sup: start_link(snmp) |
监控进程 |
通过SNMP方式监控服务器消耗 |
ts_time:start |
工作进程 |
定时器 |
ts_msg_server:start |
工作进程 |
消息服务进程,用于消息的生成 |
ts_user_server_sup: start_link |
监控进程 |
用户管理服务进程 |
ts_job_notify: start_link |
工作进程 |
在ts_controller_sup:init执行完毕后,会返回到tsung_controller:start。
=> TSUNG_ROOT/src/tsung_controller/tsung_controller.erl:(application)
Tsung_controller:start执行完毕后,erl会根据tsung_controller.app中定义的start_phases中定义的启动阶段按阶段执行:start_phase(load_config)-> start_phase(start_os_monitoring)-> start_phase(start_clients),分别完成加载配置、开始服务器监控(通过配置文件中的monitor指定)、启动压力客户端。后续说明只分析下start_phase(start_clients)的实现。
start_phase(start_clients)会调用ts_mon:start_clients函数启动压力客户端。
=> TSUNG_ROOT/src/tsung_controller/ts_mon.erl:(gen_server)
ts_mon:start_clients-> start_logger-> start_launchers
ts_mon:start_launchers会以压力客户端列表为参数调用ts_config_server:newbeams。
=> TSUNG_ROOT/src/tsung_controller/ts_config_server.erl:(gen_server)
ts_config_server:newbeams主要会调用两个函数: local_launcher,remote_launcher。
如果use_controller_vm是true,ts_config_server:local_launcher会被调用,并且会先加载Tsung中的第二个application:tsung,然后启动该应用。启动成功后,会调用ts_launcher:launch和ts_launcher_static:launch(for static user)在启动tsung_controller应用的同一个VM上启动一个压力进程。
ts_config_server:local_launcher-> start_slave启动远程结点。start_slave通过slave:start函数启动远程erl进程(通过start函数的arg参数传递命令行参数(通过set_remote_args构造),命令内容跟启动tsung_controller应用的基本相同,只不是启动的应用不是tsung_controller,而是tsung),并通过net_adm:ping验证远程端口是否打开。验证成功后,newbeams会为每一个远程结点分别调用ts_launcher_static:launch和ts_launcher:launch启动压力进程。
=> TSUNG_ROOT/src/tsung/ts_launcher.erl:(gen_fsm)
ts_launcher:launch->wait->wait_static->launcher->do_launch。
do_launcher通过ts_config_server:get_next_session拿到配置中定义的session信息,然后通过ts_client_sup:start_child来启动一个会话进程。
launcher会循环启动会话进程,直到完成所承担的压力数量。
=> TSUNG_ROOT/src/tsung/ts_client_sup.erl:(supervisor)
ts_client_sup:start_client通过supervisor:start_child生成一个会话进程。ts_client_sup启动的会话进程为ts_client,由其负责与测试服务器之间的交互。
这样,基本就完成了Tsung的启动过程,并且会话客户端已经启动,然后每个会话客户端会按照配置中定义的session来与测试服务器进行交互,直到会话完成,然后完成测试。