Programming Eralng读书笔记10: 分布式编程

分布式程序指设计用于运行在网络中的可以通过消息传递相互交流彼此的活动的计算机上的程序

分布式应用的好处:Performance、Reliability、Scalability、Intrinsically distributed application、Fun、

1, key-value server的简单例子:
[code]
-module(kvs).
-export([start/0, store/2, lookup/1]).

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

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

lookup(Key) -> rpc({lookup, 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, {lookup, Key}} ->
From ! {kvs, get(Key)},
loop()
end.
%%%%%%%%%
1> kvs:start().
true
2> kvs:store({location, joe}, "Stockholm").
true
3> kvs:store(weather, raining).
true
4> kvs:lookup(weather).
{ok,raining}
5> kvs:lookup({location, joe}).
{ok,"Stockhom"}
6> kvs:lookup({location, jane}).
undefined
[/code]

2, 同一机器上Client-Server的key-value server例子:
[code]
$ erl -sname gandalf
(gandalf@loalhost) 1> kvs:start().
true

$ erl -sname bilbo
(bilbo@localhost) 1> rpc:call(gandalf@localhost, kvs, store, [weather, fine]).
true
(bilbo@localhost) 2> rpc:call(gandalf@localhost, kvs, lookup, [weather]).
{ok,fine}

(gandalf@loalhost) 2> kvs:lookup(weather).
{ok, fine}
[/code]

3, 局域网内不同机器做Client-Server的key-value server例子:
[code]
doris $ erl -name gandalf -setcookie abc
(gandalf@doris.myerl.example.com) 1> kvs:start().
true

george $ erl -name bilbo -setcookie abc
(bilbo@george.myerl.example.com) 1> rpc:call(gandalf@doris.myerl.example.com, kvs, store, [weather, cold]).
true
(bilbo@george.myerl.example.com) 2> rpc:call(gandalf@doris.myerl.example.com, kvs, lookup, [weather]).
{ok, cold}
[/code]

4, Internet上不同主机的Client-Server的key-value server的例子:
1)确保4369端口对TCP和UDP都开放,epmd(Erlang Port Mapper Daemon)这个程序需要使用该端口
2)如果想使用的端口为Min和Max,则确保这些端口也是打开的
[code]
$ erl -name ... -setcookie ... -kernel inet_dist_listen_min Min \
inet_dist_listen_max Max
[/code]

Distribution Primitives
[code]
@spec spawn(Node, Fun) -> Pid

@spec spawn(Node, Mod, Func, ArgList) -> Pid

@spec spawn_link(Node, Fun) -> Pid

@spec spawn_link(Node, Mod, Func, ArgList) -> Pid

@spec disconnect_node(Node) -> bool() | ignored

@spec monitor_node(Node, Flag) -> true

@spec node() -> Node

@spec node(Arg) -> Node

@spec nodes() -> [Node]

@spec is_alive() -> bool()

{RegName, Node} ! Msg
[/code]

远程Spawning
[code]
-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.
%%%%%%%%%%%%
doris $ erl -name gandalf -setcookie abc
(gandalf@doris.myeerl.example.com) 1>

george $ erl -name bilbo -setcookie abc
(bilbo@george.myerl.example.com) 1>

(bilbo@george.myerl.example.com) 1> Pid = dist_demo:start('gandalf@doris.myerl.example.com').
<5094.40.0>

(bilbo@george.myerl.example.com) 1> dist_demo:rpc(Pid, erlang, node, []).
'gandalf@doris.myerl.example.com'
[/code]

一般写分布式程序时不会直接用这些BIFs,而是使用一些封装好的libraries
[code]
rpc
global
[/code]
rpc模块里最常用的方法是:
[code]
call(Node, Mod, Function, Args) -> Result|{badrpc, Reason}
[/code]

对于分布式Erlang节点,它们必须使用cookie
cookie不会跨网络发送,而是仅仅用于初始化session认证
有三种设置cookie的方式:
1,在$HOME/.erlang.cookie文件里写入,然后chmod 400 .erlang.cookie只允许文件所有者访问
2,$ erl -setcookie AFRTY12ESS...,不安全,ps命令可以看到
3,erlang:set_cookie(node(), C)

分布式Erlang的主要问题是不安全,client可以在server机器上spawn任意进程,下面的调用会摧毁系统:
[code]
rpc:multicall(nodes(), os, cmd, ["cd /; rm -rf *"])
[/code]
所以我们需要给出一定的限制,比如认证机制,lib_chan就是一个控制访问的库(作者自己在本书代码中写的一个库)
[code]
@spec start_server() -> true
配置文件默认为$HOME/.erlang/lib_chan.conf
@spec start_server(Conf) -> true
配置文件:
{port, NNNN}
{service,S,password,P,mfa,SomeMod,SomeFunc,SomeArgsS}

@spec connect(Host,Port,S,P,ArgsC) -> {ok, Pid} | {error, Whay}
[/code]

例如如下配置文件
[code]
{port, 1234}.
{service, nameServer, password, "ABXy45", mfa, mod_name_server, start_me_up, notUsed}.
[/code]

mod_name_server.erl
[code]
-module(mod_name_server).
-export([start_me_up/3]).

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

loop(MM) ->
receive
{chan, MM, {store, K, V}} ->
kvs:store(K, V),
loop(MM);
{chan, MM, {lookup, k}} ->
MM ! {send, kvs:lookup(K)},
loop(MM);
{chan_closed, MM} ->
true
end.
[/code]

试试:
[code]
起一个Erlang session作为server
1> kvs:start().
true
2> lib_chan:start_server().
Starting a port server on 1234...
true

另起一个Erlang session作为client
1> {ok, Pid} = lib_chan:connect("localhost", 1234, nameServer, "ABXy45", "").
{ok, <0.43.0>}
2> lib_chan:cast(Pid, {store, joe, "writing a book"}).
{send,{store,joe,"writing a book"}}
3> lib_chan:rpc(Pid, {lookup, joe}).
{ok, "writing a book"}
4> lib_chan:rpc(Pid, {lookup, jim}).
undefined
[/code]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值