Outline
笔记系列
Erlang环境和顺序编程
Erlang并发编程
Erlang分布式编程
Yaws
Erlang/OTP
日期 变更说明
2014-11-23 A Outline
A 1.1-1.2
2014-12-08 A 1.3
Agenda
0范围
节点和通信
基本分布式编程模块
empd进程
套接字编程
1 Erlang节点和通信
1.1节点
一个Erlang节点是已命名的(named)的正在运行的Erlang运行时系统(erts)。
多个节点可以运行在一台机器上,也可以运行在不同的机器上。之前的顺序编程、并发编程中示例实际上是在一个Erlang节点上运行的。
存活节点/可命名的节点:如果一个节点可以与其他节点通信。任何存活的节点都需要命名,命名有两种方式:
(1)短名字 erl -sname <sname>
sname在局域网中命名一个主机,已[email protected]给出,例:[email protected]
(2)长名字 erl -name <name>
name给出完整的主机IP地址,可以是[email protected],或[email protected](可DNS解析的主机名)。
长名字节点只能与长名字节点通信,短名字节点只能与短名字节点通信。
节点启动和信息
erl -[s]name <nodeName>
命名节点方式启动
net_kernel:start([‘[email protected]’]).
启动节点
net_kernel:stop().
停止当前节点
node().
查看当前节点
elrang:is_alive().
当前节点是否存活
1.2 节点通信
节点连通性测试
net_adm:ping(‘[email protected]’).
pang:不连通,pong:连通。
Cookie
每个节点在任意时刻只有一个cookie,共享同一值的节点可以通信。
启动时设置cookie
erl -sname foo -setcookie <cookieValue>
运行时设置cookie
erlang:set_cookie(node(), <cookieValue>).
局限性
分布式节点通过cookie与另一远程节点建立连接后,远程节点的拥有者获得本地节点运行者用户相同的权限。远程节点能够执行spawn(YourNode, os, cmd, [“rm -rf *”]).是任何人都不想看到的。故,cookie安全通信在封闭式系统中是足够的,但在开放式系统中需要融入其他的安全通信机制,可以考虑安全套接字等。
连接性建立和配置
只要分布式Erlang节点共享相同的cookie值,它们之间就可以通信。
Erlang运行时系统(erts)在第一次引用一个节点时,自动建立连接。自动建立连接可以是通过调用net_adm:ping/1或者发送一个消息到该节点注册的进程上来完成。
连接在一起的节点,信息是共享的,具有可传递性。
net_kernel进程
每个节点的net_kernel进程负责协调分布式Erlang节点之间的操作,例如:spawn/4会被net_kernel进程转换为消息发送到远程节点的net_kernel进程上、net_kernel进程处理cookie认证。很重要的一点:用户可以修改net_kernel进程以获得期望的行为。
自动建立的可传递的连接行为的覆盖方法有:使用net_kernel模块中的函数手动的控制连接、运行erl -connect_all false拒绝节点全局的相互连接。
隐藏节点
希望覆盖默认配置下所有节点互相连接行为,只在必要时建立与其他节点的连接的时候,可以考虑隐藏节点。
启动隐藏节点: erl -sname ‘nodeName’ -hidden。
手动建立节点连接:net_kernel:connect(NodeName).。
nodes/0不会返回隐藏节点,nodes(hidden)返回隐藏节点,nodes(connected)返回隐藏节点和非隐藏节点。
1.3 远程过程调用与本地调用的区别
?Sample: facserver/facclient[1]
facserver.erl
-module(facserver). %% API -export([start/0]). %%%=================================================================== %%% API %%%=================================================================== start() -> register(facserver, self()), facLoop(). %%%=================================================================== %%% Internal functions %%%=================================================================== facLoop() -> receive {Pid, N} -> Pid ! {ok, fac(N)} end, facLoop(). fac(0) -> 1; fac(1) -> 1; fac(N) -> N * fac(N-1).
facclient.erl
-module(facclient). %% API -export([remote_call/2]). %%%=================================================================== %%% API %%%=================================================================== remote_call(Message, Node) -> {facserver, Node} ! {self(), Message}, %?向远程节点远程发送消息节点 receive {ok, Result} -> Result end. %%%=================================================================== %%% Internal functions %%%===================================================================
运行示例
分布式系统是一个会因为另一个你甚至不知道其存在的计算机的错误,而导致你的计算机无法使用的系统。
—— Lesilie Lamport
远程过程调用与本地调用的本质区别在于:远程节点可能失效,无法调用期望的功能。故,需要在远程过程调用时添加一些“护卫”语句,以确保远程节点连接正常、远程节点失效时有机会优雅的继续处理。[1]中给出了三种常见的方法:超时(receive … after)、连接到远程节点进程(spawn_link/4)、监视远程节点进程(monitor_node(Node, Bool));有关细节可以参考Erlang随版本发布的文档。
2 基本分布式编程模块
2.1 erl模块
2.2 rpc模块
2.3 erlang模块
2.4 net_kernel模块
2.5 net_adm模块
3 empd进程
4 Erlang套接字编程
参考文献
[1] Cesarini F., Thompson S.著,慕尼黑Isar工作组 杨剑译.
Erlang编程指南.
北京: 机械工业出版社.2011.
[2] Armstrong J.著,牛化成 译.
Erlang程序设计(第2版).(Programming Erlang, Second Edition – Software for a Concurrent World).
北京: 人民邮电出版社.2014.