[Erlang_Question14]怎样模拟节点互连后的各种失败情况?

情景:

当节点群互连时,会通过心跳包检查所连接节点是不是连接正常,这个心跳时间默认为60s,可以通过

net_kernel:set_net_ticktime(600).

来重设这个时间值,怎么测试?

每次我把其中一个节点kill掉后,与之想连的节点就会立即收到nodedown消息,根本无法测试这个ticktime是不是生效。

原因:

在Erl Doc里面关于节点互连时有一个关于节点间心跳检查的片段:

http://www.erlang.org/doc/man/kernel_app.html

net_ticktime = TickTime

Specifies the net_kernel tick time. TickTime is given in seconds. Once every TickTime/4 second, all connected nodes are ticked (if anything else has been written to a node) and if nothing has been received from another node within the last four (4) tick times that node is considered to be down. This ensures that nodes which are not responding, for reasons such as hardware errors, are considered to be down.

The time T, in which a node that is not responding is detected, is calculated as: MinT < T < MaxT where:

         MinT = TickTime - TickTime / 4
         MaxT = TickTime + TickTime / 4

TickTime is by default 60 (seconds). Thus, 45 < T < 75 seconds.

Note: All communicating nodes should have the same TickTime value specified.

Note: Normally, a terminating node is detected immediately.

从文档中可以看出,节点会在每TickTime/4 秒检查一下连接的节点是不是正常,如果连续4次没有收到(TickTime时间内)没有收到心跳消息,就会认为这个节点挂了,

可是如果节点是被终结掉(terminating node),其它节点会马上收到down通知.

为了测试这个心跳时间,必须要对Erlang节点互连的基本epmd和net_kernel的工作原理有所了解【Google真是万能!】。



Erlang节点使用TCP连接通讯,当开启一个新节点,它会随机选择一个端口(大约在52300左右),在EPMD(Erlang Port Mapper Daemo)注册,EPMD默认使用4369端口对外连接,

结论:

1. epmd就是Erlang里的port mapper,每台计算机上启动一个该进程,它记录/交换集群上的每个进程的端口信息:

2. 每个节点起动时会向本地的EPMD注册一个可用端口,用于收信息;

3. 当A节点尝试与B节点建立双向通信时,首先向本地的EPMD进程查询B节点信息(第一次连接当然找不到啦);

4. 找不到就会向B节点的EPMD查询B节点上可收消息的PortB,同时把A节点上的PortA携带给B节点;

5. A节点随机一个可用端口PortA1---->PortB; B节点随机一个PortB1----->PortA;

6.双向通信连接建立成功。

The following figure shows three nodes N1, N2, and N3 with their incoming connection TCP port 52383, 52236, 52275. Communication is ongoing between N1 and N2, N1 and N2 where the nodes have picked random ports R1, R2, R3, and R4.

那我们来看看3个节点相连是什么情况?

节点N1,N2,N3,分别注册52383, 52236, 52275用来建立接收的TCP连接,R1,R2,R3,R4就是随机生成的端口用来发送的TCP连接。

Erlang有很多方法来检测节点是不是可连接,比如我们上面说的节点启动时自动设置的心跳Net-Ticks(双向就用Links,单向监测就用Monitors),
1> net_kernel:monitor_nodes(true, [{node_type, visible}, nodedown_reason]).
可能失败的原因:
%%connection_setup_failed
%%no_network
%%net_kernel_terminated
%%shutdown
%%connection_closed
%%disconnect
%%net_tick_timeout
%%send_net_tick_fail
%%edget_status_failed
接下来的好戏:怎么制造出这些错误?

1 没有效果的方式:

 1.1. 改变节点cookie.
     众所周知:2个节点要连接在一起,必须要知道对方的cookie,那么,我们在连接已建立后,手动把cookie改一下:
1> erlang:set_cookie(node(), zhongwencool).
   结果非常有趣:居然对运行中已连接的节点没有任何影响.
1.2.阻塞或杀死EPMD进程.
   结果和1一样,对已连接的节点没有任何影响,这个是因为EPMD只用于连接建立之前,建立完成后就没EPMD的事啦.

2. 破坏性的方式:

2.1 使VM Crash掉:

直接在操作系统里面用

$ kill -9 $PID
或者使用:
1> os:cmd("kill -9 " ++ os:getpid()).
结果是对方节点马上收到了
{connection_closed}

2.2 正常kill或停止 VM:

如果你是在Erlang shell里面,你可以使用C-c C-c来结束VM.

也可以在调用:

1> erlang:halt().
或者更常见的:
1> init:stop().
但是两者了结果都是:马上收到:
{connection_closed}

3. 临时性的方式:

3.1 可以在终端使用C-z,或:

1> os:cmd("kill -STOP " ++ os:getpid()).

使VM机器Halt住。

终于我们在60s后收到了:
{net_tick_timeout}

终于看到了一个我们想要的结果,但是好像这个节点也无法再继续用了……

3.2 把 net_kernel进程给kill掉:

1> timer:kill_after(0, whereis(net_kernel)).
结果还是马上收到:
{connection_closed}

4. 阻塞端口:

使用防火墙规则阻塞端口:

