2017-11-12 6 views
1

私たちは分散型erlangクラスタを使用しています。ネット分割の場合にこれをテストします。Distributed Erlang:multicallが要求されたタイムアウトを超過しました

クラスタのすべてのノードから情報を取得するには、定義されたタイムアウトでgen_server:multicall/4を使用します。私が必要とするのは、できるだけ早く利用可能なノードから情報を得ることです。タイムアウトはそれほど大きくはない(約3000ms)。ここで は例を呼び出す:

Timeout = 3000 
Nodes = AllConfiguredNodes 
gen_server:multi_call(Nodes, broker, get_score, Timeout) 

私はこの呼び出しが戻るが、タイムアウトミリ秒につながることを期待しています。しかし、純分割の場合はそうではありません。それは約待つ。 8秒。

私は、マルチコールリクエストが、erlang:monitor(process, {Name, Node})コールでさらに5秒間停止され、リクエストを送信することが判明しました。

私は本当に気にしませんいくつかのノードが応答しないか、またはビジー状態ではない、私は他のものを使用することができますが、私はErlang VM への新しい接続を確立しようとすると、

質問があります:この停止を防ぐことができる解決法をご存知ですか?あるいは私の状況に適した別のRPCかもしれません。

+0

ルック更新回答で明らかな方法で処理することができる。このマルチコール機能で同じことを行うことが有用であろう最初のノードではない場合、私はそれはあなたのソリューションでは、あなたの問題 – Jr0

答えて

0

私の問題の解決策。私はgen_server:call 基本的な考え方を使用してマルチコールの私の独自の実装を作った

はgen_serverですべてのノードを呼び出すことです:別のプロセスで()を呼び出します。これらの呼び出しの結果を収集します。収集は、呼び出しプロセスのメールボックスからメッセージを受信することによって行われます。

タイムアウトを制御するには、タイムアウトが期限切れになったときの期限を計算し、それを参照ポイントとして使用してafterのタイムアウトをreceiveに計算します。

実装

主な機能は次のとおりです。ここ

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) }. 

アイデアは、すべてのノードを呼び出し、1つのタイムアウト内の全ての結果を待つことです。

1ノードの呼び出しは、生成されたプロセスから実行されます。エラーの場合はgen_server:callで使用されている出口をキャッチします。締め切りは

を発生しなくなるまで

call_node(Node, Name, Req, Timeout) -> 
    Ref = make_ref(), 
    Self = self(), 
    spawn_link(fun() -> 
         try 
          Result = gen_server:call({Name,Node},Req,Timeout), 
          Self ! { Ref, { ok, { Node, Result } } } 
         catch 
          exit:Exit -> 
           Self ! { Ref, { error, { 'EXIT', Exit } } } 
         end 
       end), 
    Ref. 

バート・ノードがタイムアウトしてメールボックスを読み取ることによって、TIMOUT

calc_bad_nodes(Nodes, PosResults) -> 
    { GoodNodes, _ } = lists:unzip(PosResults), 
    [ BadNode || BadNode <- Nodes, not lists:member(BadNode, GoodNodes) ]. 

結果内に応答されていないものを収集しているように計算されている

read_all(ReadList, Timeout) -> 
    Now = erlang:monotonic_time(millisecond), 
    Deadline = Now + Timeout, 
    read_all_impl(ReadList, Deadline, []). 

実装読み取り

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. 

1回の読み取りは、タイムアウトのあるメールボックスからの受信だけです。

read(Timeout, Ref) -> 
    receive 
     { Ref, Result } -> 
      { ok, Result } 
    after Timeout -> 
      { error, { read_timeout, Timeout } } 
    end. 

さらなる改良:

  • RPCモジュールは、後半の答えのゴミを避けるために別のプロセスを生成します。だから、
  • infinityはタイムアウトが
0

あなたが解決しようとしている問題を完全に理解しているかどうかはわかりませんが、Xの時間内に取得して残りのものを無視できるすべての回答を得るには、 async_callと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]. 

参照のようなもの:詳細はhttp://erlang.org/doc/man/rpc.html#async_call-4

+0

を解決だと思います利用可能な場合、rpc:nb_yeild()はタイムアウトを待機します.2番目のノードも使用できない場合は、2 *タイムアウトなど待機します。タイムアウト内に到着したすべての回答を収集したい。また、私は確信していませんが、私はrpc:async_callもerlang:monitor(node)を呼び出してからメッセージを送ることを期待しています。 –

+0

更新された提案を見てください。超短時間のタイムアウトを使用して、1つまたは十分な結果が得られるまで繰り返すだけです。私はあなたに、完全な解決策ではなく、うまくいくと思う方向を与えています。これは*約束*なので、私はそれが何かをブロックすることを期待しません - asynch_call/4はすぐに戻ります – Jr0

関連する問題