Archive

Archive for the ‘源码分析’ Category

Erlang heart – 高可靠性的最后防线

August 23rd, 2013 Comments off

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: Erlang heart – 高可靠性的最后防线

我们写的程序不可能都没有bug, 都存在crash的危险。很多时候我们需要个看门狗(watchdog)程序,在发现系统不正常的时候,就把系统重新启动。这类watchdog程序从内核到各种高可用程序都会设置有一个。erlang系统当然不能免俗,也会有几个heart.

我们来看下流程和效果:

$ export HEART_COMMAND="erl -heart"
$ erl -heart
heart_beat_kill_pid = 12640
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.3.1  (abort with ^G)
1> os:getpid().
"12640"
2> 
CTRL + Z 挂起erlang

$ pstree -p

+-beam.smp(12640)-+-heart(12670)
| | | |-{beam.smp}(12647)
| | | |-{beam.smp}(12648)
| | | |-{beam.smp}(12650)
| | | |-{beam.smp}(12653)
| | | |-{beam.smp}(12654)
| | | |-{beam.smp}(12655)
| | | |-{beam.smp}(12656)
| | | |-{beam.smp}(12657)
| | | |-{beam.smp}(12658)
| | | |-{beam.smp}(12659)
| | | |-{beam.smp}(12660)
| | | |-{beam.smp}(12661)
| | | |-{beam.smp}(12662)
| | | |-{beam.smp}(12663)
| | | |-{beam.smp}(12664)
| | | |-{beam.smp}(12665)
| | | |-{beam.smp}(12666)
| | | |-{beam.smp}(12667)
| | | |-{beam.smp}(12668)
| | | `-{beam.smp}(12669)
| | `-pstree(13702)

$ heart: Fri Aug 23 20:36:25 2013: heart-beat time-out, no activity for 65 seconds
heart_beat_kill_pid = 27920

我们看到erl重新被启动起来了。 现在简单的分析下原理:
heart由2部份组成:1. 外部程序: heart 2. erlang port模块: heart.erl

当开启heart的时候(erl – heart …) 外部程序heart被erlang模块heart.erl作为独立的进程启动起来,监视emulator的运作. heart.erl 每隔一定的时间向heart外部程序报告状态。当外部heart没有监测到心跳的时候就要采取行动, 重新运行$HEART_COMMAND所指定的命令。
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Erlang探索, 源码分析 Tags:

application之染色特性分析和应用

August 18th, 2013 Comments off

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: application之染色特性分析和应用

我们知道典型的erlang虚拟机里面会运行好多application,这些app互相依赖,相互协作,形成一个生态圈。典型场景见下图:

Screen Shot 2013-08-18 at 3.22.01 PM

每个app里面都会有很多进程,这些进程为这个app负责,会有些共同特性。那么这些进程如何区分出来属于哪个app的呢?就像我们伟大的祖国,有56个民族一样,这些民族都有自己的文化、服饰,甚至相貌,一看就和其他族群不太一样。他们的基因里面就携带了某种东西,这些东西子子孙孙传下去,一直保持下去。那么同样的,每个app里面的进程就和我们人,一样也会生老病死,也会有生命周期。他们是靠什么来识别的呢? 典型的application里面有很多层次的进程,通常成树状,和我们人类的组织差不多,见下图:

Screen Shot 2013-08-18 at 3.21.45 PM

我们先来看下application的文档和关键的几个函数:

which_applications() -> [{Application, Description, Vsn}]
Returns a list with information about the applications which are currently running. Application is the application name. Description and Vsn are the values of its description and vsn application specification keys, respectively.

示例如下:

1> application:which_applications().
[{os_mon,”CPO CXC 138 46″,”2.2.9″},
{sasl,”SASL CXC 138 11″,”2.2.1″},
{stdlib,”ERTS CXC 138 10″,”1.18.3″},
{kernel,”ERTS CXC 138 10″,”2.15.3″}]

我们可以看到我们运行的几个app的名字,版本号,描述等基本信息,再细节的就没有了。那第一,二个图中的这些信息是哪里来的呢?

Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Erlang新增全面的系统信息收集器-system_information模块

July 29th, 2013 Comments off

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: Erlang新增全面的系统信息收集器-system_information模块

Erlang其实是个操作系统,从下面的图可以看出它的架构:

erlang-vm

