ERLANG远端节点奔溃导致发消息进程堵消息问题探源

问题描述:在生产环境中出现一例性能问题,A和B两个结点运行在两台服务器上,A与B互联,A不断向B发送消息。B结点所在机器发生宕机,导致A结点中发送消息的进程赌消息。

追踪过程:通过erlang:process_info(erlang:whereis(Pid))发现current_function一直是gen:do_call/4。messages消息堆积到数十万级别。

源码分析:在代码中向远端发送消息的调用函数为erlang:send(Pid,Msg),Pid是属于远端结点的接收进程。对该函数做一个简单的测试,测试环境如下,利用两台机器192.168.8.206和192.168.8.207,分别在其上运行erlang节点。在B上运行一个接收进程,测试在B机器进程、结点、机器三者挂掉的情况下send的效率问题。

服务端代码如下:

-module(recv).
-export([start/0]).
start() ->
    erlang:spawn(fun() -> erlang:register(recv,self()),loop() end).
loop() ->
    receive
        Data ->
        io:format("~p~n",[Data]),
	    loop()
    end.

测定结果:


进程、结点、机器存活情况


进程、结点、机器都存活


进程挂掉,结点和机器存活


进程、结点挂掉,机器存活


机器挂掉


1000次send消耗时间(ms)


8.333


7.6


1108


2866366.6

结论:机器挂掉本身对rpc:call的超时影响非常,具体原因和erlang的Trap机制有关系,每次send在机器不在线的情况下超时能接近3秒,可以确认该问题就是导致behavior_server堵消息的关键因素。

追踪源码:

