Erlang分布式

分布式erlang的核心概念是节点,包含了地址空间和独立进程集的完整虚拟机。

访问单个节点或节点集都受到cookie保护,每个节点都有自己的cookie,而且必须保证所有要和这个节点通信的其他节点有相同的cookie,为此,在一个分布式系统中,所有的节点必须用相同的magic cookie来启动。具有相同cookie而且彼此互相连接的节点集称为erlang集群。
三种方法来设置cookie:
1.把相同的cookie存放在$HOME/.erlang.cookie文件中。
2.在启动erlang时,带上命令行参数-setcookie C把cookie设置为C。
3.使用erlang:set_cookie(C)把本地节点的cookie设置为C

事例:名字服务

-module(kvs).
-compile(export_all).

start() ->
register(kvs,spawn(fun() -> loop() end)).

store(Key,Value) ->
rpc({store,Key,Value}).

loopup(Key) ->
rpc({loopup,Key}).

rpc(Q) ->
kvs ! {self(),Q},
receive
{kvs,Reply} ->
Reply
end.

loop() ->
receive
{From,{store,Key,Value}} ->
put(Key,{ok,Value}),
From ! {kvs,true},
loop();
{From,{loopup,Key}} ->
From ! {kvs,get(Key)},
loop()
end.


本地测试:

kvs:start().
kvs:store(aaa,”aaa”).
kvs:loopup(aaa).


在同一台机器上运行两个节点测试:

erl –sname a //命令行启动erlang,-sname表示启动一个名字为a的节点
kvs:start(). //在a节点上启动服务
erl -sname b //启动一个名字为b的节点
rpc:call(a@LBWin7,kvs,store,[aaa,"aaa"]). //在b节点上远程调用服务
rpc:call(a@Lbwin7,kvs,loopup,[aaa]).

函数rpc:call(Node,Mod,Fun,[Arg1,Arg2…]):在Node节点上执行一个远程调用,被调用的函数是Mod:Func(Arg1,Arg2…)

spawn(Node,Fun) -> Pid:在Node节点上创建一个进程。
spawn(Node,Mod,Fun,Args) -> Pid:在一个节点上创建一个会执行apply(Mod,Fun,Args)的新进程。
disconnect_node(Node) ->bool()|ignored:强制断开一个节点的连接。
monitor_node(Node,Flag) ->true:如果Flag为true就打开监视,如果Flag为false就会关闭监视,在监视被打开时若有新的Node加入或者离开erlang集群,执行这个BIF的进程就会接收到{nodeup,Node}和{nodedown,Node}消息。
node() -> Node:返回本地节点的名字。如果本地节点不是分布式的,就会返nonode@nohost.
node(Arg) -> Node:返回Arg所指定的节点,Arg可以是一个Pid,一个引用或者一个端口。如果本地节点不是分布式的,就会返回nonode@nohost.
nodes() -> [Node]:返回网络上与当前节点连接的所有其他节点列表。
is_alive() ->bool():如果本地节点状态正式而且是一个分布式系统的一部分,那么返回true,否则返回false.

我们可以使用send原语来向一个分布式的erlang节点集中注册的进程发送消息.
{RegName,Node} ! Msg.
向节点Node上名为RegName的注册进程发送消息Msg.


一个启动远程进程的例子:

-module(dist_demo).
-export([rpc/4,start/1]).
start(Node) ->
spawn(Node,fun()->loop() end).

rpc(Pid,M,F,A) ->
Pid ! {rpc,self(),M,F,A},
receive
{Pid,Response} -> Response
end.

loop() ->
receive
{rpc,Pid,M,F,A} ->
Pid ! {self(), (catch apply(M,F,A))},
loop()
end.

启动两个节点:

erl –sname a
erl –sname b

在a节点上启动一个运行在b节点上的进程:

Pid = dist_demo:start(b@LBWin7).
dist_demo:rpc(Pid,erlang,node,[]).
//这里我们在远程节点上对erlang:node()求值,然后返回运算结果。


分布式编程使用到的lib:
rpc模块提供了一系列的远程调用服务。
global模块提供了名称注册函数和分布式系统中的锁定功能,还有完整的网络连接维护函数。
详情参考官方文档。

rpc模块最为常用的函数:
call(Node,Mod,Fun,Args) -> Result|{badrpc,Reason}
这个函数会在Node节点上对apply(Mod,Fun,Args)进行求值并且返回Result或者在调用失败时返回{badrpc,Reason}.


基于套接字的分布式模型:
在一个不安全的网络环境中,我们使用一种受限的进程创建模式,在这种模式下,特定机器的拥有者有显示的控制权来控制什么能在他们自己的机器上运行。

lib_chan:lib_chan是一个允许一个用户显示的控制他自己的机器能够启动哪些模块进程。
主要接口有:
start_server() -> true:这个函数在本地主机上启动一个服务,这个服务器的行为取决于文件$HOME/.erlang/lib_chan.conf中的配置。
start_server(Conf) -> true.:这个函数在本地主机上启动一个服务器,其行为取决于文件Conf的内容。
配置文件是一个包含了一系列元祖的文件,格式如下:

{port,NNNN} //告诉服务器监听的端口号为NNNN
{service,S,password,P,mfa,SomeMod,SomeFun,SomeArg}
//这个配置定义了一个由密码P保护的服务S
//如果服务启动,那么由SomeMod:SomeFun(MM,ArgsC,SomeArgs)创建的进程处理来自客户
//端的消息,这里MM是代理进程的Pid,这个代理进程通常用来向客户机发送消息,参数//ArgsC则是来自客户端的调用参数。

connect(Host,Port,S,P,ArgsC) -> {ok,Pid} | {error,Why}:尝试在主机Host上打开端口Port,然后尝试激活由密码P保护的服务S,如果密码正确,则返回{ok,Pid},其中Pid是向服务器发送消息的代理进程的进程标识。当客户端调用这个函数来发起一个连接时,就会创建两个代理进程,一个在客户端,一个在服务端,这两个代理进程负责把erlang消息处理为TCP数据包,并且负责捕获来自控制进程的退出信号和套接字消息。

事例:把lib_chan和kvs整合在一起。
首先编写配置文件:

{port,1234}.
{service,nameServer,password,"123456",mfa,mod_name_server,start_me_up,notUsed}

这个配置文件的意思是我们准备在机器上1234端口启动一个名为nameServer的服务,并且使用密码123456把服务保护起来。

-module(mod_name_server).
-compile(export_all).

start_me_up(MM,_ArgC,_ArgS) ->
loop(MM).

loop(MM) ->
receive
{chan,MM,{store,K,V}} ->
{chan,MM,{store,K,V}} ->
kvs:store(K,V),
loop(MM);
{chan,MM,{loopup,K}} ->
MM ! {send,kvs:loopup(K)},
loop(MM);
{chan_closed,MM} ->
true
end.

mod_name_server的协议如下:
如果客户端向服务器发送一个消息{send,X},那么它就会在mod_name_server中转换成形如{chan,MM,X}的消息(MM是服务器代理进程的Pid)。
如果客户端停止或者套接字因为某种原因终止通信并且关闭,那么服务器就会收到形如{chan_closed,MM}的消息。
如果服务器想要发送消息X给客户端,服务器只需要调用MM!{send,X}。
如果服务器想要显示的关闭连接,那么服务器只要执行M!close。
这份协议是客户端和服务器两端的代码都必须遵守的中间协议。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值