Tsung在进行压力测试同时,也可以监控服务器结点上的CPU、内存、系统负载等信息(详见监控一节)。
Tsung提供了三种监控方式:Erlang,SNMP,Munin。在tsung_controller启动的第二个阶段,会通过ts_os_mon:activate启动服务器监控。activate函数的执行很简单,通过ts_config_server:get_monitor_hosts拿到要监控的服务器列表,根据配置的监控方式调用ts_os_mon_sup:start_child来启动相应类型的监控进程,比如配置的监控类型为Erlang,那么ts_os_mon_sup:start_child最终会调用到ts_os_mon_erlang:init,对应SNMP,则是ts_os_mon_snmp:init。下面分别分析ts_os_mon_erlang和ts_os_mon_snmp的实现(Munin不了解,暂不做分析)
ts_os_mon_erlang:init的关键代码如下:
init( {Host, {}, Interval, MonServer} ) -> {ok, LocalHost} = ts_utils:node_to_hostname(node()), case list_to_atom(LocalHost) of Host -> % same host, don't start a new beam Pid = spawn_link(?MODULE, updatestats, [Interval, MonServer]), {ok, #state{node=node(),mon=MonServer, host=Host,interval=Interval,pid=Pid}}; _ -> erlang:start_timer(?INIT_WAIT, self(), start_beam), {ok, #state{host=Host, mon=MonServer, interval=Interval}} end
当要监控服务器是当前服务器结点的时候,直接创建一个进程,执行updatestats函数,该函数会每隔Interval时间自调用一次,通过node_data函数收集服务器的监控数据,并发送到负责统计的进程。如果要监控的服务器是远程结点,init函数通过start_beam调用先在远程结点上启动一个Erlang虚拟机,并把跟监控相关的几个模块的代码加载到虚拟机中,然后执行的代码就跟本地的执行类似,只不过统计数据要发送到主控结点上的统计进程。updatestats函数的具体代码如下:
updatestats(Interval,Mon_Server) -> Node = atom_to_list(node()), {Cpu, FreeMem, RecvPackets, SentPackets, Load} = node_data(), ts_os_mon:send(Mon_Server,[{sample, {cpu, Node}, Cpu}, {sample, {freemem, Node}, FreeMem}, {sample, {load, Node}, Load}, {sample_counter, {recvpackets, Node}, RecvPackets}, {sample_counter, {sentpackets, Node}, SentPackets}]), timer:sleep(Interval), updatestats(Interval,Mon_Server)其中的 Mon_Server 参数就代表主控结点。
node_data实现比较简单,有Erlang通用接口可以使用的就直接调用,比如CPU相关的通过cpu_sup模块相关函数;如果没有通用接口,则根据系统的具体类型,通过os:cmd直接执行命令来获取,比如内存,Linux下通过free,Solaris通过vmstat。
ts_os_mon:add的实现如下:
send(Mon_Server, Data) when is_pid(Mon_Server) -> Mon_Server ! {add, Data}; send(Mon_Server, Data) -> gen_server:cast(Mon_Server, {add, Data})也就是如果在本地的话,直接发送到监控进程,如果监控远程服务器,则监控数据发回到主控结点(至于数据如何处理后续文章会继续分析)。
SNMP类型的监控原理上同Erlang监控类似,只不过在初始化时,ts_os_mon_snmp会检查要监控的目标服务器上SNMP服务有没有启动。如果没有,通过application:start(snmp)先加载snmp应用,再通过snmpm:start启动SNMP服务,然后按照SNMP的协议获取服务器的相关信息,并通过ts_os_mon将监控数据发送到主控结点的数据统计进程。