金利0無利息キャッシング – キャッシングできます

 | 

2009-05-28

Gearman::Clientの非同期化

22:05 | Gearman::Clientの非同期化 - 金利0無利息キャッシング – キャッシングできます を含むブックマーク はてなブックマーク - Gearman::Clientの非同期化 - 金利0無利息キャッシング – キャッシングできます

Coro::Selectをuseしただけで非同期化した。すばらしい。

#!/usr/local/bin/perl

use lib qw(../lib/);
use Coro;
use Coro::Select;
use Gearman::Client;

my $work_count = 0;
for (1..5) {
    my $sleep_time = 5 - $_;
    async {
        my $client = Gearman::Client->new;
        $client->job_servers("127.0.0.1:4730");
        my $res = $client->do_task("sleep", $sleep_time);
        warn $$res;
        $work_count++;
    };
}

$w = AnyEvent->timer(
    after    => 0,
    interval => 1,
    cb       => sub {
        warn time;
        if ($work_count == 5) {
            exit;
        }
    }
);
schedule;

指定秒数sleepするworkerを作って複数立ち上げておく。workerが同時に実行されているのが分かる。

1243515805 at ./sleep-test.pl line 25.
 at 1243515805 at ./sleep-test.pl line 16.
1243515806 at ./sleep-test.pl line 25.
1 at 1243515806 at ./sleep-test.pl line 16.
1243515807 at ./sleep-test.pl line 25.
2 at 1243515807 at ./sleep-test.pl line 16.
1243515808 at ./sleep-test.pl line 25.
3 at 1243515808 at ./sleep-test.pl line 16.
1243515809 at ./sleep-test.pl line 25.
4 at 1243515809 at ./sleep-test.pl line 16.
1243515810 at ./sleep-test.pl line 25.

Coro::Selectを使わない場合。

4 at 1243515772 at ./sleep-test.pl line 16.
3 at 1243515775 at ./sleep-test.pl line 16.
2 at 1243515777 at ./sleep-test.pl line 16.
1 at 1243515778 at ./sleep-test.pl line 16.
 at 1243515778 at ./sleep-test.pl line 16.
FATAL: deadlock detected at ./sleep-test.pl line 0

PerlのDBIを非同期にしたい(MySQL限定編)

20:22 | PerlのDBIを非同期にしたい(MySQL限定編) - 金利0無利息キャッシング – キャッシングできます を含むブックマーク はてなブックマーク - PerlのDBIを非同期にしたい(MySQL限定編) - 金利0無利息キャッシング – キャッシングできます

信頼できる情報筋からいくつか有益な情報を受け取りましたので追加情報です。

Net::MySQL + kazuho okuパッチ

http://labs.cybozu.co.jp/blog/kazuho/archives/2007/09/mysql_async.php

Net::MySQLは株式会社ミクシィ技術顧問でありApacheモジュールプログラミングガイドの著者としても知られるさんによるPurePerlによるMySQLプロトコルの実装です。初期リリースは2002年であり、先見の明に驚かされます。僕は使いませんけど。

perl-mysql-async

これもMySQLPerlから自力で接続するクライアント。

http://code.google.com/p/perl-mysql-async/

Event::Libを使用、Craigslistで動作実績がある模様。

http://www.scribd.com/doc/15014388/MySQL-and-Search-at-Craigslist

最近見つけたmemcached関連のプロダクト

18:08 | 最近見つけたmemcached関連のプロダクト - 金利0無利息キャッシング – キャッシングできます を含むブックマーク はてなブックマーク - 最近見つけたmemcached関連のプロダクト - 金利0無利息キャッシング – キャッシングできます

http://code.google.com/hosting/search?q=label:memcached

Cache::Memcached::Tags

タグ関連のコマンドをサポートするようにパッチを当てたmemcachedと、そのクライアント。

http://code.google.com/p/memcached-tags/

http://search.cpan.org/dist/Cache-Memcached-Tags/

関連するitemにタグを付けておいて、まとめて消すことができる。

タグの情報はitemを保存しているのと同じサーバーに保存、delete_by_tagsは全サーバーに対して発行する。

Cache::Memcached::Managedみたいにムリヤリ保存するよりスマートだと思う。機会があれば使ってみたい。

memcache-top

top風にmemcachedの利用状況を表示。Perlで書かれている。

http://code.google.com/p/memcache-top/

似たようなコマンド、PHPで書かれている。

http://code.google.com/p/mctop/

1台ごとに表示できるので偏ってるのとかが分かる。

PerlのDBIを非同期にしたいメモ

