IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    riak_sysmon使用和源码分析

    hoterran发表于 2012-10-22 11:41:48
    love 0

    riak_sysmon 是利用 BIF 函数 system_monitor 来监控 Erlang vm 产生的消息状态的项目。下面结合使用来分析一下其源码。

    由于使用 system_monitor,那么 riak_sysmmon 仅能做到如下四类事件的捕获:

    1. 进程的 heap 超过预设的 heap_word_limit。
    2. gc 的收集时间过长超过预设的 gc_ms_limit。
    3. 繁忙的文件或者套接口 port。
    4. Erlang 节点之间的网络通信烦忙。

    riak_sysmon 启动之后,会产生两个 gen 进程。其一为 riak_sysmon_filter,这个进程会做如下工作:

    1. 读取app或者config里的阀值(heap_word_limit,gc_ms_limit等)。
    2. 根据阀值来启动 system_monitor ,让 vm 发现有超过阀值的状态,发消息给 riak_sysmon_filter 进程。
    3. riak_sysmon_filter 对这些消息进行过滤,然后 notify 给另外一个 riak_sysmon_mgr 的  gen_event 进程,通知其做出相应的行为。

    开始之时,riak_sysmon_mgr 是没有 handler 来处理对应事件的,需要用户自己写一个 module 来处理消息事件。 我们可以利用项目自带的一个 example 来看看效果,这个 exmaple 仅仅是把收到的事件通过 error_logger 给打印出来,我们来使用 riak_sysmon :

    erl -sname node1 -boot start_sasl -pa ebin
    (node1@hoterran-laptop)1> application:start(riak_sysmon).
    ok
    (node1@hoterran-laptop)2> riak_sysmon_example_handler:add_handler().
    ok

    两个进程已经启动,handler 也设置后,我们来构造一个让 heap 逐渐涨大的例子 t.erl:

    -module(t).
    -behaviour(gen_server).
    
    -export([start_link/1]).
    -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
    
    -define(SERVER,	?MODULE).
    
    -record(state, {l}).
    
    start_link(Args) ->
    	gen_server:start_link({local, ?SERVER}, ?MODULE, [Args], []).
    
    init([Args]) ->
    	io:format("Args is ~p~n", [Args]),
    	{ok, #state{l=[]}, 1000}.
    
    handle_call(Msg, {From,_}, State) ->
    	{reply, call_ok, State}.
    
    handle_cast(Msg, State) ->
    	{noreply, State}.
    
    handle_info(Info, State) ->
    	L = State#state.l ++ lists:duplicate(1000, "test"),
    	{noreply, #state{l=L}, 1000}.
    
    terminate(Reason, _State) ->
    	ok.
    
    code_change(_OldVsn, _State, _Extra) ->
    	{ok, _State}.

    我们启动这个 t  之后,他的 heap 会逐渐变最终超过预设的 heap 阀值,最后触发了 system_monitor 的信息。

    (node1@hoterran-laptop)3> t:start_link("test").
    Args is "test"
    {ok,<0.60.0>}
    (node1@hoterran-laptop)4>
    =INFO REPORT==== 22-Oct-2012::19:25:43 ===
    Example: event {monitor,<0.60.0>,large_heap,
                            [{old_heap_block_size,0},
                             {heap_block_size,17711},
                             {mbuf_size,0},
                             {stack_size,10},
                             {old_heap_size,0},
                             {heap_size,10015}]}
    
    =INFO REPORT==== 22-Oct-2012::19:25:44 ===
    Example: event {monitor,<0.60.0>,large_heap,
                            [{old_heap_block_size,28657},
                             {heap_block_size,28657},
                             {mbuf_size,0},
                             {stack_size,10},
                             {old_heap_size,6012},
                             {heap_size,8003}]}
    
    =INFO REPORT==== 22-Oct-2012::19:25:46 ===
    Example: event {monitor,<0.60.0>,large_heap,
                            [{old_heap_block_size,28657},
                             {heap_block_size,46368},
                             {mbuf_size,0},
                             {stack_size,10},
                             {old_heap_size,6012},
                             {heap_size,22003}]}

    总结

    riak_system_filter 有如下好处:

    1. 对于以上 1,2 类的消息条数进行过滤,每秒仅仅捕获前 proc_limit 条。
    2. 对于 3,4 每秒仅仅捕获前 port_limit 条,避免瞬时接受过多的消息。
    3. 原来的 system_monitor 只能发送某个进程,这里可以通过 filter 转发 gen_event:notify 给多个 handler 进程来分别处理。

    比较简单就说到这里。



沪ICP备19023445号-2号
友情链接