Archive

Author Archive

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

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…

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

epmd端口定制

July 6th, 2013 1 comment

在前面一篇 Erlang epmd的角色以及使用 我们知道epmd是起到节点名称和地址的转换服务,绑定在周知端口4369.
但是这也会带来三个问题:
1. 因为是周知端口,所以通过查询目标机器上的4369,就可以知道这个机器上节点的情况。
2. 在同一机器可能会部署不同的Erlang集群,希望不要互相干扰。
3. 防火墙不允许过4369端口,或者不在开放端口之列表。

这就需要对epmd绑定的端口能够定制。

参见epmd的文档

ERL_EPMD_PORT
This environment variable can contain the port number epmd will use. The default port will work fine in most cases. A different port can be specified to allow several instances of epmd, representing independent clusters of nodes, to co-exist on the same host. All nodes in a cluster must use the same epmd port number.

Read more…

谁引起busy_dist_port

July 4th, 2013 Comments off

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…

持续学习的习惯

July 4th, 2013 5 comments

元朔同学的百阿毕业感言写的洋洋洒洒,谁再说程序员没有文学青年,我和谁急! 摘抄部分如下:

霸曰:“学不在多,在乎深也;书不在众,在乎智也。君子生非异也,为何有智与愚之异?人之学无难易,学之,则难者亦易已;不学,则易者亦难矣,是故聪与敏,可恃而不可恃也;自持其聪与敏而不学者,自败者也。孰知卖油翁否?油自钱孔入而钱不湿,盖因熟能生巧也,吾于闲暇时学Erlang,六载积有一万时也,故业精于勤荒于嬉,此万古真理也。”

点点滴滴,持续积累,我相信一万小时投入会让一个人成为领域专家的。
祝学的开心!

Categories: 杂七杂八 Tags:

crash_dump中Taints项含义

July 2nd, 2013 Comments off

erlang的应用程序出问题的时候通常会生成一个dump文件,这个文件很好的保存了当时的现场,很利于后面诊断问题。 比如:

=erl_crash_dump:0.1
Sun Jun 23 15:35:39 2013
Slogan: Kernel pid terminated (application_controller) ({application_start_failure,ump_proxy,{bad_return,{{ump_proxy_app,start,[normal,[]]},{‘EXIT’,{undef,[{cherly_server,start_link,[ump_proxy_cherly_server
System version: Erlang R15B02 (erts-5.9.2) [64-bit] [smp:16:16] [async-threads:5] [hipe] [kernel-poll:true]
Compiled: Fri Sep 14 13:23:22 2012
Taints: ump_proxy_partitioner_nifs,asn1rt_nif,crypto,dyntrace,ump_la_nifs
Atoms: 37857

crash_dump也开门见山的描述了出错的原因,系统的版本,编译时间,原子的个数,还有一个叫做Taints的东西。
前面这几个都很好理解,原子的个数也能理解,毕竟原子表是有大小限制的,爆了一定要crash的。 那这个Taints是哪路神仙,也要列在这么重要的位置。
从字面上理解,Taints的意思就是污染的意思,再看它的内容很明显都是nif模块的名字。
看到这些nif列表,大概就能明白了。由于nif是在vm里面运作的, 如果有bug或者问题,就会直接把vm挂掉,所以官方信任自己的vm代码,系统出了问题,第一时间就会怀疑到用户写的nif代码,也是很自然的。

Erlang开发组的人回答是:

The idea was a way to see all user libraries that has ever been loaded
and executed by the VM. Currently it only shows NIF libraries, but
driver names will hopefully be added as well in some future release.

/Sverker, Erlang/OTP Ericsson

我们从代码验证下:
Read more…

Erlang节点重启导致的incarnation问题

June 29th, 2013 7 comments

今天晚上mingchaoyan同学在线上问以下这个问题:

152489 =ERROR REPORT==== 2013-06-28 19:57:53 ===
152490 Discarding message {send,<<19 bytes>>} from <0.86.1> to <0.6743.0> in an old incarnation (1 ) of this node (2)
152491
152492
152493 =ERROR REPORT==== 2013-06-28 19:57:55 ===
152494 Discarding message {send,<<22 bytes>>} from <0.1623.1> to <0.6743.0> in an old incarnation (1) of this node (2

我们中午服务器更新后,日志上满屏的这些错误,请问您有遇到过类似的错误吗?或者提过些定位问题,解决问题的思路,谢谢

这个问题有点意思,从日志提示来再结合源码来看,马上我们就可以找到打出这个提示的地方:

/*bif.c*/
Sint
do_send(Process *p, Eterm to, Eterm msg, int suspend) {
    Eterm portid;
...
} else if (is_external_pid(to)) {
        dep = external_pid_dist_entry(to);
        if(dep == erts_this_dist_entry) {
            erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
            erts_dsprintf(dsbufp,
                          "Discarding message %T from %T to %T in an old "
                          "incarnation (%d) of this node (%d)\n",
                          msg,
                          p->id,
                          to,
                          external_pid_creation(to),
                          erts_this_node->creation);
            erts_send_error_to_logger(p->group_leader, dsbufp);
            return 0;
        }
..
}

触发这句警告提示必须满足以下条件:
1. 目标Pid必须是external_pid。
2. 该pid归宿的外部节点所对应的dist_entry和当前节点的dist_entry相同。

通过google引擎,我找到了和这个描述很相近的问题:参见 这里 ,该作者很好的描述和重现了这个现象,但是他没有解释出具体的原因。

好,那我们顺着他的路子来重新下这个问题.
但演示之前,我们先巩固下基础,首先需要明白pid的格式:
可以参见这篇文章:

pid的核心内容摘抄如下:

Printed process ids < A.B.C > are composed of [6]:
A, the node number (0 is the local node, an arbitrary number for a remote node)
B, the first 15 bits of the process number (an index into the process table) [7]
C, bits 16-18 of the process number (the same process number as B) [7]

再参见Erlang External Term Format 文档的章节9.10
描述了PID_EXT的组成:

1 N 4 4 1
103 Node ID Serial Creation
Table 9.16:
Encode a process identifier object (obtained from spawn/3 or friends). The ID and Creation fields works just like in REFERENCE_EXT, while the Serial field is used to improve safety. In ID, only 15 bits are significant; the rest should be 0.

Read more…

erlang coredump问题

June 27th, 2013 2 comments

早上成立涛同学问道:

: :)我们最近发生了几次宕机。。节点无缘无故就没有了。也没有crash dump,也不知道任何线索。

我们知道erlang的VM在正常运作的时候,如果发现erlang程序的异常或者虚拟机资源不够如内存不够的时候,会产生erl_crash.dump文件,里面把crash的原因和上下文描述的非常清楚,定位问题起来就很容易。但是vm本身是c实现的,如果vm的实现有bug或者系统用到了自己写的nif,这个情况下就很容易把vm搞挂了。 vm都挂了,就不再可能还有机会产生erl_crash.dump.
所以这时候应该产生的是操作系统的core,碰巧如果系统的coredump没开,那么节点就会看起来无缘无故的消失了。

我摘取我们的个案给大家看下:我们在erlang系统里面用到了nif, 这个nif不是多线程安全的,所以在运作的时候产生问题了,搞垮了beam:
Read more…

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