原创作者: mryufeng   阅读:3132次   评论:0条   更新时间:2011-06-01    
Erlang系统在我看来有3个特性 1. 分布 2. 多核心支持 3. fp。 这这3个特性中分布我认为是erlang最强大的,从第一个版本就支持到现在,相对非常成熟,而多核心支持是这几年才加进去的。

erlang的分布系统做到了2点 1.节点的位置无关性。 2. 对用户分布式透明的。具体体现就是node是靠名字识别的, 进程也是靠pid来识别。

分布系统就要实现节点间通讯,erlang也不列外。 erlang的节点通讯介质是可以替换的 目前官方版本支持tcp, ssl通讯。

可以用 -proto_dist xxxx来选择通道。 目前支持inet_ssl inet_tcp 用户很容易模仿这这2个通讯协议,写个自己的传输通道,就是要求这个通道是可靠的,不能丢失信息。

这几个实现防火墙友好:
{inet_dist_use_interface, ip_address()}
    If the host of an Erlang node has several network interfaces, this parameter specifies which one to listen on. See inet(3) for the type definition of ip_address().
{inet_dist_listen_min, First}
    See below.
{inet_dist_listen_max, Last}
    Define the First..Last port range for the listener socket of a distributed Erlang node.

erlang的内核里面和分布相关的erl模块主要有net_kernel inet_tcp_dist inet_ssl_dist inet_tcp dist_util erlang(trap send/link等语义)。

当用户运行erl -sname xxxxx启动erlang系统的时候 kernel模块就会启动net_kernel和epmd模块。

epmd的作用是提供一个node名称到监听地址端口的映射。epmd值守在知名端口4369上.

net_kernel会启动proto_dist比如说inet_tcp_dist监听端口,同时把端口报到epmd. 这时候erts就准备好了节点通讯。

这时候另外一个节点要和我们通讯的时候,首先要连接,流程大概是这样的:
1. 根据节点名找到节点地址。
2. 查询节点的4369端口,也就是epmd,向它要节点对应的inet_tcp_dist监听的端口。
3. 发起连接, 握手,cookie认证,如果未授权就失败。
4. 记录节点名称和响应的信息。

所以节点要正常通讯要考虑到firewall和nat的影响,以及cookie正常。

具体的可以看另外一篇文章:http://mryufeng.iteye.com/blog/120666

要给节点发消息首先要保证我们和节点联系过,也就是说我们的节点表里可以查到这个节点。

net_kernel要节点的可用性, 会定期发tick消息坚持节点的可达。对端节点也会主动发送nodeup,nodeup等消息,协助维护。

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.

节点有2种类型可见的和不可见的。erlang节点是可见的, c_interface写的节点不可见,因为c模块提供的节点能力有限。

erlang进程见通讯可以通过 1. pid  2.进程名称 来进行。 erlang系统很大的威力就在用elang实现了名称和pid的全局性维护。也就是说erlang做了个相当复杂的模块来解决名称失效 重复 查询功能。正常情况下名称是全局行的,也就是erlang的节点是全联通的,可以通过来调整。
auto_connect = Value
    Specifies when no will be automatically connected. If this parameter is not specified, a node is always automatically connected, e.g when a message is to be sent to that node. Value is one of:

    never
        Connections are never automatically connected, they must be explicitly connected. See net_kernel(3).
    once
        Connections will be established automatically, but only once per node. If a node goes down, it must thereafter be explicitly connected. See net_kernel(3).

erlang实现透明进程通信的关键点在于pid的变换:

pid {X,Y,Z} 在发到网络的时候发出去的格式是{sysname, Y, Z}
因为节点之前互相联系过 所以互相知道对方的sysname, 而且sysname在dist_entry里保存,当对端收到dec_pid的时候,用peer sysname 的查到在自己dist_entry里面的索引,然后用这个index 来构造新的pid,即 {index, Y, Z}。

erlang给一个pid发消息的时候, 首先检查Pid是本地的还是外部的, 如果是外部的,则进行上面的变换,然后通过inet_tcp_dist模块,沿着inet_tcp, inet_drv这条线发送出去。

这条消息到达对端的时候 inet_drv首先受到这条消息, 照理说应该提交给inet_tcp, 然后再到inet_tcp_dist, net_kernel来处理.但是erlang为了效率的考虑做了个折中。在inet_drv里面driver_output*中检查消息的类型 如果是dist来的消息,就给erts_net_message来处理。

这个erts_net_message处理以下几个重要消息:

#define DOP_SEND 2
#define DOP_EXIT 3
#define DOP_UNLINK 4
#define DOP_NODE_LINK 5
#define DOP_REG_SEND 6
#define DOP_GROUP_LEADER 7
#define DOP_EXIT2 8
#define DOP_SEND_TT 12
#define DOP_EXIT_TT 13
#define DOP_REG_SEND_TT 16
#define DOP_EXIT2_TT 18
#define DOP_MONITOR_P 19
#define DOP_DEMONITOR_P 20
#define DOP_MONITOR_P_EXIT 21

如果是DOP_SEND的话,就把message放到变换好的进程的队列中去。

这个核心的功能,由beam的c模块(dist.c, erl_node_tables.c, io.c )和net_kernel模块一起实现。然后在这底层的原语上进一步实现了如rpc 这样的上层模块,进一步方便了用户.

用erlsnoop http://mryufeng.iteye.com/blog/167695 可以观察到上面的通讯,有助于理解系统的运作。
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

Global site tag (gtag.js) - Google Analytics