8

私は PHP アプリを作成しましたが、API を呼び出したり、時間のかかる操作を実行したりするときに、「ワーカー」+ キュー サーバーを使用するのがベスト プラクティスであることを読みました。

チュートリアルをすばやく検索すると、ドライになってしまいました。私は codeigniter を使用してアプリを構築しました。Facebook API にさまざまな呼び出しを行い、アプリ全体で php ベースの画像操作を使用しています。私が疑問に思っている唯一のことは、API呼び出しを実行したり、画像のサイズを変更したりしている場合、キューサーバー+ワーカーがどのように役立つかということです。ユーザーは通常、完了するまでサーバーからの応答を気にしません。

ワーカー + キュー サーバーの候補として適しているのはどのような状況ですか?また、これらをアプリケーションに含めるためのガイドはありますか? 最近、アプリに memcache を含めましたが、これは簡単でした。SQL クエリを memcache ハンドラでラップしただけです。

4

2 に答える 2

8

説明した例(画像のサイズ変更)では、基本的に、画像のサイズ変更にかかる時間の間、Apache接続を開いたままにします。Apache プロセスはコストがかかるため、システムをできるだけスケーラブルにするために、Web 要求/応答をできるだけ短くすることを目指す必要があります。もう 1 つのアイデアは、キューを使用すると同時実行性を制御できるということです。100 人以上のユーザーが同時にサイズ変更する画像をアップロードするとどうなりますか? あなたのサーバーはそれを処理できますか?これらのリクエストを処理するワーカー (バックエンド) サーバーがある場合、X 個の同時ジョブのみの実行を許可できます。

同じことが Web サービス要求にも当てはまります。接続を開いたままにする代わりに、基本的に Web サービス呼び出しの実行をワーカー プロセスにオフロードします。これにより、Apache プロセスが解放され、AJAX ポーリング メカニズムを実装して、バックエンド サーバーが Web サービスに発行したリクエストが完了しました。長期的には、システムはより適切にスケーリングされます。ユーザーは通常、操作がどこにあるのかについてのフィードバックがない状態で操作が完了するのを待ちたくありません。キューイングを使用すると、タスクを非同期に実行し、訪問者にタスクの完了ステータスに関するフィードバックを提供できます。

私は通常、Zend Server フル エディション (商用版) で利用できる Zend Server のジョブ キュー ( http://devzone.zend.com/article/11907およびhttp://devzone.zend.com/article/11907 ) を使用します。ただし、Gearman はそれを行うのにも優れており、PHP 拡張機能があります: http://php.net/manual/en/book.gearman.phpと例: http://www.php.net/manual/en/ gearmanclient.do.php

お役に立てれば。

- 編集 -

@Casey、コメントの追加を開始しましたが、これはすぐに回答が長くなりすぎることに気付いたので、代わりに回答を編集しました。知らなかったサービスであるクラウド コントロールのドキュメントを読みました。ただし、幸運なことに、私は Codeigniter をかなり広範囲に使用しているので、答えをハックしようとします。

1- Cloudcontrol のワーカーの概念は、コマンド ラインから php スクリプトを起動することです。そのため、Codeigniter がコマンド ラインからスクリプトを起動し、コントローラーにディスパッチすることを受け入れる方法が必要です。おそらく、それを 1 つのコントローラーに制限したいと思うでしょう。次のコードを参照してください: http://pastebin.com/GZigWbT3 このファイルは、設定を通じてリクエストをエミュレートすることを除いて、本質的に CI の index.php ファイルと同じことを行います$_REQUEST['SERVER_URI']。そのファイルをドキュメント ルートの外に配置し、$system_folderそれに応じて変数を調整してください。

2-コントローラーフォルダーにコントローラーscript.phpが必要です。そこからWebリクエストを無効にします。次の効果を得るために何かを行うことができます。

<?php
class script extends CI_Controller {
    public function __construct() {
        if(php_sapi_name() !== 'cli') {
            show_404();
        }
        parent::__construct();
    }

    public function resizeImage($arg1, $arg2) {
        //Whatever logic to resize image, or library call to do so.
    }
}

3- 最後のピースは、CloudController のワーカー呼び出しの機能を効果的にラップする CI (system/application/libraries フォルダー内) でラッパー ライブラリを開発することです。

    public function _construct() {
        $ci = get_instance();

        //add check to make sure that the value is set in the configuration
        //Ideally since this is a library, pass the app_name in a setter to avoid creating a dependancy on the config object.
        //Somewhere in one of your config files add $config['app_name'] = 'YOUR_APP_NAME/YOUR_DEP_NAME';
        //where APP_NAME and DEP_NAME are cloud controller's app_name and dep_name
        $this->_app_name = $ci->config->item('app_name');

        //Also add: $config['utilities_script'] = 'path/to/utilities.php';
        //This is the script created in step 1
        $this->_utilities_script = $ci->config->item('utilities_script');
    }

    public function run() {
        $args = func_get_args();
        if(count($args) < 1 ) {
            //We expect at least one arg which would be the command name
            trigger_error('Run expects at least one argument', E_USER_ERROR);
        }

        $method = array_shift($args);

        //utilities.php is the file created in step 1
        $command = "cctrlapp " . $this->_app_name . " worker.add ".$this->_utilities_script;

        //Add arguments if any
        $command .= ' "'.implode(' ', $args).'"';

        //finally...
        exec($command);
    }
}