$ erl -name ‘[email protected]‘
$ erl -name ‘[email protected]‘

这下上面的2个节点都使用不用的network interface

$ sudo iptables -I INPUT --destination 127.0.1.1 -j DROP
$ sudo iptables -I INPUT --source 127.0.1.1 -j DROP

$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 127.0.1.1/32 -j DROP
-A INPUT -d 127.0.1.1/32 -j DROP

:
:

$ sudo iptables -F

结果还是60s后收到一个:

{net_tick_timeout}

最终结果:

如果想测试nodedown消息,最好使用防火墙设置端口来模拟。

参考阅读:

1. http://blog.yufeng.info/archives/2779

2. http://www.cnblogs.com/me-sa/p/erlang-epmd.html

心中一万匹马在奔腾啊……………………………….

[Erlang_Question14]怎样模拟节点互连后的各种失败情况?,布布扣,bubuko.com

时间: 2024-10-24 06:41:00

[Erlang_Question14]怎样模拟节点互连后的各种失败情况?的相关文章

探索javascript----获得节点计算后样式

节点计算后样式是一个属性与属性值的值对对象: IE:    node.currentStyle; 非IE: window.getComputedStyle(node,null); 兼容方式: function getCurrentStyle(node){ var style=[]; node.currentStyle?style=node.currentStyle:window.getComputedStyle(node,null); return style; }

rac 11g_第二个节点重启后无法启动实例:磁盘组dismount问题

原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/41480075 rac第二个节点重启后无法启动实例:磁盘组dismount问题 实验案例: 实验环境:CentOS 6.4.Oracle 11.2.0.1 现象重演:1. 重启第二节点服务器2. 手工启动第二节点实例,报错[[email protected] ~]# s

rac_第二个节点重启后无法启动实例:磁盘组dismount问题

原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/41480075 rac第二个节点重启后无法启动实例:磁盘组dismount问题 实验案例: 实验环境:CentOS 6.4.Oracle 11.2.0.1 现象重演: 1. 重启第二节点服务器 2. 手工启动第二节点实例,报错 [[email protected] ~]

Consul坑坑一人行之从入门到放弃,记Consul的重复注册、节点失效后无健康检查等坑。。。求解

环境: dotnet core 2.1 CentOS 7 由于听到Eureka2.X最近好像要凉的消息 所以昨天在尝试使用Consul替代Eureka来实现服务发现等功能 Consul使用HttpAPI注册服务 但是!!!! 发现几个非常恶心的地方,在这里分享出来,希望可以得到园子里各位大牛的指导. 坑1:同一个ServiceID 可以在多个节点上重复注册! 情况是这样,我对Consul进行了好多折腾, 首先,为了避免本地Consul挂了导致服务无法注册, 所以我对Consul的HTTP端口(8

注解方式定义的spring component打jar后,扫描失败的可能原因

情况是这样的:web工程采用了ssh框架,dao和service都是通过annotation方式注入的,工程运行正常.后来把service和dao打成jar放在工程的lib目录下,问题来了,配置没改动,结果就是不能自动注入dao和service.但是如果把dao和service在spring配置文件中通过xml文件配置,这些component能找到. 搜索了一把,发现这个问题比较常见,大部分帖子说的是在打jar包的时候add entity directory,仔细看了下,我的jar包是通过mav

路由器配置Stub后 邻接关系建立失败

路由器配置Stub后 邻接关系建立失败 如图11.1所示,BENET总公司和分公司通过E1专线连接.R1.R2为总公司路由器,R3为分公司路由器.网络规划如下: n R1和R2的互联地址为:10.0.0.0/30:R2和R3的互联地址为:20.0.0.0/30: n 使用路由器的Loopback0接口地址作为Route-id,R1的Loopback0:1.1.1.1/32,R2的Loopback0:2.2.2.2/32,R3的Loopback0:3.3.3.3/32. 图11.1 配置Sutb后

【BUG】插入或者更新超过限制后写入数据库失败

Error Code: 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Usage: mysqldump [OPTIONS] database [tables]   OR mysqldump [OPTIONS] --databa' at line 1 报错: Er

文件存到aws的S3后, 调用getimagesize失败分析

一.问题 将图片在windows下用图片查看器修改后,上传到s3中,调用getimagesize获取图片信息总是返回false,其它图片正常: 代码如下: $fileName = 's3://sdk1/20150317/174290_1_1428371.JPG'; $size = getimagesize($fileName);var_dump($size); 以上代码总是输出false. 即部分图片调用成功,部分调用失败: 图片上传后,可以对上传的临时文件调用getimagesize获取图片信

windows+ubuntu双系统,重装windows后启动ubuntu失败

双系统,重装windows后启动linux失败修复方法 一.背景 这几天将windows10 32位升级到64位后(其实是重装,增量升级应该不能实现,如果有方法请留言),使用easybcd添加linux启动项后选择linux启动项,进去就是黑屏,只有一个光标在闪,没有任何文字,第一次碰到这个情况,我慌了,虽然折腾双系统期间经历过各种蛋疼的问题,但是linux始终是能进去的,至少能进个grub rescue模式.蛋疼的修复尝试开始了. 二.正确的方法: 双系统重装windows后,如何找回linu