分布式Erlang:多调用超过请求的超时

分布式Erlang:多调用超过请求的超时,erlang,distributed-computing,rpc,otp,Erlang,Distributed Computing,Rpc,Otp,我们使用分布式erlang集群,现在我在网络分裂的情况下测试它 为了从集群的所有节点获取信息,我使用gen_server:multicall/4和定义的超时。我需要的是尽快从可用节点获取信息。所以超时时间不是太大(大约3000毫秒)。 这里举个例子: Timeout = 3000 Nodes = AllConfiguredNodes gen_server:multi_call(Nodes, broker, get_score, Timeout) 我希望这个调用返回超时毫秒的结果,但在网络分裂的

我们使用分布式erlang集群,现在我在网络分裂的情况下测试它

为了从集群的所有节点获取信息,我使用gen_server:multicall/4和定义的超时。我需要的是尽快从可用节点获取信息。所以超时时间不是太大(大约3000毫秒)。 这里举个例子:

Timeout = 3000
Nodes = AllConfiguredNodes
gen_server:multi_call(Nodes, broker, get_score, Timeout)
我希望这个调用返回超时毫秒的结果,但在网络分裂的情况下,它不会。等待约8秒

我发现在发送请求之前,在call
erlang:monitor(进程,{Name,Node})
中,multi_调用请求被暂停了5秒钟

我真的不在乎某个节点不应答、忙或不可用,我可以使用任何其他节点,但由于这个暂停,我不得不等到Erlang VM 尝试建立到失效/不可用节点的新连接


问题是:您知道可以防止这种停顿的解决方案吗?或者可能是另一个适合我的RPC。

我不确定我是否完全理解您试图解决的问题,但如果要在X时间内获得所有可以检索到的答案,而忽略其他答案,您可以尝试结合使用async_call和nb_产量

也许像

somefun() ->
    SmallTimeMs = 50,
    Nodes = AllConfiguredNodes,
    Promises = [rpc:async_call(N, some_mod, some_fun, ArgList) || N <- Nodes],
    get_results([], Promises, SmallTimeMs).


get_results(Results, _Promises, _SmallTimeMs) when length(Results) > 1 ->   % Replace 1 with whatever is the minimum acceptable number of results
    lists:flatten(Results);
get_results(Results, Promises, SmallTimeMs) ->
    Rs = get_promises(Promises, SmallTimeMs)
    get_results([Results|Rs], Promises, SmallTimeMs)).


get_promise(Promises, WaitMs) ->
    [rpc:nb_yield(Key, WaitMs) || Key <- Promises].
somefun()->
SmallTimeMs=50,
节点=所有配置的节点,
Promissions=[rpc:async_call(N,some_mod,some_fun,ArgList)| | N 1->%1替换为可接受的最小结果数
列表:展平(结果);
获取结果(结果、承诺、SmallTimeMs)->
Rs=获得承诺(承诺、小时间)
获取结果([结果]、承诺、SmallTimeMs))。
获得承诺(承诺,等待)->

[rpc:nb_yield(Key,WaitMs)| | Key我不确定我是否完全理解您试图解决的问题,但如果要在X时间内获得所有可以检索到的答案,而忽略其他答案,您可以尝试将异步_调用和nb_yield结合起来

也许像

somefun() ->
    SmallTimeMs = 50,
    Nodes = AllConfiguredNodes,
    Promises = [rpc:async_call(N, some_mod, some_fun, ArgList) || N <- Nodes],
    get_results([], Promises, SmallTimeMs).


get_results(Results, _Promises, _SmallTimeMs) when length(Results) > 1 ->   % Replace 1 with whatever is the minimum acceptable number of results
    lists:flatten(Results);
get_results(Results, Promises, SmallTimeMs) ->
    Rs = get_promises(Promises, SmallTimeMs)
    get_results([Results|Rs], Promises, SmallTimeMs)).


get_promise(Promises, WaitMs) ->
    [rpc:nb_yield(Key, WaitMs) || Key <- Promises].
somefun()->
SmallTimeMs=50,
节点=所有配置的节点,
Promissions=[rpc:async_call(N,some_mod,some_fun,ArgList)| | N 1->%1替换为可接受的最小结果数
列表:展平(结果);
获取结果(结果、承诺、SmallTimeMs)->
Rs=获得承诺(承诺、小时间)
获取结果([结果]、承诺、SmallTimeMs))。
获得承诺(承诺,等待)->