4-コントローラーからの場合、実際にジョブをキューに入れたいコードのどこからでも:

$this->load->library('Worker');
//resizeImage will call the method resizeImage in the script controller.
$this->worker->run('resizeImage', $width, $height);

次の点に注意してください: 1- これはさらに洗練された ものになる可能性があります。
実際には、それをどのように実行できるかについてのアイデアを提供するためのものでした。
プロジェクトで使用する utility.php スクリプトなので、これで十分です。
幸運を!

于 2011-08-30T21:38:57.560 に答える
3

専用のワーカー/キュー サーバーのセットアップが必要ない場合は、単純な作業キューを管理するための codeigniter インストール用の小さなライブラリを作成できます。

最初のクライアント要求時に、生成されたイメージまたはキャッシュ内のリモート ファイルを (再) 生成する必要がないことを確認し、ファイルを提供します。ファイルまたはイメージをビルドする必要がある場合は、キュー ライブラリにそれをキューに追加するように指示してから、ブラウザへの接続を閉じます。ただし、同じリクエスト中に、コントローラーの最後でキューを処理します。この方法では、別のキューとワーカー サーバーは必要ありません。

私にとって、 http://www.php.net/manual/en/features.connection-handling.phpのコメントは非常に役に立ちました。基本的に次のようなことを行います: (概念実証、詳細はリンクを参照)

header("Connection: close\r\n");  // close the connection
ob_end_flush();                   // flush everything
ob_flush();
flush();

set_time_limit(300);              // set a nicer time-out for the queue-worker
$this->queue_lib->process();      // do processing
sleep(5);                         // or get some of that much needed sleep
echo 'Text user will never see';

開発中およびデバッグ中は、close-connection 部分を一時的に無効にして、出力を確認できます。本番環境では、log_message() を使用できます。

キュー ライブラリ機能(コーダー/自己へのメモ) : ファイルをキューに追加するとき、キュー ライブラリは、ファイルが既にキューにあるかどうかを確認する必要があります。このセットアップでは、ワーカーは非同期で実行されるため (多くの異なるブラウザー接続)、ワーカーがジョブの処理を開始するとき、ジョブのステータスを「処理中」などに設定して、他のワーカーが同じジョブで作業を開始しないようにする必要があります。 . または、キュー全体のステータスを「queue-is-processing」(一度に 1 つのワーカー) に設定して、順次キューを設定することもできます。ジョブ (またはキュー全体) のタイムアウトもおそらく良い考えであり、タイムアウトは set_time_limit() より少し大きくする必要があります。このようにして、ジョブがいつ失敗したかを知り、エラー ログを更新できます。キューのクリーンアップを早い段階で処理して、それらが処理され、タイムアウトにならないようにします。

: 同じリンク先のページから、ローカル ファイル システムのファイルを操作すると同時に、ignore_user_abort(true) または register_shutdown_function() を使用する場合は、最初に作業ディレクトリを保存するのが賢明と思われます。$cwd = getcwd();

編集:
ジョブ ライブラリの適切な出発点を見つけました: http://www.andy-russell.com/job-scheduler-library

于 2012-03-11T14:02:55.547 に答える