« Alexa(アレクサ)の統計データの問題点 | メイン | DecentURL : cool URLに短縮してくれるサイト »

2007年10月25日

PHPでメッセージキューを使う

先週、株式会社ノッキングオンの会議室で行なわれた第28回PHP勉強会で、飛び入りで10分ほど発表させていただいた話をこちらに起こすことにした。

発表の題は「PHPでメッセージキューを使う」。10分の発表なので一番基本的なサンプルまで。

もともと、Perl系の人たちが「TheShwartzいいよ」と盛り上がっていた夏頃に、ちょっとうらやましくなってPHPでメッセージキューを扱うソリューションを調べたもの。数ヶ月放置してたが、個々一番さんが「最近気になってる」というので、はなはだ初歩的なところまでしかわかってないけど説明した。

TheSchwartzのように、スクリプト言語とDBサーバでキューを実現するという意味だと、PHPではPEAR::Mail_Queueがメールのバッチ送信に特化しているけど近いみたい。ただこれは使ったことないので質については不明。

今回デモしたのは、メッセージキュー自体はJavaのオープンソースサーバを利用するというもの。

道具立てとしては、

の二つ。ActiveMQは、デフォルトでStompプロトコルもサポートしているので、Stompを話すコードを書くか、自分の使っている言語でStompライブラリを探せばよい。

Stompライブラリのほうは、SubVersionでのみ公開。一ファイルだし中身もとても短いが、PHPからActiveMQを(というかStompプロトコルに対応したサーバを)呼び出すことができるライブラリ。

ActiveMQのインストールと実行

Windowsの場合を書く。すごい簡単。

これで、設定ファイル conf/activemq.xml の設定でActiveMQが動く。ローカルで実験するだけならそのままのactivemq.xmlでも動いた。

PHP Stompライブラリの準備

php.ini の以下を有効にしてsocket関数を使えるようにしておく。

extension=php_sockets.dll

PHP5だったら、SubVersionから取ってきたままのStomp.phpでは古い書き方のせいで警告が出る箇所が有るので、それらは3箇所の "&$" を "$" に置き換えれば消えると思う。

あとは、Stomp.phpをinclude_pathに置くなどして、requireできるようにしておく。

PHP Stompライブラリを呼び出す生産者スクリプトを書く

ライブラリファイルStomp.phpが呼べる状態になっているとして、Publisher側はこんなコード。

<?php

/** キューの生産側サンプル */

// ライブラリ読み込み
require_once 'Stomp.php';

// ローカルホストのStompサーバに接続
$connection = new StompConnection("localhost");
// TBA: エラー処理。ライブラリ中でdieしてるのでライブラリも要修正

// 接続パスワードは今は何でも通し
$handler = $connection->connect("akky", "dummypassword");
// TBA: エラー処理
//print_r($handler);

// メッセージを作る
$message = "Hello World! The time is " . date("h:i:s");

// キューの識別子を与えて、メッセージを送る
$connection->send("/queue/miaumiau", $message);

echo "I've sent [$message]!\n";

// 接続を切る
$connection->disconnect();
?>

これを、

  • php Publisher.php

と実行すると、キューにメッセージを投げる。2回呼べば2つ投げる。

PHP Stompライブラリを呼び出す消費者スクリプトを書く

消費側はこんな感じで。

<?php

/** キューの消費側サンプル */

// ライブラリ読み込み
require_once 'Stomp.php';

// ローカルホストのStompサーバに接続
$connection = new StompConnection("localhost");
// TBA: エラー処理。ライブラリ中でdieしてるのでライブラリも要修正

// 接続パスワードは今は何でも通し
$handler = $connection->connect("akky", "dummypassword");
// TBA: エラー処理
//print_r($handler);

// キューの識別子を与えて、メッセージを受ける
$connection->subscribe("/queue/miaumiau");

// 無限ループで受信を続ける
while (true) {
    // キューから一個取得
    $gottenFrame = $connection->readFrame();
    //print_r($gottenFrame);

if (array_key_exists('message-id', $gottenFrame->headers)) {
// 受け取り確認を発行
$connection->acknowledge($gottenFrame->headers["message-id"]);
echo "Received [" . $gottenFrame->body . "]\n";
} else {
// 何かが変
echo "invalid frame\n";
break;
}
// サンプルはぐるぐる回してもいいけど、まあ適当な間隔で処理するイメージ
sleep(1);
}


// 接続を切る
$connection->disconnect();
?>

こっちを、別のシェル/コマンドプロンプトを開いて、

  • php Subscriber.php

と実行すると、キューにメッセージがあれば取り出して表示する。Subscriber.phpを起動したままでPubslisher.phpを起動すれば、キュー経由でメッセージが届いていることも確認できる。

実運用では、エラー処理をして、アクセスに認証をかけ、キューのIDを分けることでたくさんのキューを同時に扱い、localhostじゃなくて別サーバに分けて、みたいにいろいろとやることはあると思う。

CodehausのStompプロトコルのサイトでは、Codehausのものや他のものも含めて、いろいろな言語でのStompクライアントライブラリの情報が載っている。C/C++/C#&.NET/Delphi/Flash/Java/Perl/PHP/Pike/Python/Ruby/Smalltalkなど。

なので、Webアプリケーションの場合でも、ユーザからの入力によって発生したバックエンド側への指示をメッセージとしてActiveMQに投げることで、まったく別の言語のバックエンドと連携させることができそうだ。キューサーバーは別マシンにも置けるので、複数台に処理を分散させるときにも使える場合があるだろう。

僕は職業Javaプログラマじゃなくなってから何年も経っているので、ActiveMQという選択が今妥当なのか、ActiveMQの実運用性とかどこまで捌けるのか、とかはわかってない。Javaの詳しい人の突っ込みをお待ちしている。

ActiveMQは出力をRSSにしたりという機能もあるようで、

また、PHP勉強会での発表後に、興味あるのでうちでも遊んでみる、という声も聞いたので、負荷実験とか実サービスへの適用試行とかやってくれれば、僕もぜひ、どんなもんか聞きたいと思っている。

[参考]

Javaの理論と実践: 次期エンタープライズ・アプリケーションにJMSの採用を

メッセージキュー自身の解説と、使いどころの例示がある。

PHPからAmazon Web ServiceのSQSを使う

有料だけど自分でメッセージキューサーバの管理しなくて済む。

投稿者 秋元 : 2007年10月25日 15:16

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1617

 
mg src="http://img.awasete.com/image.phtml?u=http%3A%2F%2Flabs.cybozu.co.jp%2Fblog%2Fakky%2F" width="160" height="140" alt="あわせて読みたい" border="0">

著書

PHPxWebServiceAPIConnections.jpg

プロフィール

週三日勤務で、残りは個人で活動しています