9

一部のコードを OTP アプリに変換するときに、OTP 開発モデルを理解するのに少し苦労しています。

私は基本的に Web クローラーを作成していますが、実際の作業を行うコードをどこに置くべきかよくわかりません。

ワーカーを開始するスーパーバイザーがあります。

-behaviour(supervisor).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

init(_Args) ->          
  Children = [
    ?CHILD(crawler, worker)
  ],  
  RestartStrategy = {one_for_one, 0, 1},
  {ok, {RestartStrategy, Children}}.

この設計では、クローラー ワーカーが実際の作業を担当します。

-behaviour(gen_server).

start_link() ->
  gen_server:start_link(?MODULE, [], []).

init([]) ->
  inets:start(),        
  httpc:set_options([{verbose_mode,true}]), 
  % gen_server:cast(?MODULE, crawl),
  % ok = do_crawl(),
  {ok, #state{}}.

do_crawl() ->
  % crawl!
  ok.

handle_cast(crawl}, State) -> 
  ok = do_crawl(),
  {noreply, State};

do_crawlは、http を介したクロール作業を処理するかなり多数のプロセスとリクエストを生成します。

質問は最終的に次のとおりです。実際のクロールはどこで行われるべきですか? 上で見たように、私は実際の作業をトリガーするさまざまな方法を試してきましたが、物事を組み合わせる方法を理解するために不可欠な概念がまだいくつか欠けています。

注: OTP 配管の一部は簡潔にするために省略されています。配管はすべてそこにあり、システムはすべて一緒にハングします。

4

3 に答える 3

12

質問が間違っていたら申し訳ありません。

あなたを正しい方向に導くために私ができるいくつかの提案(または私が正しい方向であると考えるもの:)

1 (かなりマイナーですが、それでも重要です) そのワーカーから inets スタートアップ コードを取得し、それをアプリケーション スタートアップ コード (appname_app.erl) に配置することをお勧めします。私が知る限り、鉄筋テンプレートを使用しているので、それらを用意する必要があります。

2 さて、肝心の部分です。OTP のスーパーバイザーモデルを最大限に活用するには、多数のクローラーを生成する必要があると仮定すると、one_for_one の代わりに simple_one_for_one スーパーバイザーを使用するのが理にかなっています( http : //www.erlang .詳細についてはorg/doc/man/supervisor.htmlを参照してください。ただし、重要な部分は次のとおりです。そのため、監督するプロセスを 1 つだけ起動する代わりに、実際のジョブを実行しているワーカー プロセスを開始する方法について、ある種の「テンプレート」を実際に指定します。その種のすべての労働者はSupervisor:start_child/2http://erldocs.com/R14B01/stdlib/supervisor.html?i=1&search=start_chi#start_child/2 . これらのワーカーは、明示的に開始するまで開始されません。

2.1 クローラーの性質によっては、ワーカーに必要な再起動戦略の種類を評価する必要がある場合があります。現在、テンプレートでそれを永続的に設定しています (ただし、別の種類の監視対象の子がいます)。オプションは次のとおりです。

 Restart defines when a terminated child process should be restarted. A permanent child process should always be restarted, 
 a temporary child process should never be restarted and a transient child process should be restarted only if it terminates 
 abnormally, i.e. with another exit reason than normal.

したがって、次のようなものが必要になる場合があります。

 -behaviour(supervisor).
 -define(CHILD(I, Type, Restart), {I, {I, start_link, []}, Restart, 5000, Type, [I]}).

 init(_Args) ->          
     Children = [
          ?CHILD(crawler, worker, transient)
     ],  
     RestartStrategy = {simple_one_for_one, 0, 1},
    {ok, {RestartStrategy, Children}}.

この種のワーカーにとっては理にかなっているので、私はこれらの子供たちに一時的な再起動を提案する自由を取りました(ジョブを実行できなかった場合は再起動し、正常に完了した場合は再起動しません)

2.2 上記の項目を処理すると、スーパーバイザーは動的に追加された任意の数のワーカー プロセスを処理します。そして、それらのそれぞれを監視し、(必要に応じて) 再起動します。これにより、システムの安定性と管理性が大幅に向上します。

3 さて、ワーカープロセスです。各クローラーには、特定の瞬間にある特定の状態があると思います。そのため、gen_fsm (有限状態マシン、詳細についてはhttp://learnyousomeerlang.com/finite-state-machinesを参照) を使用することをお勧めします。このように、スーパーバイザーに動的に追加する各 gen_fsm インスタンスは、init/1でそれ自体にイベントを送信する必要があります( http://erldocs.com/R14B01/stdlib/gen_fsm.html?i=0&search=send_even#send_event/2を使用) )。

次の行だけで何か:

   init([Arg1]) ->
       gen_fsm:send_event(self(), start),
       {ok, initialized, #state{ arg1 = Arg }}.

   initialized(start, State) ->
       %% do your work
       %% and then either switch to next state {next_state, ...
       %% or stop the thing: {stop, ...

特定のニーズに応じて、作業をこの gen_fsm プロセス内に含めることも、別のプロセスを生成することを検討することもできます。

必要に応じて、クロールのさまざまなフェーズに複数の州名を付けたい場合があります。

いずれにせよ、これがアプリケーションを OTP っぽい方法で設計するのに役立つことを願っています。ご不明な点がございましたら、お気軽にお問い合わせください。必要に応じて追加させていただきます。

于 2011-03-12T11:47:11.400 に答える
4

実際に gen_server の状態を追跡していますか?

答えが「はい」の場合、あなたは正しい方法で物事を進めているように見えます。メッセージはシリアル化されるため、上記の実装では 2 つのクロールを同時に実行できないことに注意してください。同時クロールが必要な場合は、こちらの質問への回答を参照してください

答えが「いいえ」の場合は、サーバーとスーパーバイザーを捨てて、ここで見られるように初期化コードにアプリケーション モジュールを使用することができます。

最後に、lhttpcibrowseは inets に代わる優れた方法と考えられています。広告サーバーの本番環境で lhttpc を使用していますが、うまく機能します。

于 2011-03-11T23:48:00.687 に答える
3

この問題に対する私の解決策は、Erlang Solutions の「ジョブ」アプリケーションを調べることです。これは、ジョブのスケジュール (つまり、ページの要求) に使用でき、別のシステムに各ジョブを処理させたり、同時実行性を制限したりすることができます。

次に、新しい URL をプロセスにフィードしてcrawl_sched_mgr、URL をフィルタリングし、新しいジョブを生成できます。リクエスタに自分でこれを行わせることもできます。

ジョブを使いたくない場合は、ユリイの提案が最適です。

于 2011-03-12T16:43:10.373 に答える