erlang集群是依靠epmd维护的,epmd是erlang集群节点间端口映射的守护进程,负责维护集群内的节点连接,提供节点名称到IP地址及端口的解析服务。
epmd 自定义端口号
epmd端口配置
默认情况下,epmd绑定在4369端口。但是,端口固定的话,容易遭受攻击,可能导致新节点的认证失败而无法启动,或无法加入集群。或者要在一台机器上部署不同的erlang集群,希望不会互相干扰。
```shell
$ epmd -daemon -port 5000
$ epmd -d -port 5000 #如果想用调试模式启动 epmd
```
另外,epmd通常伴随着erlang节点启动时自动启动,无须手动处理,所以,这里也可以通过修改erl启动参数以达到自动调整epmd端口。
```shell
$ erl -name hello@127.0.0.1 -epmd "epmd -port 5000 -daemon"
```
节点启动配置
当epmd端口改变时,erlang节点需要显式指定epmd端口信息。
windwos下启动方式:
1、设置环境变量ERL_EPMD_PORT
```bat
C:\>set ERL_EPMD_PORT=5000
C:\>erl -name hello@127.0.0.1
```
注意了, 以上命令端口号(这里是5000)前后不能留有空格。
2、设置erlang启动参数
```shell
$ erl -name hello@127.0.0.1 -epmd_port 5000
```
linux下启动方式:
```shell
1、设置环境变量ERL_EPMD_PORT
ERL_EPMD_PORT=5000 erl -name hello@127.0.0.1
2、设置erlang启动参数
erl -name hello@127.0.0.1 -epmd_port 5000
```
这两种方式是等价的,erlang启动时会做以下处理:
```c
// erlexec.c
static void add_epmd_port(void)
{
char* port = get_env("ERL_EPMD_PORT");
if (port != NULL) {
add_args("-epmd_port", port, NULL);
}
}
//其中,epmd_port在erl_epmd模块被用到,完成epmd连接。
%% 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.
%%
%% Epmd socket
%%
open() -> open({127,0,0,1}). % The localhost IP address.
open({A,B,C,D}=EpmdAddr) when ?ip(A,B,C,D) ->
gen_tcp:connect(EpmdAddr, get_epmd_port(), [inet]);
%% 注册节点名称和端口
do_register_node(NodeName, TcpPort) ->
case open() of
{ok, Socket} ->
Name = to_string(NodeName),
Extra = "",
Elen = length(Extra),
Len = 1+2+1+1+2+2+2+length(Name)+2+Elen,
gen_tcp:send(Socket, [?int16(Len), ?EPMD_ALIVE2_REQ,
?int16(TcpPort),
$M,
0,
?int16(epmd_dist_high()),
?int16(epmd_dist_low()),
?int16(length(Name)),
Name,
?int16(Elen),
Extra]),
wait_for_reg_reply(Socket, []);
Error ->
Error
end.
```
限制指定IP的节点加入集群
```shell
epmd -port 5000 -address 127.0.0.1 -daemon #这样,如果节点名字不是 xxx@127.0.0.1,将无法启动,或加入集群。
```
如何杀掉epmd进程
epmd独立于erlang节点,在所有节点关闭后还会继续存在,有时候可能需要杀掉epmd进程。
```shell
epmd -kill
```
设定节点连接监听端口
节点启动时,会启动一个tcp socket,用于监听并处理其他节点的连接请求,但是,这个端口号是随机的,有时候我们需要定义防火墙规则,就要对端口范围做一些限定。
通过修改erlang启动参数即可设定,方法如下:
erl -name hello@127.0.0.1 -kernel inet_dist_listen_min 9100 -kernel inet_dist_listen_max 9200
看下这两个参数是怎么被使用的?
```erlang
%% inet_tcp_dist.erl
listen(Name) ->
%% 启动本地节点监听socket
case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of
{ok, Socket} ->
TcpAddress = get_tcp_address(Socket),
{_,Port} = TcpAddress#net_address.address,
%% 注册节点名称和端口
case erl_epmd:register_node(Name, Port) of
{ok, Creation} ->
{ok, {Socket, TcpAddress, Creation}};
Error ->
Error
end;
Error ->
Error
end.
do_listen(Options0) ->
%% 获取端口范围
{First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
{ok,N} when is_integer(N) ->
case application:get_env(kernel,
inet_dist_listen_max) of
{ok,M} when is_integer(M) ->
{N,M};
_ ->
{N,N}
end;
_ ->
{0,0}
end,
%% 获取绑定IP地址
Options = case application:get_env(kernel, inet_dist_use_interface) of
{ok, Ip} ->
[{ip, Ip} | Options0];
_ ->
Options0
end,
do_listen(First, Last, [{backlog,128}|Options]).
do_listen(First,Last,_) when First > Last ->
{error,eaddrinuse};
do_listen(First,Last,Options) ->
%% 尝试监听socket
case inet_tcp:listen(First, Options) of
{error, eaddrinuse} ->
do_listen(First+1,Last,Options);
Other ->
Other
end.
```
- 1.学习
- 1.1安装与运行环境
- 1.2编辑器、集成开发环境与其它工具
- 1.3代码编译运行
- 2.基础
- 2.1 Erlang终端
- 2.2 基础语法
- 2.2.1 异常处理
- 2.3 数据类型
- 2.4 操作符
- 2.5 模块属性
- 3.库函数
- 3.1 常用模块
- 3.2 OTP模块
- 3.2.1 函数
- 3.2.2 receive
- 3.2.3 .app.src文件
- 3.2.4 _app.erl
- 3.2.5 _sup.erl
- 3.2.6 gen_server
- 3.2.7 gen_fsm
- 3.3 erts
- 3.3.1 init
- 3.3.2 BIF
- 3.3.3 NIF
- 3.4 kernel
- 3.4.1 code_server
- 3.4.2 inet
- 3.4.3 net_kernel
- 3.4.4 net_adm
- 3.4.5 error_logger
- 3.4.6 global
- 3.4.7 application
- 3.5 stdlib
- 3.5.2 array
- 3.5.4 base64
- 3.5.5 binary
- 3.5.6 c
- 3.5.8 calendar
- 3.5.9 code
- 3.5.11 dict
- 3.5.12 erl_
- 3.5.13 file
- 3.5.14 filelib
- 3.5.15 gb_trees
- 3.5.16 gb_sets
- 3.5.17 gen_tcp
- 3.5.18 gen_server
- 3.5.19 httpc
- 3.5.20 init_parse
- 3.5.21 init
- 3.5.22 inet
- 3.5.23 io
- 3.5.24 lists
- 3.5.25 maps
- 3.5.26 os
- 3.5.27 ordsets
- 3.5.28 proplists
- 3.5.29 queue
- 3.5.30 qlc
- 3.5.31 re
- 3.5.32 random
- 3.5.33 rfc4627-json
- 3.5.34 string
- 3.5.35 ssh
- 3.5.36 soft
- 3.5.37 sets
- 3.5.38 supervisor
- 3.5.39 tuple
- 3.5.40 timer
- 3.5.41 unicode
- 3.5.42 cpu
- 3.5.43 math
- 3.5.44 zip
- 3.5.45 shell
- 3.6 SASL
- 3.7 asn1
- 3.8 compiler
- 3.9 tools
- 3.10 OS_Mon
- 3.11 crypto
- 3.12 Port
- 4.工具
- 4.1 Erlang预处理器
- 4.2 Erlang节点
- 4.3 Erlang多节点
- 4.3.1主从节点
- 4.4 Epmd
- 4.5 断点工具
- 4.6 dialyzer
- 4.7 dbg-debug 模块
- 4.7.1 dbg
- 4.8 Erlang跟踪工具
- 4.9 etop
- 4.10 profiling
- 4.10.1 fprof
- 4.10.2 eprof
- 4.10.3 cprof
- 5.进阶
- 5.1 TCP粘包、大小端
- 5.2 rebar发布系统
- 5.3 ErlangVM 心跳
- 5.4 Erlang GC
- 5.5 Erlang Time
- 5.6 Erlang 启动
- 5.6.1 SASL配置
- 5.7 Erlang系统限制
- 6.项目
- 6.1 the_seed
- 6.2 network
- 6.3 parse_tool
- 6.4 cache
- 7.项目研究
- 7.1 Mnesia
- 7.1.1 Mnesia模式
- 7.1.2 Mnesia操作
- 7.1.3 Mnesia增删改查
- 7.1.4 Mnesia过载分析
- 7.1.5 Mnesia高级特性
- 7.1.6 分布式
- 7.1.7 Mnesia表分片
- 7.1.8 Mnesia锁
- 7.1.9 dets
- 7.1.10 ets
- 7.2 Ejabberd
- 7.2.1 mod_echo.erl
- 7.2.2 hooks for module developers
- 7.2.3 Events list
- 7.3 cowboy
- 7.4 rebar
- 7.4.1 rebar Wiki
- 7.4.2 rebar.config.script
- 7.5 RIAK CS
- 7.6 Leofs
- 7.6.1 简介
- 8.资料整理
- 8.1 资料
- 8.1.1 Erlang的调度原理
- 8.1.2 虚拟机代码执行原理
- 8.1.3 SMP
- 8.2 杂记
- 8.2.1 设计