`
hideto
  • 浏览: 2679197 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

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

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

1, key-value server的简单例子:
-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


2, 同一机器上Client-Server的key-value server例子:
$ 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}


3, 局域网内不同机器做Client-Server的key-value server例子:
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}


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


Distribution Primitives
@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


远程Spawning
-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'


一般写分布式程序时不会直接用这些BIFs,而是使用一些封装好的libraries
rpc
global

rpc模块里最常用的方法是:
call(Node, Mod, Function, Args) -> Result|{badrpc, Reason}


对于分布式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任意进程,下面的调用会摧毁系统:
rpc:multicall(nodes(), os, cmd, ["cd /; rm -rf *"])

所以我们需要给出一定的限制,比如认证机制,lib_chan就是一个控制访问的库(作者自己在本书代码中写的一个库)
@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}


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


mod_name_server.erl
-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.


试试:
起一个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
分享到:
评论
1 楼 linkerlin 2008-01-23  
1~10都看了,写的很棒!
期待后续...
:D

相关推荐

Global site tag (gtag.js) - Google Analytics