- 在 Erlang 中沒有共享,只有消息傳遞,因此分佈式還是單機本質上沒有什麼區別。
- Erlang 集羣是一個全聯通網絡。
- 節點啓動:
- erl -name xx
適用於配有 DNS 的普通網絡環境,需要給出節點的完全限定域名 - erl -sname xx
適用於完全限定域名不可用的情況
- erl -name xx
- 採用短節點名和長節點名的節點所處的通信模式是不同的,它們之間無法形成集羣。
- 隱形節點:
藉助一些特殊的節點,我們可以將多個集羣合併成更大的、非全聯通的集羣。
這類節點經過特殊配置,不會對外傳播其他節點的信息,它們甚至可以對其他節點隱身,以便對集羣進行非侵入式監控。 - 建立連接:
net_adm:ping('[email protected]').
- EPMD(Erlang 端口映射守護進程):
- 啓動每一個節點,EPMD 都會檢查本地機器上是否運行着 EPMD,如果沒有,節點就會自動啓動 EPMD;
- EPMD 會追蹤在本地機器上運行的每個節點,並記錄分配給它們的端口號;
- 當一臺機器上的 Erlang 節點試圖與遠程節點通信時, 本地的 EPMD 就會聯絡遠程機器上的 EPMD(默認使用TCP/IP,端口號4369),詢問在遠程機器上有沒有相應名字的節點。如果有,遠程 EPMD 就會回覆一個端口號,通過該端口便可直接與遠程節點通信;
- EPMD 不會主動搜尋其他 EPMD,只有在某個節點主動搜尋其他節點時才能建立。
- 通信安全:
Erlang 默認的分佈式模型基於這樣一個假設,集羣中的所有節點都運行在一個受信網絡內。
如果這個假設不成立,或者其中的某些機器需要與外界通信,那麼就應該直接在TCP(或 UDP、SCTP 等)之上配合恰當的應用層協議來實現非受信網絡上的通信。此外還可以利用 SSL、SSH、IPsec 等技術建立加密隧道,甚至直接將 Erlang 的分佈式通信層架設在 SSL 等傳輸協議之上。 -
auth:get_cookie(). % 獲取當前節點的 cookie set_cookie(Node, Cookie). % 設置 cookie
- 在 Erlang 中,shell 是採用進程來容錯的。shell 進程崩潰後,信箱中的內容會丟失,但變量綁定關係仍然會保留。
- 遠程使用 shell:
- 節點之間事先無須建立連接
- Ctrl-G 命令下:r '[email protected]'
- 如果節點名中含有句點,要加上單引號
- 命令不會立即見效
- 退出遠程 shell 時注意:!!!不要用 q(). q() 是關閉執行該命令的節點,也就是遠程節點。
要想安全退出,要使用 Ctrl-G 或 Ctrl-C
- 資源探測應用:
- 資源探測:建立資源提供方和資源使用方之間的關係
- 代碼實現:
-module(resource_discovery). -behavior(gen_server). %% API -export([start_link/0, add_target_resource_type/1, add_local_resource/2, fetch_resources/1, trade_resources/0]). -export([ init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3 ]). -define(SERVER, ?MODULE). -record(state, {target_resource_types, local_resource_tuples, found_resource_tuples}). start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). init([]) -> {ok, #state{target_resource_types = [], local_resource_tuples = dict:new(), found_resource_tuples = dict:new()}}. add_target_resource_type(Type) -> gen_server:cast(?SERVER, {add_target_resource_type, Type}). add_local_resource(Type, Instance) -> gen_server:cast(?SERVER, {add_local_resource, {Type, Instance}}). fetch_resources(Type) -> gen_server:call(?SERVER, {fetch_resources, Type}). trade_resources() -> gen_server:cast(?SERVER, trade_resources). handle_cast({add_target_resource_type, Type}, State) -> TargetTypes = State#state.target_resource_types, NewTargetTypes = [Type | lists:delete(Type, TargetTypes)], {noreply, State#state{target_resource_types = NewTargetTypes}}; handle_cast({add_local_resource, {Type, Instance}}, State) -> ResourceTuples = State#state.local_resource_tuples, NewResourceTuples = add_resource(Type, Instance, ResourceTuples), {noreply, State#state{local_resource_tuples = NewResourceTuples}}; handle_cast(trade_resources, State) -> ResourceTuples = State#state.local_resource_tuples, AllNodes = [node() | nodes()], lists:foreach( fun(Node) -> gen_server:cast({?SERVER, Node}, {trade_resources, {node(), ResourceTuples}}) end, AllNodes), {noreply, State}; handle_cast({trade_resources, {ReplyTo, Remotes}}, State) -> #state{local_resource_tuples = Locals, target_resource_types = TargetTypes, found_resource_tuples = OldFound} = State, FilteredRemotes = resource_for_types(TargetTypes, Remotes), NewFound = add_resources(FilteredRemotes, OldFound), case ReplyTo of noreply -> ok; _ -> gen_server:cast({?SERVER, ReplyTo}, {trade_resources, {noreply, Locals}}) end, {noreply, State#state{found_resource_tuples = NewFound}}. handle_call({fetch_resources, Type}, _From, State) -> {reply, dict:find(Type, State#state.local_resource_tuples), State}. handle_info(_, State) -> {stop, normal, State}. terminate(_Reason, _State) -> sc_store:delete(self()), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. add_resources([{Type, Resource} | T ], ResourceTuples) -> add_resources(T, add_resource(Type, Resource, ResourceTuples)); add_resources([], ResourceTuples) -> ResourceTuples. resource_for_types(Types, ResourceTuples) -> Fun = fun(Type, Acc) -> case dict:find(Type, ResourceTuples) of {ok, List} -> [{Type, Instance} || Instance <- List] ++ Acc; error -> Acc end end, lists:foldl(Fun, [], Types). add_resource(Type, Resource, ResourceTuples) -> case dict:find(Type, ResourceTuples) of {ok, ResourceList} -> NewList = [Resource | lists:delete(Resource, ResourceList)], dict:store(Type, NewList, ResourceTuples); error -> dict:store(Type, [Resource], ResourceTuples) end.
《Erlang/OTP併發編程實戰》第八章 分佈式 Erlang/OTP 簡介
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.