Eterm erl_send(Process *p, Eterm to, Eterm msg)
{
    Sint result = do_send(p, to, msg, !0);
    if (result > 0) {
     ERTS_VBUMP_REDS(p, result);
     BIF_RET(msg);
    } else switch (result) {
    case 0:
     BIF_RET(msg);
     break;
    case SEND_TRAP:
     BIF_TRAP2(dsend2_trap, p, to, msg);
....

erlang:send/2函数最终会进入一个Trap的过程,Trap的作用可以参考余峰老大的博文http://mryufeng.iteye.com/blog/334744,为什么会进入Trap呢?在do_send的过程中调用到remote_send

static Sint remote_send(Process *p, DistEntry *dep,
   Eterm to, Eterm full_to, Eterm msg, int suspend)
{
    Sint res;
    int code;
    ErtsDSigData dsd;
    ASSERT(is_atom(to) || is_external_pid(to));
    code = erts_dsig_prepare(&dsd, dep, p, ERTS_DSP_NO_LOCK, !suspend);
    switch (code) {
      case ERTS_DSIG_PREP_NOT_ALIVE:
      case ERTS_DSIG_PREP_NOT_CONNECTED:
       res = SEND_TRAP;
  ....
ERTS_GLB_INLINE int
erts_dsig_prepare(ErtsDSigData *dsdp,
    DistEntry *dep,
    Process *proc,
    ErtsDSigPrepLock dspl,
    int no_suspend)
{
    int failure;
    if (!erts_is_alive)
     return ERTS_DSIG_PREP_NOT_ALIVE;
    if (!dep)
     return ERTS_DSIG_PREP_NOT_CONNECTED;
...

erlang的send操作用到的第二点,延迟操作,原因是在erlang:send的时候,结点之间的连接还未建立,这个send操作就不能继续,在下一次调度的时候首先执行结点连接操作,在结点建立连接之后再继续进行。这里Trap执行的函数就是erlang的dsend/2函数。

dsend(Pid, Msg) when is_pid(Pid) ->
    case net_kernel:connect(node(Pid)) of
     true -> erlang:send(Pid, Msg);
     false -> Msg
    end;

而其中net_kernel:connect/1实际上是调用了gen:do_call去建立TCP的连接,而一旦对方机器挂掉,TCP无法收到返回,于是要等待到超时才能退出,从而导致了net_kernel:connect/1本事是阻塞方式的。

解决方案:在远端机器可能存在不可靠的情况下使用erlang:send(Pid,Msg,[noconnect])代替erlang:send(Pid,Msg)。任何大量的对某些远端结点的send,call操作都要小心。如果机器会出现长时间宕机,都会可能造成本结点对对方结点的访问出现阻塞式的访问。

原因如下:noconnect参数

BIF_RETTYPE send_3(BIF_ALIST_3)
{...
    result = do_send(p, to, msg, suspend);
    if (result > 0) {
        ERTS_VBUMP_REDS(p, result);
     BIF_RET(am_ok);
    } else switch (result) {
    case 0:
     BIF_RET(am_ok);
     break;
    case SEND_TRAP:
   if (connect) {
       BIF_TRAP3(dsend3_trap, p, to, msg, opts);
   } else {
       BIF_RET(am_noconnect);
   }
....

在设置noconnect之后erlang发送到远端的消息就不需要等待对方连接建立而是直接在对方结点不存在的时候返回noconnect。

时间: 2024-12-25 20:20:38

ERLANG远端节点奔溃导致发消息进程堵消息问题探源的相关文章

undo回滚异常导致实例奔溃,无法正常open

接到地市反馈某一个数据库打不开了 1.登陆主机,查看数据库告警日志 最早数据库出现问题时的日志是在2014年6月7日 数据库在切换redo时异常关闭,之后数据库一直为开启使用 2.数据库在2014年6月8日 OPEN后,有recovery的进程报错 目前已经找不到这些文件,无法核实当时的异常信息源,接着往下看日志 3.数据库在2014年6月9日11:36:45时又异常关闭 4.同样的现象出现在2014年8月11日13:26:07,数据库异常关闭 5.数据库在2014年8月11日13:18:46再

见鬼?粉碎移动硬盘数据导致两年Windows8.1奔溃了!

一.这两天可谓闹心,吐槽一下: 本来最近很忙,不小心用了近两年的windows8.1系统奔溃了,很伤心,因为我粉碎了我移动硬盘的数据.前两天我的移动硬盘借给了公司同事,同事备份一些东西,之后过了几天,数据没用了,我就说删除了,但是删除了一部分,一些文件夹和文件始终删除不了,用电脑管家强制粉碎,确实删除了一部分,但是说一些东西要重启生效(当时自然而然重启了,没多想,现在挺郁闷的,理论不需要),然后,然后,就没有然后了,系统奔溃了.因为处理过程比较久,就不截图了. 二.大致流程: 2.1)移动硬盘数

从一个弱引用导致的奔溃 谈 weak assign strong的应用场景【iOS开发教程】

从一个弱引用导致的奔溃 谈 weak assign strong的应用场景 .h中的定义方法一: @property (nonatomic, assign) NSArray *dataSource; 定义方法二 @property (nonatomic, strong) NSArray *dataSource; .m中的实现方法 - (void)viewDidLoad { [super viewDidLoad]; if (YES) { NSArray *array = @[@"1",

iOS 解决上传100张图片内存奔溃问题

最近项目需求,从相册中提取100张图片,然后上传到服务器.前提是图片不能压缩.因为要将图片信息采集出来制作出3D模型.所以必须是高清图片. 先看下代码 [NetWorking uploadWithUrl:@"xxx" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { for (int i = 0; i<imageArr.count; i++) { UIImage

注意!神秘DNS漏洞现身 可致服务器奔溃

近日,互联网系统协会ISC发布紧急补丁修复隐藏在开源软件BIND中的严重安全漏洞.该安全漏洞编号为CVE-2015-5477,能够允许远程.未经认证的攻击者使用BIND发送特殊的命令,导致DNS服务器奔溃. 通过这个漏洞,一名黑客可以在一次行动中造成一片网络区域不正常.但是,当多名黑客同时行动的时候,就会导致足够多的DNS服务器出现奔溃,从而对于互联网带来非常严重的宕机和其他延伸影响. 那么这一漏洞跟普通用户有什么关系呢?域名服务器保存了网络中主机的域名和对应ip地址,并将域名转换为ip地址,也

iOS之UI--错误、奔溃、bug集合

1.循环利用cell的ID设置位置写错了.导致程序奔溃. 2.对于除数算法,可以直接算出结果的就写上结果,不要偷懒写式子让计算机自己算,更何况是除数,可能会算出无限小数的可能性.

Win10桌面奔溃怎么办?雨林木风Win10奔溃解决方法教程

Win10用户量一大,问题就如潮水般涌来.最严重的问题就是桌面奔溃,导致电脑无法正常使用.小编也找了很多方法,终于被小编成功突破了,现在来带给大家分享一下如何解决Win10系统桌面奔溃问题. 推荐雨林木风Win10装机版系统:http://www.ylmf10.com/win10zhuangji/ 造成这一系列原因是因为诺顿杀毒及其他杀毒软件.iCloud以及IDT Audio等软件原因,大家可以进入Win10安全模式来卸载这些软件解决Win10桌面奔溃. 进入安全模式的方法: 按Win+R打开

iOS-设置-app-位置,点击位置奔溃的原因

IOS8的定位需要有些变化.增加plist文件以及选择 使用期间 一直两种选择, requestWhenInUseAuthorization requestAlwaysAuthorization 按照配置进行调试后,功能都正常,无意中进入设置-APP-位置,点击位置,发生奔溃,非常意外 后面经过比较调试,是因为在plist文件里面加NSLocationWhenInUseUsageDescription的时候,类型选择是Boolean, 就是这个导致奔溃,后来改为string类型即可,后面的描述则

android app记录运行日志 捕获奔溃异常 ,存储日志到文件

app在运行过程中,为了后期的维护升级,记录日志是一个非常好的方法. 为了读取到app运行时的日志,一般的作法是单独开一个线程,在app运行的启动线程,然后app退出时停掉线程. 然而我们更好的方法是开启一个service,然后在里面做日志记录,代码如下: package com.hai.logcat; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.i