erlang系统设计的时候是完全按照unix的理念来平行移植的,它的引导进程叫otp_ring0,第一个进程叫init,有没有感觉很熟悉?
既然是一个操作系统,那么这个系统就是一个非常复杂的系统。erlang vm运行的时候是以unix的进程方式体现的,然后这个进程本身是个小世界,这个世界会跑着很多application,每个application包含配置,数据,模块代码等,多个applcaiton之间相互协作,完成指定的业务目标。

当我们的业务系统出现不按预期执行的时候,那么问题出在哪里呢?我们如何调查呢?
首先erlang当然提供了非常多的调查类的函数,如erlang:system_info,erlang:memory,os:getenv等提供各种各样的信息。但是问题是这些信息是散落在各地的,很难汇集起来提供全面的诊断信息。

官方在最近也认识到了这个问题,在最新的R16版本添加了system_information模块来解决这个问题,具体的patch参考 这里

这个patch总的来讲做了三件比较大的事情:

1. Add system information aggregate
2. Add erts app-file
3. erts: Add cflags, ldflags and config.h into executable

除聚合信息以外,还有一个就是把编译beam的时候的配置, cflags, ldflags 什么的都聚合进去。因为beam vm是依靠操作系统提供各种服务的,如锁,原子,epoll,网络等服务,这些服务每个系统都是不太一样的,出了问题很有必要先调查这些结合处。

新增加的system_information模块位于runtime_tools应用中,它的注释里面也写的清楚:

%% The main purpose of system_information is to aggregate all information
%% deemed useful for investigation, i.e. system_information:report/0.

简单的分析下代码,它聚合的信息主要有以下几块:
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

webtool小问题

July 29th, 2013 Comments off

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: webtool小问题

erlang的观察工具如crashdump,appmon,cover等工具有二种不同的界面:gs(wx)和web。这些tool都遵循一定的接口,用户可以自行扩展这些功能,使的能够融入toolbar或者webtool体系。 其中webtool在线上使用的时候比较方便,因为是web界面,容易过防火墙什么的。

webtool的使用界面如下:
webtool
但是默认的webtool在启动的时候,默认只在127.0.0.1:8888网络上监听,无法在其他机器上查看状态,这样使用起来很不方便。

演示下:

$ erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.3.1  (abort with ^G)
1> webtool:start().
WebTool is available at http://localhost:8888/
Or  http://127.0.0.1:8888/
{ok,<0.35.0>}
2> 

粗粗的研究下webtool的启动代码,可以透过下面的方式来绕开这个问题,注意下面这三个参数都需要的,具体的值用户自己配:

webtool:start(standard_path, [{bind_address, {0,0,0,0}},{port, 8888},{server_name, “foobar”}]).

这种方式默认是全部接口监听:

$ hostname -i
10.232.64.76

看下具体的网卡地址就可以访问到服务了,本例子中是: http://10.232.64.76:8888

祝玩的开心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Erlang探索, 源码分析 Tags:

ms()用途浅析

July 27th, 2013 1 comment

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: ms()用途浅析

erlang系统的application,稍微复杂一点的都会提供一个ms/0的导出函数,而且这个导出函数通常在文档里面找不到描述,很奇怪不是吗?
比如mnesia就有这样的ms, 我们来看下:

$ erl
Erlang R17A (erts-5.11) [source-b7fbc28] [64-bit] [smp:16:16] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.11  (abort with ^G)
1> mnesia:ms().
[mnesia,mnesia_backup,mnesia_bup,mnesia_checkpoint,
 mnesia_checkpoint_sup,mnesia_controller,mnesia_dumper,
 mnesia_loader,mnesia_frag,mnesia_frag_hash,
 mnesia_frag_old_hash,mnesia_index,mnesia_kernel_sup,
 mnesia_late_loader,mnesia_lib,mnesia_log,mnesia_registry,
 mnesia_schema,mnesia_snmp_hook,mnesia_snmp_sup,
 mnesia_subscr,mnesia_sup,mnesia_text,mnesia_tm,
 mnesia_recover,mnesia_locker,mnesia_monitor,mnesia_event]
2> 

看起来貌似只是返回组成mnesia的模块列表而已。
那么它的作用是什么呢?

复杂一点的程序都需要在运行期间来进行观察或者优化,比如说dbg跟踪一个函数或者模块运作的时候,是需要这个模块的名字的,如:

dbg:tp(Module,MatchSpec)

