« サーバシグニチャは隠さないのが当たり前 | メイン | swifty-0.02 と Perl バインディング »

2007年09月10日

Perl から MySQL に非同期アクセスする方法

mod_perl のプロセス内でやるのに POE でイベントループ回せ、ということ? もうちょいkwsk! > b:id:kazuhooku
naoyaグループ - naoyaの日記 - 非同期SQLサーバ

 エントリ全体の趣旨はさておき、ソケット通信を非同期化するためにまた別のソケット通信を行うという使用例に違和感を覚えたのですが、回避策としてブクマコメントで提示した POE::Component::EasyDBI も内部で fork (&プロセス間通信) してるんですね。変なコメントしてごめんなさい忘れてください。って、それだけではなんなので...

 ここから本題。

 私はそういうケースに遭遇したことはないのですが、大規模なサービスでは、複数の SQL クエリを同時実行したり、あるいは、時間がかかるクエリを実行中に他の処理を行ったりしたくなる、ということがあるかもしれません。ですが、DBI にはクエリを非同期実行するための仕組みがないようです。というわけで、Net::MySQL で非同期クエリを可能にするパッチを書いてみました。

 このパッチを適用すれば、MySQL へ非同期にアクセスできるようになります (下の例を参照)。また、クエリの実行が完了したかを知りたい場合は、response_is_ready(0.1) のようにタイムアウト値をセットして呼び出すこともできます。

use Net::MySQL;

# サーバに接続して、非同期モードに設定
my $my_async = Net::MySQL->new(
    database => '********',
    user     => '****',
    password => '********',
    async    => 1,
);

# クエリを実行開始
$my_async->query(q{select ...});

# その他の処理を行う
...

# クエリの実行完了まで待機
while (! $my_async->response_is_ready()) {
}

# レスポンスを処理
$my_async->handle_response() or die $my_async->get_error_message;
my $record_set = $my_async->create_record_iterator;
while (my $record = $record_set->each) {
    ...
}

 同一プロセス、同一スレッド内で非同期処理を実現するメリットは、言うまでもなく、演算量やメモリ消費を抑えることができる点にあります。また、システムを構成する部品の数が減ることで、メンテナンスが容易になるということもあるかもしれません。重たいクエリを非同期化するだけであれば、fork したりサーバプロセスを別途用意したりしてもかまわないと思いますが、より柔軟な方法としてはこういうものもあるよ、ということでご理解いただければ幸いです。

投稿者 kazuho : 2007年09月10日 10:54 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク

トラックバック

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