7

設定:

erlang クラスターで一意のグローバル登録 gen_server プロセスを開始したいと考えています。プロセスが停止した場合、またはプロセスを実行しているノードがダウンした場合、プロセスは他のノードのいずれかで開始されます。

プロセスはスーパーバイザーの一部です。問題は、gen_server がすでに実行されており、最初のノードからグローバルに登録されているため、2 番目のノードでスーパーバイザーを起動できないことです。

質問:

  • プロセスが gen_server の start_link 関数内で既にグローバルに登録されているかどうかを確認しても問題ありませんか? この場合{ok, Pid}、新しい gen_server インスタンスを起動する代わりに、既に実行中のプロセスを返しますか?
  • このようにして、1 つのプロセスが複数のスーパーバイザーの一部になり、1 つのプロセスがダウンした場合、他のすべてのノードのすべてのスーパーバイザーがプロセスを再起動しようとするのは正しいですか。最初のスーパーバイザーは新しい gen_server プロセスを作成し、他のスーパーバイザーはすべてその 1 つのプロセスに再度リンクします。
  • global:trans()gen_server の start_link 関数内である種のものを使用する必要がありますか?

コード例:


start_link() ->
    global:trans({?MODULE, ?MODULE}, fun() ->
        case gen_server:start_link({global, ?MODULE}, ?MODULE, [], []) of
            {ok, Pid} -> 
                {ok, Pid};
            {error, {already_started, Pid}} ->  
                link(Pid), 
                {ok, Pid};
            Else -> Else
        end     
    end).

4

2 に答える 2

6

リンクしていないものの{ok、Pid}を返すと、戻り値に依存するスーパーバイザーが混乱します。スーパーバイザーにこれをstart_link関数として使用させる予定がない場合は、これを回避できます。

グローバルインスタンスが停止した場合、各ノードが新しいインスタンスを開始しようとするため、アプローチは機能するはずです。MaxRクラスタのメンバーが変更されるたびにプロセスメッセージが表示されるため、スーパーバイザの設定で値を増やす必要がある場合があります。

過去にグローバルシングルトンを作成した1つの方法は、すべてのノードでプロセスを実行することですが、そのうちの1つ(グローバル登録レースに勝ったノード)をマスターにします。他のプロセスはマスターを監視し、マスターが終了したら、マスターになろうとします。(そして、彼らが登録レースに勝てなかった場合、彼らは勝ったもののpidを監視します)。これを行う場合は、グローバル名の登録を自分で処理する必要があります(つまり、gen_server:start({global, ...機能を使用しないでください)。登録に勝ったかどうかに関係なくプロセスを開始する必要があるため、それぞれの場合で動作が異なります。

プロセス自体はより複雑である必要があります(マスターモードと非マスターモードの両方で実行する必要があります)が、迅速に安定し、スーパーバイザーの開始試行で大量のログスパムを生成しません。

私の方法では、通常、コーナーケースを取り除くために数回の修正が必要ですが、OTP分散アプリケーションを作成するよりも面倒ではありません。この方法には、クラスターに含まれるノードのリストを静的に構成する必要がないという点で、分散アプリケーションに比べて別の利点があります。どのノードも、プロセスのマスターコピーを実行する候補になる可能性があります。あなたのアプローチにはこれと同じ特性があります。

于 2010-12-16T19:59:15.897 に答える
4

gen_server をアプリケーション化し、分散アプリケーションを使用するのはどうですか?

于 2010-12-16T12:25:10.787 に答える