《Erlang/OTP并发编程实战》第八章 分布式 Erlang/OTP 简介

  1. 在 Erlang 中没有共享,只有消息传递,因此分布式还是单机本质上没有什么区别。
  2. Erlang 集群是一个全联通网络。
  3. 节点启动:
    1. erl -name xx
      适用于配有 DNS 的普通网络环境,需要给出节点的完全限定域名
    2. erl -sname xx
      适用于完全限定域名不可用的情况
  4. 采用短节点名和长节点名的节点所处的通信模式是不同的,它们之间无法形成集群。
  5. 隐形节点:
    借助一些特殊的节点,我们可以将多个集群合并成更大的、非全联通的集群。
    这类节点经过特殊配置,不会对外传播其他节点的信息,它们甚至可以对其他节点隐身,以便对集群进行非侵入式监控。
  6. 建立连接:
    net_adm:ping('[email protected]').
  7. EPMD(Erlang 端口映射守护进程):
    1. 启动每一个节点,EPMD 都会检查本地机器上是否运行着 EPMD,如果没有,节点就会自动启动 EPMD;
    2. EPMD 会追踪在本地机器上运行的每个节点,并记录分配给它们的端口号;
    3. 当一台机器上的 Erlang 节点试图与远程节点通信时, 本地的 EPMD 就会联络远程机器上的 EPMD(默认使用TCP/IP,端口号4369),询问在远程机器上有没有相应名字的节点。如果有,远程 EPMD 就会回复一个端口号,通过该端口便可直接与远程节点通信;
    4. EPMD 不会主动搜寻其他 EPMD,只有在某个节点主动搜寻其他节点时才能建立。
  8. 通信安全:
    Erlang 默认的分布式模型基于这样一个假设,集群中的所有节点都运行在一个受信网络内。
    如果这个假设不成立,或者其中的某些机器需要与外界通信,那么就应该直接在TCP(或 UDP、SCTP 等)之上配合恰当的应用层协议来实现非受信网络上的通信。此外还可以利用 SSL、SSH、IPsec 等技术建立加密隧道,甚至直接将 Erlang 的分布式通信层架设在 SSL 等传输协议之上。
  9.  
    auth:get_cookie().            % 获取当前节点的 cookie
    set_cookie(Node, Cookie).     % 设置 cookie
  10. 在 Erlang 中,shell 是采用进程来容错的。shell 进程崩溃后,信箱中的内容会丢失,但变量绑定关系仍然会保留。
  11. 远程使用 shell:
    1. 节点之间事先无须建立连接
    2. Ctrl-G 命令下:r '[email protected]'
    3. 如果节点名中含有句点,要加上单引号
    4. 命令不会立即见效
    5. 退出远程 shell 时注意:!!!不要用 q(). q() 是关闭执行该命令的节点,也就是远程节点。
      要想安全退出,要使用 Ctrl-G 或 Ctrl-C
  12. 资源探测应用:
    1. 资源探测:建立资源提供方和资源使用方之间的关系
    2. 代码实现:
      -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.
发布了42 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sanmao123456_/article/details/103481125