那么如果要跟踪整个application的运作,我们通常会写这样的代码:
[do_some_thing(M) || M<-myapp:ms()]. 所以这就是ms的意义所在。 现在的问题是mnesia的代码是把ms的模块硬编码的,这样会带来一个维护的问题,比如添加,改名或者减少一个模块都要记得去修改这个列表,很麻烦。 [erlang] %mnesia.erl ms() -> [ mnesia, mnesia_backup, mnesia_bup, ... ]. [/erlang] 程序员是个很懒的群体,必定不会这么挫的,于是rebar就专门花了点力气把这个事情做的漂亮。 rebar在编译application的时候,会把src/myapp.app.src的内容添加以下内容:

{modules,[mod_a, mod_b,…]}

形成ebin//myapp.app文件,这个文件是每个app必须的!

rebar处理这个事情的核心代码如下:

%%rebar_otp_app.erl
AppVars = load_app_vars(Config1) ++ [{modules, ebin_modules()}],
ebin_modules() ->
    lists:sort([rebar_utils:beam_to_mod("ebin", N) ||
                   N <- rebar_utils:beams("ebin")]).

Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Erlang探索, 源码分析 Tags: ,

进程死亡原因调查:被杀?

July 25th, 2013 3 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: 进程死亡原因调查:被杀?

最近MySQL平台化系统都是用热升级来更新的,在线上的日志发现类似的crashlog:

2013-07-24 23:54:06 =ERROR REPORT====
** Generic server <0.31760.980> terminating
** Last message in was {‘EXIT’,<0.29814.980>,killed}
** When Server state == {state,”app873″,false,172683,33,<<"app873">>,<0.29814.980>,ump_proxy_session,1,[59,32,204,78,86,208,242,122,240,207,269,79,80],[],2,true,<<>>,0,0,{conn_info,{10,246,161,112},10145,”app873″,”8813684fc05fb6cd”},<0.31762.980>,1,{conn_info,{172,18,134,8},10085,”app873″,”8813684fc05fb6cd”},ump_proxy_cherly_server,<0.31763.980>,1,undefined,<<>>,false,true,[],{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[[{session,names},103,98,107]],[],[],[],[],[],[],[[{session,”character_set_results”},78,85,76,76]],[],[],[],[],[],[],[]}}},1,0,0,0,0,0,200,1374681206757732}
** Reason for termination ==
** killed

其中Reason是killed, 有点困扰。

我们知道在热升级的时候会purge用旧代码的进程, purge的时候发现有必要就会exit(P, kill)让进程死亡,但是怎么kill变成了killed呢?

我们看下release_handler和code的代码,验证我们的判断:

%%release_handler_1.erl
eval({purge, Modules}, EvalState) ->
    % Now, if there are any processes still executing old code, OR
    % if some new processes started after suspend but before load,
    % these are killed.
    lists:foreach(fun(Mod) -> code:purge(Mod) end, Modules),
    EvalState;

%%code_server.erl
do_purge([P|Ps], Mod, Purged) ->
    case erlang:check_process_code(P, Mod) of
        true ->
            Ref = erlang:monitor(process, P),
            exit(P, kill),
            receive
                {'DOWN',Ref,process,_Pid,_} -> ok
            end,
            do_purge(Ps, Mod, true);
        false ->
            do_purge(Ps, Mod, Purged)
    end;

release_handler最终确实是调用了exit(P, kill)杀人,可是为什么对端收到killed死因呢?

再深入调查下原因,我们知道exit是虚拟机内部的实现,简单的grep下killed就可以看到send_exit_signal这个执行函数:
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Erlang探索, 源码分析 Tags:

谁引起busy_dist_port

July 4th, 2013 Comments off

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: 谁引起busy_dist_port

Erlang节点间RPC通道的载波是tcp,实现上是一个带特殊标志的tcp port, 当这个节点由于某种原因发生拥堵的时候,就会影响到节点间的交互,是个很严重的事情,具体参见 Erlang集群RPC通道拥塞问题及解决方案 博文。

riak_sysmon 提供了busy_dist_port的监控方法,我们在这基础上改进了下,在日常环境中发现了不少busy_dist_port问题,如图:

sysmon_distbusyport

从图中可以看出,我们的系统在几天前busy_dist_port还是比较严重的,后面我们透过+zdbbl 8192参数来修正了这个问题,busy_dist_port问题从图中也消失了。
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.