LoginSignup
16
17

More than 5 years have passed since last update.

RabbitMQ + php-amqplib でメッセージキューイング試してみた

Last updated at Posted at 2016-02-18

動機と背景

下記のような理由から、RabbitMQでメッセージキューイングを試してみたので、記録として残しておきます。

  • PHP + Silex(Symfony2.3+)で、BtoBtoCなWebアプリケーションを開発・運用している
  • 管理画面で時間のかかる処理がある(CSVファイルのダウンロードなど)
  • データベースに、キューイング用のテーブルを作って、cronで一定間隔でキューがあるかチェックする、というような実装をしている
  • cron使いたくない(1分おきに実行とかなんとなく)
  • もっと汎用的な仕組みに置き換えたい

RabbitMQ

メッセージキューイングで調べると下記のようなライブラリが見つかります。

チームのエンジニアに意見を聞いて、RabbitMQは使いやすかったということだったので、試してみることにしました。

php-amqplib

RabbitMQのClients and Developer Toolsを見ると、PHP用のライブラリがいくつかあります。
ただ、公式のtutorialを見ると、php-amqplibが使われているので、これを採用しました。

CUI版のexampleを作成

ほぼほぼ、tutorialにしたがって、CUI版のexampleを作りました。
https://github.com/imunew/php-rabbitmq-example

ざっとポイントを列挙すると、以下のようになります。

  • vagrant + ansible で実行環境構築を自動化
  • コンソールを2つ起動し、1つは受信用、1つは送信用として使う
  • 送信側でスクリプトを実行すると、受信側にメッセージが表示される

GUI(Web)版のexampleを作成

次に、GUI(Web)版を実装してみました。
https://github.com/imunew/silex-rabbitmq-example

より実戦に近いイメージで、実装をしてみました。
CUI版との違いを列挙すると、以下のようになります。

  • supervisorで受信側スクリプトを常駐化(デーモン化)
  • redisを経由して、処理結果を画面側に渡すようにした
  • 重たい処理はusleep(1000000);を10回実行することで再現

ハマったところ

メッセージをどう管理するか

複数のメッセージを非同期で扱うことになるので、一つ一つのメッセージがそれぞれユニークになる必要があります。
exampleでは、画面表示したときに、md5(time())でハッシュを作り、それをメッセージのIDとするようにしました。

// src/controllers.php
$app->get('/example', function (Request $request) use ($app) {
    $result = $request->get('result', []);
    /** 
     * 初期表示のときに、md5(time())でハッシュが作られ、それがメッセージのIDとなる
     */
    $hash = $request->get('hash', md5(time()));
    $startTime = $request->get('startTime', '');
    $endTime = $request->get('endTime', '');
    return $app['twig']->render('app/example.html.twig', [
        'result' => $result,
        'hash' => $hash,
        'startTime' => $startTime,
        'endTime' => $endTime,
    ]);
})
;

supervisorのセットアップ

正直ハマりましたw。
yumでインストールすると、2.x系がインストールされるので、easy_installから(3.x系を)インストールします。
supervisordコマンドで常駐化するというのも、はじめ分かりませんでした。
最終的には、ansibleに手順がまとまっていますので、参照ください。

ansible/roles/supervisor/tasks/main.yml

使いどころや課題など

チームで話し合って実戦投入するか決めたいと思いますが、なんとなく課題になりそうなところを想像してみました。

  • 使いどころ
    • 重たいドキュメント系処理(CSV、PDF出力)
    • メール送信(spoolしておいて非同期に送信)
  • 非同期にするだけで、単純に実装の難易度あがる
    • いい感じにパッケージ化してあげないと、オレオレな実装が増えそう
  • 受信側プロセスをどこで動かすか
    • 各Webサーバーに分散するか、中央集権的なサーバーを作るか
    • どこで処理しても、結果を受け取れなければいけない

実戦で投入したら、記事を更新しようと思います。
exampleの実装などで、ご意見ご感想ありましたら、githubでpull-requestやissueください。
もちろん、本投稿にコメントいただいても結構です。

16
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
17