2017-11-12 15 views
1

우리는 분산 된 erlang 클러스터를 사용하고 이제는 넷 스플릿의 경우 테스트합니다.Distributed Erlang : multicall이 요청 된 시간 초과를 초과했습니다.

클러스터의 모든 노드에서 정보를 얻으려면 gen_server : multicall/4를 정의 된 시간 초과와 함께 사용하십시오. 필요한 것은 가능한 한 빨리 사용 가능한 노드에서 정보를 얻는 것입니다. 따라서 시간 제한은 너무 크지 않습니다 (약 3000ms). 여기 예 전화 :

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

나는이 호출이 돌아이 시간 초과 MS가 발생할 것으로 기대합니다. 그러나 넷 분할의 경우에는 그렇지 않습니다. 그것은 대략 기다린다. 8 초.

멀티 요청이 요청을 보내기 전에 erlang:monitor(process, {Name, Node})에 추가로 5 초 동안 중단 된 것을 발견했습니다.

는 정말 일부 노드가 응답하지 않거나 통화 중이거나 사용할 수없는, 내가 어떤 다른 사용할 수있는 상관 없어하지만이 정지와 나는 얼랑 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) }. 

아이디어는 모든 노드를 호출 한 제한 시간 내의 모든 결과를 기다리는 것입니다.

하나의 노드 호출은 생성 된 프로세스에서 수행됩니다. 오류가 발생한 경우 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. 

단일 읽기는 시간 초과가있는 사서함에서 수신됩니다.

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()는 두 번째 노드도 사용할 수 없다면 Timeout을 기다립니다. 2 * Timeout 등을 기다립니다. 하나의 Timeout 내에 도착한 모든 응답을 수집하려고합니다. 또한 잘 모르겠지만 rpc : async_call이 erlang : monitor (node)를 호출하여 메시지를 보내기도합니다. –

+0

업데이트 된 제안 사항을 확인하십시오. 초단 시간 제한을 사용하고 1 또는 충분한 결과가 나올 때까지 반복하십시오. 나는 완전한 해결책이 아니라 내가 일해야한다고 생각하는 방향을주고있다. 이것은 * 약속 *이기 때문에 아무것도 기대하지 않을 것입니다 - asynch_call/4가 즉시 반환되어야합니다. – Jr0