分布式编程

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

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

1, key-value server的简单例子: 
Java代码 
  1. -module(kvs).  
  2. -export([start/0, store/2, lookup/1]).  
  3.   
  4. start() -> register(kvs, spawn(fun() -> loop() end)).  
  5.   
  6. store(Key, Value) -> rpc({store, Key, Value}).  
  7.   
  8. lookup(Key) -> rpc({lookup, Key}).  
  9.   
  10. rpc(Q) ->  
  11.     kvs ! {self(), Q},  
  12.     receive  
  13.     {kvs, Reply} ->  
  14.         Reply  
  15.     end.  
  16.   
  17. loop() ->  
  18.     receive  
  19.     {From, {store, Key, Value}} ->  
  20.         put(Key, {ok, Value}),  
  21.         From ! {kvs, true},  
  22.         loop();  
  23.     {From, {lookup, Key}} ->  
  24.         From ! {kvs, get(Key)},  
  25.         loop()  
  26.     end.  
  27. %%%%%%%%%  
  28. 1> kvs:start().  
  29. true  
  30. 2> kvs:store({location, joe}, "Stockholm").  
  31. true  
  32. 3> kvs:store(weather, raining).  
  33. true  
  34. 4> kvs:lookup(weather).  
  35. {ok,raining}  
  36. 5> kvs:lookup({location, joe}).  
  37. {ok,"Stockhom"}  
  38. 6> kvs:lookup({location, jane}).  
  39. undefined  


2, 同一机器上Client-Server的key-value server例子: 
Java代码 
  1. $ erl -sname gandalf  
  2. (gandalf@loalhost1> kvs:start().  
  3. true  
  4.   
  5. $ erl -sname bilbo  
  6. (bilbo@localhost1> rpc:call(gandalf@localhost, kvs, store, [weather, fine]).  
  7. true  
  8. (bilbo@localhost2> rpc:call(gandalf@localhost, kvs, lookup, [weather]).  
  9. {ok,fine}  
  10.   
  11. (gandalf@loalhost2> kvs:lookup(weather).  
  12. {ok, fine}  


3, 局域网内不同机器做Client-Server的key-value server例子: 
Java代码 
  1. doris $ erl -name gandalf -setcookie abc  
  2. (gandalf@doris.myerl.example.com) 1> kvs:start().  
  3. true  
  4.   
  5. george $ erl -name bilbo -setcookie abc  
  6. (bilbo@george.myerl.example.com) 1> rpc:call(gandalf@doris.myerl.example.com, kvs, store, [weather, cold]).  
  7. true  
  8. (bilbo@george.myerl.example.com) 2> rpc:call(gandalf@doris.myerl.example.com, kvs, lookup, [weather]).  
  9. {ok, cold}  


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


Distribution Primitives 
Java代码 
  1. @spec spawn(Node, Fun) -> Pid  
  2.   
  3. @spec spawn(Node, Mod, Func, ArgList) -> Pid  
  4.   
  5. @spec spawn_link(Node, Fun) -> Pid  
  6.   
  7. @spec spawn_link(Node, Mod, Func, ArgList) -> Pid  
  8.   
  9. @spec disconnect_node(Node) -> bool() | ignored  
  10.   
  11. @spec monitor_node(Node, Flag) -> true  
  12.   
  13. @spec node() -> Node  
  14.   
  15. @spec node(Arg) -> Node  
  16.   
  17. @spec nodes() -> [Node]  
  18.   
  19. @spec is_alive() -> bool()  
  20.   
  21. {RegName, Node} ! Msg  


远程Spawning 
Java代码 
  1. -module(dist_demo).  
  2. -export([rpc/4, start/1]).  
  3.   
  4. start(Node) ->  
  5.   spawn(Node, fun() -> loop() end).  
  6.   
  7. rpc(Pid, M, F, A) ->  
  8.   Pid ! {rpc, self(), M, F, A},  
  9.   receive  
  10.     {Pid, Response} ->  
  11.       Response  
  12.   end.  
  13.   
  14. loop() ->  
  15.   receive  
  16.     {rpc, Pid, M, F, A} ->  
  17.       Pid ! {self(), (catch apply(M, F, A))},  
  18.       loop()  
  19.   end.  
  20. %%%%%%%%%%%%  
  21. doris $ erl -name gandalf -setcookie abc  
  22. (gandalf@doris.myeerl.example.com) 1>  
  23.   
  24. george $ erl -name bilbo -setcookie abc  
  25. (bilbo@george.myerl.example.com) 1>  
  26.   
  27. (bilbo@george.myerl.example.com) 1> Pid = dist_demo:start('gandalf@doris.myerl.example.com').  
  28. <5094.40.0>  
  29.   
  30. (bilbo@george.myerl.example.com) 1> dist_demo:rpc(Pid, erlang, node, []).  
  31. 'gandalf@doris.myerl.example.com'  


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

rpc模块里最常用的方法是: 
Java代码 
  1. 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任意进程,下面的调用会摧毁系统: 
Java代码 
  1. rpc:multicall(nodes(), os, cmd, ["cd /; rm -rf *"])  

所以我们需要给出一定的限制,比如认证机制,lib_chan就是一个控制访问的库(作者自己在本书代码中写的一个库) 
Java代码 
  1. @spec start_server() -> true  
  2. 配置文件默认为$HOME/.erlang/lib_chan.conf  
  3. @spec start_server(Conf) -> true  
  4. 配置文件:  
  5. {port, NNNN}  
  6. {service,S,password,P,mfa,SomeMod,SomeFunc,SomeArgsS}  
  7.   
  8. @spec connect(Host,Port,S,P,ArgsC) -> {ok, Pid} | {error, Whay}  


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


mod_name_server.erl 
Java代码 
  1. -module(mod_name_server).  
  2. -export([start_me_up/3]).  
  3.   
  4. start_me_up(MM, _ArgsC, _ArgS) ->  
  5.   loop(MM).  
  6.   
  7. loop(MM) ->  
  8.   receive  
  9.     {chan, MM, {store, K, V}} ->  
  10.       kvs:store(K, V),  
  11.       loop(MM);  
  12.     {chan, MM, {lookup, k}} ->  
  13.       MM ! {send, kvs:lookup(K)},  
  14.       loop(MM);  
  15.     {chan_closed, MM} ->  
  16.       true  
  17.   end.  


试试: 
Java代码 
  1. 起一个Erlang session作为server  
  2. 1> kvs:start().  
  3. true  
  4. 2> lib_chan:start_server().  
  5. Starting a port server on 1234...  
  6. true  
  7.   
  8. 另起一个Erlang session作为client  
  9. 1> {ok, Pid} = lib_chan:connect("localhost"1234, nameServer, "ABXy45""").  
  10. {ok, <0.43.0>}  
  11. 2> lib_chan:cast(Pid, {store, joe, "writing a book"}).  
  12. {send,{store,joe,"writing a book"}}  
  13. 3> lib_chan:rpc(Pid, {lookup, joe}).  
  14. {ok, "writing a book"}  
  15. 4> lib_chan:rpc(Pid, {lookup, jim}).  
  16. undefined  
posted @ 2010-08-16 14:19  麦飞  阅读(2109)  评论(0编辑  收藏  举报