« Alexa(アレクサ)の統計データの問題点 | メイン | DecentURL : cool URLに短縮してくれるサイト »
2007年10月25日
PHPでメッセージキューを使う
先週、株式会社ノッキングオンの会議室で行なわれた第28回PHP勉強会で、飛び入りで10分ほど発表させていただいた話をこちらに起こすことにした。
発表の題は「PHPでメッセージキューを使う」。10分の発表なので一番基本的なサンプルまで。
もともと、Perl系の人たちが「TheShwartzいいよ」と盛り上がっていた夏頃に、ちょっとうらやましくなってPHPでメッセージキューを扱うソリューションを調べたもの。数ヶ月放置してたが、個々一番さんが「最近気になってる」というので、はなはだ初歩的なところまでしかわかってないけど説明した。
TheSchwartzのように、スクリプト言語とDBサーバでキューを実現するという意味だと、PHPではPEAR::Mail_Queueがメールのバッチ送信に特化しているけど近いみたい。ただこれは使ったことないので質については不明。
今回デモしたのは、メッセージキュー自体はJavaのオープンソースサーバを利用するというもの。
道具立てとしては、
- Apacheが出しているJMSの実装ActiveMQ
- CodehausのPHP版Stompライブラリ
の二つ。ActiveMQは、デフォルトでStompプロトコルもサポートしているので、Stompを話すコードを書くか、自分の使っている言語でStompライブラリを探せばよい。
Stompライブラリのほうは、SubVersionでのみ公開。一ファイルだし中身もとても短いが、PHPからActiveMQを(というかStompプロトコルに対応したサーバを)呼び出すことができるライブラリ。
ActiveMQのインストールと実行
Windowsの場合を書く。すごい簡単。
- Javaが入ってなければインストール
- ActiveMQダウンロードサイトから最新版(4.1.1)をダウンロード。zipを適当な場所に展開。(例: C:\work\apache-activemq-4.1.1)
- コマンドプロンプトで、展開した場所へcd
- cd bin
- activemq.batを実行 (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