14:52 | PerlのDBIを非同期にしたいメモ - 金利0無利息キャッシング – キャッシングできます を含むブックマーク はてなブックマーク - PerlのDBIを非同期にしたいメモ - 金利0無利息キャッシング – キャッシングできます

  • Coroを使うとselectをノンブロッキングに出来る。
  • DBD::なんちゃらはXSの中でブロッキングしてるからCoroの影響は及ばない。
  • MySQLの遅いクエリ、Q4Mのqueue_waitなどは依然としてブロッキングする。
  • DBDをPurePerlで書く → 馬鹿げている。*1

非同期化するために

  • 別プロセスにやらせる
  • RPCClientを非同期化する

という戦略がシンプルだろう。

POEの場合

POE::Component::EasyDBI*2の実装を見る

  • POE::Wheel::Run*3を使用
    • Wheel::Runはブロッキングするコードをsubprocessで実行するための仕組みである。
    • 別プロセスを立ち上げて、本体と通信、POE::Filter::Reference*4を使って結果を受け取る。

IO::Lambda::DBI*5

  • IO::Lambdaというなんか気合いの入ったモジュールの一部。
  • ブロッキングする処理を別スレッドにやらせる→IO::Lambda::Messageを使って結果を受け取る。
  • threadが有効なperlじゃないと使えない。

DBD::Proxy or DBD::Gofer

この辺り、あまり日本語の記事を見ない。

  • DBD::Proxy*6
    • DBI::ProxyServer*7を立ち上げておいて、それを経由して通信する。
    • thread(使えれば),fork,singleモードで動かすことが出来る。
    • RPC::PlServer/RPC::PlClientを使用している。
    • client-proxy間、proxy-DB間で、それぞれコネクションを維持する。(セッション中、同じコネクションを使う)
    • 非同期化する場合、RPC::PlClientを非同期化すればよいだろう。
  • DBD::Gofer*8
    • A stateless-proxy driver for communicating with a remote DBI とのこと。
    • DBD::Proxyと似ているがステートレスである。
    • DBI::Gofer::Transport::なんちゃら : プロキシサーバーみたいなもん。
    • DBD::Gofer::Transport::なんちゃら : ↑に対応するDBDドライバ。
    • 接続経路が限られている、コネクションプーリングしたい、リクエスト毎に何か処理を振り分けたい。
    • オンメモリのクエリキャッシュ機構がある(デフォルトオフ)。memcached対応したいねとかなんとか書いてある。
  • DBIにTransport::pipeoneとTransport::streamが標準付属
  • DBI::Gofer::Transport::pipeone
    • リクエスト毎にプロセスを立ち上げる。非効率である。
  • DBI::Gofer::Transport::stream
    • あらかじめサーバーを立ち上げておく。
  • ProxyとGoferの違い: Goferはステートレスである。
    • GoferTransporter-DB間はコネクションを維持する(最大コネクション数設定有り)。
    • clientとGoferTransporterの間はコネクションを維持しない。
    • 複数コネクションが張られていれば、1リクエストごとに違うコネクションが使われるだろう。

ステートレスの問題

例えばDBD::Gofer経由でQ4Mを使おうとした場合、

select queue_wait(test_queue, 10);
select * from test_queue;
select queue_end();

3つのSQL文が別のコネクションに対して発行される可能性があるので、上手く動かないだろう。一文で取れれば多分問題ない。 select * from test_queue WHERE queue_wait(test_queue, 10);

コネクションプーリングによる高速化

  • 例: mod_perlのプロセスが1000件あってDBが1台。
  • 1000プロセスがコネクションプーリング → max_connectionsデフォルト100件。
  • 1. コネクション数増やす: 増やしすぎるとパフォーマンス劣化。
  • 2. コネクションプーリングしない: 1リクエスト毎に切断する。
  • 3. DBD::Goferを使用
    • 50件がコネクションプーリングしてリクエストを代理で処理。
    • コネクションプーリングによる速度向上がプロキシによる遅延を上回れば、高速化する。
    • gearmanの場合: 遅延 = Gearmand + Gearmanworker + Storable(freeze/thaw)

Coroによるブロッキングの解除

  • DBI::Gofer::Transport::http使う場合はCoro::LWPがうまいことやってくれるはず。
  • Transport::gearman使う場合も、Gearman::Clientのwait中にブロッキングしないようにすれば良いだけ。
  • Coro::LWPの要領で、元のコードに変更を加えることなくソケット通信だけを非同期処理にすることが可能。
    • ただし予想外のバグが発生する可能性はある。例えば、グローバルに何かをキャッシュしていたりする場合。
    • あり得ない実装だけど、例えば受信バッファがグローバル変数になってればデータが混ざる。

メモ終わり。

トラックバック - http://subtech.g.hatena.ne.jp/mala/20090528
 |