ETS
, common test
를 다루는 25, 28 장은 대충 보고,Erlang Term Storage
$ erl
1> ets:new(ingredients, [set, named_table]).
ingredients
2> ets:insert(ingredients, {bacon, great}).
true
3> ets:lookup(ingredients, bacon).
[{bacon,great}]
4> ets:insert(ingredients, {bacon, awesome}, {cabbage, alright}).
true
3> ets:lookup(ingredients, bacon).
[{bacon,awesome}]
4> ets:delete(ingredients, cabbage).
true
5> ets:lookup(ingredients, cabbage).
[]
$ erl
1> ets:new(table, [ordered_set, named_table]).
table
2> ets:insert(table, [{a, 10}, {z, 70}, {c, 20}]).
true
3> ets:first(table).
a
4> ets:next(table, a).
c
4> ets:last(table).
z
$ erl
1> ets:new(table, [bag, named_table]).
table
2> ets:insert(table, [{items,1,1},
{items,6,7},
{items,3,4},
{items,1,2}]).
true
3> ets:match(table, {items, '$1', '$1'}).
[[1]]
4> ets:match_object(table, {items, '$1', '$1'}).
[{items,1,1}]
5> ets:select(table, [{{items,'$1','_'},[{'>','$1',5}],['$_']}]).
[{items,6,7}]
6> ets:select(table, ets:fun2ms(fun(N = {items,X,_}) when X > 5 -> N end)).
[{items,6,7}]
드디어 3번째 매력을 학습할 차례!!
"Distributed programming is like being left alone in the dark, with monsters everywhere."
Distributed Erlang is still leaving you alone in the dark.
Erlang gives you some tools. (not solutions)
Erlang gives you
net_kernel
global
rpc
remote shells
dist_ac
Consistency, Availability, Parition tolerance 를 모두 만족하는건 불가능하다...
$ erl -sname hi
(hi@cmbp)1>
$ erl -sname ho
(ho@cmbp)1> net_kernel:connect_node(hi@cmbp).
true
(ho@cmbp)2> net_kernel:i(hi@cmbp).
Node = hi@cmbp
State = up
Type = normal
In = 17
Out = 16
Address = 127.0.0.1:60313
ok
(ho@cmbp)2> nodes()
[hi@cmbp]
책에 나온 net_kernel:connect
는 없어진듯?Erlang Port Mapper Daemon
node (VM) 이 실행될때 같이 실행 되는 프로세스
-start_epmd false
옵션으로 epmd 실행을 제한할 수 있습니다.4369
포트를 사용합니다.이름이 주어진 모든 node 는 epmd 에 자신의 이름을 등록합니다.
$ erl -sname hi
(hi@cmbp)1> register(shell, self()).
true
$ erl -sname ho
(ho@cmbp)1> register(shell, self()).
true
(ho@cmbp)2> net_kernel:connect_node(hi@cmbp).
true
(ho@cmbp)3> {shell, hi@cmbp} ! {hello, self()}.
(hi@cmbp)2> receive {hello, Other} -> Other ! "ho there!" end.
"ho there!"
(ho@cmbp)4> flush().
Shell got "ho there!"
ok
$ erl -sname hi
(hi@cmbp)1>
$ erl -sname ho
(ho@cmbp)1> spawn(hi@cmbp, fun() ->
(ho@cmbp)1> io:format("I'm on ~p~n", [node()])
(ho@cmbp)1> end).
I'm on hi@cmbp
<8490.145.0>
Erlang shell 에서 ctrl-G 을 통해 다른 node 에 shell 을 실행할 수 있습니다.
q()
또는 init:stop()
을 호출하면 node 가 종료되니 주의해야 합니다.(hi@cmbp)1>
User switch command
--> h
c [nn] - connect to job
i [nn] - interrupt job
k [nn] - kill job
j - list all jobs
s [shell] - start local shell
r [node [shell]] - start remote shell
q - quit erlang
? | h - this message
--> j
1 {shell,start,[init]}
2 * {ho@cmbp,shell,start,[]}
--> c
(ho@cmbp)1>
rpc
moduleremote procedure call
원격 node 의 함수를 MFA
스타일로 호출할 수 있습니다.
$ erl -sname hi
hi@cmbp1>
$ erl -sname hu
hu@cmbp1>
$ erl -sname ho
ho@cmbp1> rpc:call(hi@cmbp, lists, sort, [[a,e,f,t,h,s,a]]).
[a,a,e,f,h,s,t]
ho@cmbp2> Key = rpc:async_call(hi@cmbp, erlang, node, []).
<0.96.0>
ho@cmbp3> rpc:yield(Key).
hi@cmbp
ho@cmbp4> rpc:multicall([hi@cmbp, hu@cmbp], erlang, is_alive, []).
{[true,true],[]}
net_kernel:connect_node
를 미리 호출하지 않아도 됩니다.rpc
🧙♀️code
모듈을 사용하면 원격 node 에 모듈을 전송할 수 있습니다.
-module(my_module).
-export([say/1]).
say(Str) -> io:format(Str++" world~n").
$ erl -sname hi
hi@cmbp1> c(my_module).
hi@cmbp2> {M, B, F} = code:get_object_code(my_module).
{my_module,<<70,79,82,49,...>>, "/root/my_module.beam"}
hi@cmbp3> rpc:call(ho@cmbp, code, load_binary, [M, F, B]).
{module,my_module}
hi@cmbp4> rpc:call(ho@cmbp, my_module, say, ["hello"]).
hello world
ok
ho@cmbp1> my_module:say("ho").
hello ho
ok
원격 node 로 모듈 자신을 전송합니다.
node
, rpc
... )를 제공하지만, 해결책을 정확하게 주지는 않습니다 ㅠCAP Theorem
) 과 그 과정에서 발생하는 문제(Fallacies of Distributed Computing
)에 대응할 수 있어야 한다고 생각합니다.failover
failover
failover
takeover
dist_ac
(distributed application) 프로세스를 사용하면 failover & takeover 를 구현할 수 있습니다.
dist_ac
를 사용하기 위해서는 config 파일에 distributed
설정이 필요합니다.
[{kernel,
[{distributed, [{m8ball,
5000,
[a@cmbp, {b@cmbp, c@cmbp}]}]},
{sync_nodes_mandatory, [b@cmbp, c@cmbp]},
{sync_nodes_timeout, 30000}
]
}
].
http://erlang.org/doc/design_principles/distributed_applications.html
m8ball
env
에 설정된 값을 랜덤하게 출력하는 아주 간단한 앱.
{application, m9ball,
[{vsn, "1.0.0"},
{description, "Answer vital questions"},
{modules, [m8ball, m8ball_sup, m8ball_server]},
{applications, [stdlib, kernel, crypto]},
{registered, [m8ball, m8ball_sup, m8ball_server]},
{mod, {m8ball, []}},
{env, [
{answers, {<<"Yes">>, <<"No">>, <<"Doubtful">>,
<<"I don't like your tone">>, <<"Of course">>,
<<"Of course not">>, <<"*backs away slowly and runs away*">>}}
]}
]}.
$ erl -make
$ erl -pa ebin
1> m8ball:ask("hi").
<<"Doubtful">>
m8ball
m8ball
distributed
설정덕분에 3개의 노드에서 모두 접근이 가능합니다.
$ erl -sname a -config config/a -pa ebin
(a@cmbp)1>
$ erl -sname b -config config/b -pa ebin
(b@cmbp)1>
$ erl -sname c -config config/c -pa ebin
(c@cmbp)1> m8ball:ask("hi").
<<"Of course not">>
pid
대신에 {global, NAME}
을 사용해, 다른 node 에서도 m8ball:ask
를 호출 할 수 있습니다.
takeover 때 실행되어야 하는 callback 을 추가합니다.
m8ball
설정에 명시된 3개의 node 가(a
, b
, c
) 모두 실행되어야지만 앱이 시작됩니다.
m8ball
앱은 하나의 node 에서만 실행됩니다.설정만으로 distributed application 을 실행할 수 있는 것은 좋았지만,
elixir
에서는 어떻게 사용할 수 있는지 궁금해 졌습니다.Fallacies of Distributed Computing
의 문제들을 해결할 수 있을지 🤔