Home > Erlang探索, 源码分析 > Erlang集群全联通问题及解决方案

Erlang集群全联通问题及解决方案

May 2nd, 2013

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

本文链接地址: Erlang集群全联通问题及解决方案

Erlang的集群默认情况下是全联通的,也就是当一个节点加入集群的时候,介绍人会推荐集群里面所有的节点主动来和新加入的节点建立联系,
效果如下图:

erlang_connect

具体点讲那就是net_kernel模块负责节点间的通道的建立、检查、断开并提供monitor_node语义。
摘抄 http://www.erlang.org/doc/man/erlang.html 如下:

monitor_node(Node, Flag) -> true
Types:
Node = node()
Flag = boolean()
Monitors the status of the node Node. If Flag is true, monitoring is turned on; if Flag is false, monitoring is turned off.

Making several calls to monitor_node(Node, true) for the same Node is not an error; it results in as many, completely independent, monitorings.

If Node fails or does not exist, the message {nodedown, Node} is delivered to the process. If a process has made two calls to monitor_node(Node, true) and Node terminates, two nodedown messages are delivered to the process. If there is no connection to Node, there will be an attempt to create one. If this fails, a nodedown message is delivered.

Nodes connected through hidden connections can be monitored as any other node.

Failure: badargif the local node is not alive.

其他模块如global, pg2, mnesia都利用这个monitor_node提供的语义来实现更上层的逻辑。那么上面提到的引荐机制正是global模块实现的,它的目的是提供集群层面的名称和进程的映射关系,所以它需要全联通。

学过中学数学的同学都知道系统总的通道的数目是N*(N-1)/2, 随着N的增长,这个数目会急速上升,见下图。

hidden_visible

这个对集群的规模有致命的破坏作用。 这么多链接需要耗用很多资源,更坏的是,erlang为了检测节点的存活,需要定期发心跳包来检查,一分钟一个tick, 这会造成大量的网络风暴。

那么我们如何来避免这个事情呢?

很简单,避免全联通,摘抄 http://www.erlang.org/doc/man/erl.html 如下:

hidden
Starts the Erlang runtime system as a hidden node, if it is run as a distributed node. Hidden nodes always establish hidden connections to all other nodes except for nodes in the same global group. Hidden connections are not published on either of the connected nodes, i.e. neither of the connected nodes are part of the result from nodes/0 on the other node. See also hidden global groups, global_group(3).

哈哈,一个参数就解决这个问题了。

但是且慢,这个参数的行为需要注意下。 hidden是or语义,也就是说当参与方只要有一个是hidden, 那么global模块就不会介绍别人来认识新加入的节点。 只要2个都不是hidden, 才会有正常的社交。

leofs 摘抄一段配置:

## set up the node with the -hidden flag
-hidden

社区已经开始注意,并回避这个问题了,你呢?

小结:有些问题很小,但是影响很坏!

祝玩得开心!

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

  1. zhaofeng
    May 14th, 2013 at 19:23 | #1

    我觉得没所谓,因为对于单个节点来说,连接数增长是可以接受的。

    Yu Feng Reply:

    单单只有连接的问题?global最名称同步什么的要你的命。

  2. piboyeliu
    May 30th, 2013 at 17:52 | #2

    我使用了 -connect_all false 但还是 不能使用 global 模块, 有什么好方法取代global 模块?

    Yu Feng Reply:

    connect_all faslse后global不能用了,建议用-hidden

    piboyeliu Reply:

    hidden 后也不能 使用 global, 只能通过 rpc:call(‘node@host’, global, whereis_name, [abc]). 才可以得到。

  3. piboyeliu
    May 30th, 2013 at 18:08 | #3

    global 有没有替代品?

  4. redink
    June 5th, 2013 at 18:26 | #4

    请教下,如果在节点启动时,register一个global group?
    我做了一些尝试,在sys.config配置文件中,加入“{global_groups, [{test, [‘my@127.0.0.1’]}]}”,节点可以正常启动,但是在启动之后,使用global_group:info(),group name 为空。
    谢谢。

  5. redink
    June 5th, 2013 at 18:30 | #5

    请教下,如何register一个global group?
    我做了一些尝试,在sys.congfig中,加入“{global_groups, [test, [‘my@127.0.0.1’]]}”,节点可以正常启动,但是在启动之后,使用global_group:info(), group的name 为空。
    谢谢。

    Yu Feng Reply:

    最好不要用global模块,这个依赖于集群全联通,集群大了,或者跨机房网络情况比较复杂,容易出问题。建议用monitor_node原语自己去做这样的东西。

  6. Xu Yifeng
    March 7th, 2014 at 14:29 | #6

    global模块还有一个缺陷,就是当一个新的名字出现的时候,我无法得到通知,只有调用registered_names()不停地轮询。在一个集群环境里,我等待一个提供服务进程出现,这个global不能做到实时通知,很遗憾。

Comments are closed.