net_sup是kernel中繼dist_ac(distribution applicationcontroller)后啟動的監(jiān)控者(supervisor),除了前文提到的net_kernel(提供節(jié)點互聯(lián))之外,還有erl_epmd(提供epmd名字注冊)和auth(提供cookie管理)。
拓?fù)鋱D如下:
| - erl_epmd
net_sup --- | - auth
| - net_kernel
本文主要說的是 erl_epmd和auth。
1. epmd(名字注冊)
與epmd相關(guān)的配置參數(shù)和環(huán)境變量:
| 名字 | 數(shù)據(jù)類型 | 備注 | |
|---|---|---|---|
start_epmd |
true / false | 在開啟節(jié)點時候是否開啟epmd,默認(rèn)true
|
|
epmd_module |
atom |
epmd模塊,默認(rèn)是erl_epmd
|
|
epmd_port |
int | 向指定端口注冊Node
|
|
ERL_EPMD_ADDRESS |
string |
epmd 監(jiān)聽地址 |
|
ERL_EPMD_PORT |
int |
epmd端口號,注意:同一個集群使用同一個端口號,默認(rèn)4369 |
1.1 如何設(shè)置epmd端口
$ epmd
$ export ERL_EPMD_PORT=Port
$ erlang node
$ erl -epmd_port Port -name ......
% erl_epmd.erl
get_epmd_port() ->
case init:get_argument(epmd_port) of
{ok, [[PortStr | _] | _]} when is_list(PortStr) ->
list_to_integer(PortStr);
error ->
?erlang_daemon_port
end.
環(huán)境變量ERL_EPMD_PORT 和vm參數(shù) epmd_port配合起來使用,可以在同一個機(jī)器上部署多個集群
# 演示了同一臺機(jī)器部署2個集群
$ 集群一,epmd端口號4000
$ export ERL_EPMD_PORT 4000
$ erl -epmd_port 4000 -name abc@127.0.0.1
(abc@127.0.0.1)1> erl_epmd:names().
{ok,[{"abc",9591}]}
$ 集群二,epmd端口號5000
$ export ERL_EPMD_PORT 5000
$ erl -epmd_port 5000 -name abc@127.0.0.1
(abc@127.0.0.1)1> erl_epmd:names().
{ok,[{"abc",21309}]}
1.2 注冊名稱過程
% erl_epmd.erl
% 由 net_kernel 發(fā)起
handle_call({register, Name, PortNo, Family}, _From, State) ->
case State#state.socket of
P when P < 0 ->
% 只有當(dāng)沒有注冊的時候,才允許注冊,換句話說,一個Node只會調(diào)用一次
case do_register_node(Name, PortNo, Family) of
{alive, Socket, Creation} ->
S = State#state{socket = Socket,port_no = PortNo,name = Name},
{reply, {ok, Creation}, S};
Error ->
{reply, Error, State}
end;
_ ->
{reply, {error, already_registered}, State}
end;
do_register_node(NodeName, TcpPort, Family) ->
Localhost = open(TcpPort) % 連本地的epmd
case Localhost of
{ok, Socket} ->
% Socket 正確連上epmd
Name = to_string(NodeName),
Packet = ...
case gen_tcp:send(Socket, Packet) of
ok ->
% 發(fā)送注冊包,等待回包
wait_for_reg_reply(Socket, []);
Error ->
close(Socket),
Error
end;
Error ->
Error
end.
wait_for_reg_reply(Socket, SoFar) ->
receive
{tcp, Socket, Data0} ->
...
{tcp_closed, Socket} ->
{error, epmd_close}
after 10000 ->
% 默認(rèn)10秒超時,并且不能修改。
gen_tcp:close(Socket),
{error, no_reg_reply_from_epmd}
end.
注意點:
- 每個節(jié)點只能注冊一次
- 注冊結(jié)束之后保存注冊連接
(Socket)作為后續(xù)與epmd的交互媒介
2. auth(管理cookie)
auth 功能比較單一,就是保存本地的cookie, 相關(guān)的vm參數(shù)如下:
| 名字 | 數(shù)據(jù)類型 | 備注 |
|---|---|---|
nocookie |
- | 主動不設(shè)置cookie
|
setcookie |
string | 設(shè)置節(jié)點cookie
|
設(shè)置cookie流程
init_cookie() ->
case init:get_argument(nocookie) of
error ->
case init:get_argument(setcookie) of
{ok, [[C0]]} ->
C = list_to_atom(C0),
#state{our_cookie = C, ...};
_ ->
% 從$HOME/.erlang.cookie讀取cookie
case read_cookie() of
{error, Error} ->
error_logger:error_msg(Error, []),
%% Is this really this serious?
erlang:error(Error);
{ok, Co} ->
#state{our_cookie = list_to_atom(Co),
other_cookies = ets:new(
cookies,
[?COOKIE_ETS_PROTECTION])}
end
end;
_Other ->
#state{our_cookie = nocookie,other_cookies = ...}
end.
- 如果
vm設(shè)置nocookie參數(shù),直接忽略cookie,否則第二步 - 如果
vm設(shè)置setcookie參數(shù),則保存該cookie, 否則第三步 - 從
$HOME/.erlang.cookie讀取cookie
如上如果要設(shè)置一個集群的cookie,有2種方式:
- 顯示使用
setcookie參數(shù)(erl -setcookie Cookie),缺點是cookie容易被同一機(jī)器上別的用戶發(fā)現(xiàn) - 使用
$HOME/.erlang.cookie文件,保密性強(qiáng)。
3.總結(jié)
erl_epmd,auth是節(jié)點互聯(lián)的基礎(chǔ)。通過對機(jī)制的深入理解,讓我們對集群的配置有更多控制權(quán)。