riak_sysmon使用和源码分析

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 进程来分别处理。

比较简单就说到这里。

2 Comments

  1. LinuxToday 说道:

    LinuxToday祝您新年快乐!合家团圆!

Leave a Reply