[rpc:nb_yield(Key,WaitMs)| | Key我的问题解决方案。

我已经实现了自己的multicall,它使用
gen\u server:call
基本思想是在单独的进程中使用gen_server:call()调用所有节点,并收集这些调用的结果。收集是通过从调用进程的邮箱接收消息来完成的

为了控制超时,我计算超时过期时的截止时间,然后将其用作参考点,以计算
接收中
之后
的超时时间

实施

主要功能是:

multicall(Nodes, Name, Req, Timeout) ->
    Refs = lists:map(fun(Node) -> call_node(Node, Name, Req, Timeout) end, Nodes),
    Results = read_all(Timeout, Refs),
    PosResults = [ { Node, Result } || { ok, { ok, { Node, Result } } } <- Results ],
    { PosResults, calc_bad_nodes(Nodes, PosResults) }.
坏节点被计算为在Timout内未响应的节点

calc_bad_nodes(Nodes, PosResults) ->
    { GoodNodes, _ } = lists:unzip(PosResults),
    [ BadNode || BadNode <- Nodes, not lists:member(BadNode, GoodNodes) ].
实现读取直到截止日期未出现

read_all_impl([], _, Results) ->
    lists:reverse(Results);
read_all_impl([ W | Rest ], expired, Results) ->
    R = read(0, W),
    read_all_impl(Rest, expired, [R | Results ]);
read_all_impl([ W | Rest ] = L, Deadline, Results) ->
    Now = erlang:monotonic_time(millisecond),
    case Deadline - Now of
        Timeout when Timeout > 0 ->
            R = read(Timeout, W),
            case R of
                { ok, _ } ->
                    read_all_impl(Rest, Deadline, [ R | Results ]);
                { error, { read_timeout, _ } } ->
                    read_all_impl(Rest, expired, [ R | Results ])
            end;
        Timeout when Timeout =< 0 ->
            read_all_impl(L, expired, Results)
    end.
进一步改进:

  • rpc模块生成单独的进程以避免延迟应答的垃圾。因此,在这个多调用函数中执行相同的操作将非常有用
  • 无限
    超时可以用明显的方式处理

    • 我的问题解决方案。

      我已经实现了自己的multicall,它使用
      gen\u server:call
      基本思想是在单独的进程中使用gen_server:call()调用所有节点,并收集这些调用的结果。收集是通过从调用进程的邮箱接收消息来完成的

      为了控制超时,我计算超时过期时的截止时间,然后将其用作参考点,以计算
      接收中
      之后
      的超时时间

      实施

      主要功能是:

      multicall(Nodes, Name, Req, Timeout) ->
          Refs = lists:map(fun(Node) -> call_node(Node, Name, Req, Timeout) end, Nodes),
          Results = read_all(Timeout, Refs),
          PosResults = [ { Node, Result } || { ok, { ok, { Node, Result } } } <- Results ],
          { PosResults, calc_bad_nodes(Nodes, PosResults) }.
      
      坏节点被计算为在Timout内未响应的节点

      calc_bad_nodes(Nodes, PosResults) ->
          { GoodNodes, _ } = lists:unzip(PosResults),
          [ BadNode || BadNode <- Nodes, not lists:member(BadNode, GoodNodes) ].
      
      实现读取直到截止日期未出现

      read_all_impl([], _, Results) ->
          lists:reverse(Results);
      read_all_impl([ W | Rest ], expired, Results) ->
          R = read(0, W),
          read_all_impl(Rest, expired, [R | Results ]);
      read_all_impl([ W | Rest ] = L, Deadline, Results) ->
          Now = erlang:monotonic_time(millisecond),
          case Deadline - Now of
              Timeout when Timeout > 0 ->
                  R = read(Timeout, W),
                  case R of
                      { ok, _ } ->
                          read_all_impl(Rest, Deadline, [ R | Results ]);
                      { error, { read_timeout, _ } } ->
                          read_all_impl(Rest, expired, [ R | Results ])
                  end;
              Timeout when Timeout =< 0 ->
                  read_all_impl(L, expired, Results)
          end.
      
      进一步改进:

      • rpc模块生成单独的进程以避免延迟应答的垃圾。因此,在这个多调用函数中执行相同的操作将非常有用
      • 无限
        超时可以用明显的方式处理

      在您的解决方案中,如果第一个节点不可用,则rpc:nb_yeild()将等待超时,如果第二个节点也不可用,则将等待2*超时等。我希望收集在一个超时内到达的所有答案。我也不确定,但我希望rpc:async_调用也会调用erlang:monitor(节点)在发送消息之前。查看更新后的建议。只需使用超短超时并重复,直到得到1个或足够的结果。我给您的是一个我认为应该有效的方向,而不是完整的解决方案。因为这是一个承诺,我不希望它会阻止任何事情-如果f第一个节点不可用,则rpc:nb_yeild()等待超时,如果第二个节点也不可用,则等待2*超时等。我想收集在一个超时内到达的所有答案。我也不确定,但我希望rpc:async_调用也会调用erlang:monitor(节点)在发送消息之前。查看更新后的建议。只需使用超短超时并重复,直到得到1个或足够的结果。我给您的是一个我认为应该有效的方向,而不是完整的解决方案。因为这是一个承诺,我不希望它会阻止任何事情-asynch_call/4应该立即返回到更新后的answer,我认为它解决了你的问题看看更新的答案,我认为它解决了你的问题