2007年9月アーカイブ

例のGearmanのあれですが、naoyaさんが調べてくれてます(GearmanのやつGearmanのやつ#2)。

とりあえず、問題となる箇所をsysread()ではなく、recv()でMSG_WAITALLをすることにより64kb以上のデータでも問題のなく取得できることを確認しました。すげー。

変更は下記のような感じにしました。ほぼnaoyaさんが書いた修正案そのままです。

--- Util.pm.old 2007-06-30 06:40:24.000000000 +0900
+++ Util.pm.new 2007-09-29 13:55:10.278878000 +0900
@@ -1,6 +1,7 @@

 package Gearman::Util;
 use strict;
+use Socket; # for MSG_WAITALL

 # I: to jobserver
 # O: out of job server
@@ -100,8 +101,10 @@
     return $err->("malformed_magic") unless $magic eq "\0RES";

     if ($len) {
-        $rv = sysread($sock, $buf, $len);
-        return $err->("short_body") unless $rv == $len;
+        $rv = recv($sock, $buf, $len, MSG_WAITALL);
+        die $! if not defined $rv;
+        my $buflen = length $buf;
+        return $err->("short_body") unless $buflen == $len;
     }

     $type = $cmd{$type};

まぁ、あと問題なのはnaoyaさんが書いている通り、$lenに不正に大きい値を入れられた時の処理や、これを修正したことによるGearman全体でのバランスとかパフォーマンスなどがどの程度影響を受けるのかといったところでしょうか。

今度はパフォーマンス的にどうなのか、他に影響がないのかなどを調べてみたいと思います。
最近Gearmanを使っていてわかったのですが、Gearmanでは64kbぐらい(ぐらいっていう曖昧な表現なのは、毎回そうとは限らないから)のデータをworkerに投げると、うまく処理できないようです。うまく処理できないというかデータが欠損してしまうようです。

なんでなのか調べてみると、Gearman::Utilのread_res_packet()という関数の下記の部分で、clientから投げられたデータを全て取得できていないというのがわかりました。

     if ($len) {
         $rv = sysread($sock, $buf, $len);
         return $err->("short_body") unless $rv == $len;
     }
この部分の$lenは、clientから投げられたデータ(パケット)のヘッダーから取得したもので、workerに送られてきたデータ長になります。で、$rvにはsysreadで読み込んだデータ長が入るのだが、その$lenと$rvの長さが違うためにshort_bodyのエラーになってしまっているのです。

実際にどのくらいのデータ欠損があるのかというと、試しに以下のworker.plを立ち上げて、task.plで処理の依頼をworkerに投げた際の$lenと$rvは、$lenは65554byte、$rvは65524byte(ヘッダーと合わせると65536byte = 64kb)となっていました。ただ、この取得できるバイト数というのは毎回こうではなく、場合によって違うようです。64kb満たない場合でもデータがある程度大きいと起るようです。
#!/usr/local/bin/perl
# worker.pl

use strict;
use Gearman::Worker;

my $worker = Gearman::Worker->new;
$worker->job_servers(qw(127.0.0.1));
$worker->register_function(
    test => sub {
        return "this is test";
    },
);
$worker->work while 1;
#!/usr/local/bin/perl
# task.pl

use strict;
use Gearman::Client;

my $client = Gearman::Client->new( job_servers => [ qw(127.0.0.1) ] );
my $tasks = $client->new_task_set;
$tasks->add_task(
    "test" => 'a' x (1024 * 64),
    {
        on_complete => sub { my $ref = shift; print $$ref, "\n" },
        on_fail     => sub { warn "failed\n" },
    },
);
$tasks->wait( timeout => 10 );

print "done.\n";
もしかしたらclientが全部データを投げる前にsysreadを始めちゃってるのかな?と思ったので、Gearman::Utilのread_res_packet()の処理の前にsleepをいれてデータを待つようにしてやったら、なんと全部のデータが取れたりする(これも必ず取れるわけではないのはタイミングの問題かな)ので、全部のデータがworkerに届いてないうちに、sysreadが走っているような気がします。

もう1つ気になっているのが、tcpのパケットのサイズ制限が64kbだからなのかな?と思い、socketの設定で1パケットの送受信の長さが変えられる SO_RCVBUF と SO_SNDBUF を多めに変更してみたのですが、それでもうまく動かないっぽいので、それだけの問題でもないようです。

ということで、どちらにしても今のところGearmanでは64kbぐらい大きいデータは扱わない方がいいみたい。

もしこのデータが欠損してしまう問題の解決方法をご存知の方がいましたら、ぜひ教えてください><

ustreamには録画機能がありますよね。
先日開催されたモバイル勉強会でも録画したものが公開されていたりします。

この録画されたもの(flv形式のファイル)をダウンロードすることができれば、それをmp4に変換してiPodで見られちゃうぜ!と思い、ちょっとハックしてみたところ、かなりめんどくさいですが方法がみつかりました。
でも、今のところアナログな方法しかなくシステマチックする方法はみつかっていません。

具体的な方法は以下。
※この方法をやるためには前提条件としてFirebugがインストールされたFirefoxが必要となります

  1. まずダウンロードしたい対象のチャンネルのURLを開く
  2. 普通に http://ustream.tv/channel/example/ を開くだけです。

  3. 次にダウンロードしたい録画された動画をクリックする
  4. 先程開いたページの Past Clips からダウンロードしたい動画をクリックします。

  5. その状態でFirebugを開いて、HTMLタブをみます。
  6. そのHTMLの中から「serverid=数字」という記述がみつかると思います。
    この数字の部分を覚えておいてください。

  7. 次に、今開いてるページの動画が流れているところの下にある「Open in larger window」というリンクをクリックする
  8. クリックすると別タブ(ウィンドウ)が開いて、そこに動画の部分だけが大きく表示されると思います。

  9. この状態でふたたびFirebugを開いて、Netのタブを見ます
  10. Netタブには、そのページを開いた際にダウンロードされたリソースがリストされていると思います。その中から「http://playback1.ustream.tv/thumbnails/orig/broadcast/数字/数字.jpg」という画像をダウンロードしているのがみつかると思います。
    ここの「数字/数字」を覚えておいてください。

  11. ここまできたら、おもむろにFirefoxの別のタブ(ウィンドウでもいいけど)のロケーションに http://flash{serverid}.ustream.tv:18881/broadcast/{数字/数字}.flv を打ってリターン
  12. 実際には http://flash1.ustream.tv:18881/broadcast/11111/1111111111111.flv みたいなかんじのURLになると思います。
    これで flv をダウンロードすることができます。

今のところ「serverid」と「数字/数字」を取得する方法が、このFirebugを使う方法しかなくて、他の方法がみつかっていません。一応動画を再生するswfを解析してはみたのですが、その中にはなさそうです。

これは想像ですが、swf内でhttp://gw.ustream.tv/gateway.phpをPOSTしているのはわかっているので、そこで取得しているのか、もしくはJavaScriptでAjaxをつかってどこかから取得しているのか、といったところだと思いますが、いずれにしてももう少し解析が必要です。

Imagerを使ってこのエントリでやっているPhotoshopと(おそらく)同等の処理になるであろう変換サービスを作った。

http://sasakillizer.47objects.com/

やってることは以下の処理だけです。

my $img = Imager->new->read( file => 'before.jpg' ) or die Imager->errstr;
$img->filter( type => "autolevels", lsat => 0.0003, usat => 0.0003 ) or die $img->errstr;
$img->filter( type => "contrast", intensity => 1.05 ) or die $img->errstr;
$img = $img->convert(
    matrix =>[ [ 1.12,    0,    0, 0 ],
              [    0, 1.08,    0, 0 ],
              [    0,    0, 1.03, 0 ] ]
) or die $img->errstr;
$img->write( file => 'after.jpg' );

autolevelsフィルターでコントラストの上下0.03%をカットして、contrastフィルターで全体的にコントラストを上げて、convertで赤と黄の色をちょっと上げる。それだけです。

小さい画像だと、変換後がちょっと荒くなってしまうのはご愛敬。

http://shibuya.pm.org/blosxom/techtalks/200710.html

やべぇ、まったく気付いてなかった。
すでに定員に達っしている模様。負け組決定。

ustreamでなんとか我慢するか。。。

こっちには書いたのですが、一昨日HTTP::MobileAgentの0.26_1をリリースしました。
メインの変更内容は前書いた通り、モバイル系のGooglebotをis_non_mobileとして判定しないようにしたところです。(詳しくはChangesを参照のこと)

自分的にも今回の対応がどうなのかという疑問も残っていて、今後どう転ぶかわからないということでDEVELOPER RELEASEにしてあります。
動作的に問題ないとは思いますが、プロダクションで使う際には気を付けるようお願いします。

バグ等ありましたら、kurihara at cpan.org までどうぞ。

なんだか流行ってるみたい(?)なので、Gravatarに写真を登録して、CPANのAuthorのページに写真を載せたよ。

設定方法は簡単。

  1. Gravatarのusername@cpan.orgでユーザ登録をする。
  2. GravatarのMy Gravatarsから自分の画像を登録する。ちなみに、画像のレートをG、PG、R、Xの4つの中から選ぶのですが自分はGにしました。Gは一番ゆるいレートみたい。Xは一番やばい(?)画像のときのレートみたい。(この理解は合ってるのかな…)
  3. しばらく待つ
  4. おわり

CPANが一定期間毎にGravatarに画像を取りにいってるっぽい。
CPANのFAQにも載ってます。

CPAN Authorな方はぜひ。


検索

広告

OpenID対応しています OpenIDについて
Powered by Movable Type 4.22-ja