SlideShare a Scribd company logo
1 of 55
Download to read offline
不安定な環境の中でのバッチ処理
~DBストア型JobQueueシステムQudoを使った事例~

            <メニュー>
           イントロダクション編
           要件編
           実装編
           デモ編


    Hirobanex(Akabane Hiroyuki)
     2012-09-28@YAPC::Asia2012
<イントロダクション編>
 ~あるある探検隊~




               1
バッチ処理とは
バッチ処理とは、コンピュータで1つの流れのプログラム群を順次に実行

   あらかじめ定めた処理を一度に行
すること。

うことを示すコンピュータ用語。反対語は対話処理またはリアルタ
イム処理。

~(中略)~


バッチジョブは一度設定されると人間の手を
煩わせることなく動作する。そのため入力データもスクリプ
トやコマンド行パラメータを通して予め用意される。この点でユー
ザーの入力を必要とする対話型プログラムと
は対極にある。
                        Wikipediaより
                                      2
ITシステムにまつわるギャップ


  みんなの期待     システム   エンジニアの小言


  これで安心、
ミスはありえない!!             おいおい・・・
                      こっちは結構大変
 スピーディーに              なんだけどなぁ・・・
なんでもできる!!




                                   3
エンジニアが直面する様々な現実
•   facebookがエラーかえしくるんですけど・・・
•   ファイルロックしてよみとれなかった・・・
•   DBがロックされていて・・・
•   外部サーバーがメンテ中で・・・
•   EC2APIのパースに失敗した・・・
•   唐突にDNSが・・・
•   いつの間に(APIの)仕様が変わって・・・
•   構築期間が短すぎて・・・
                                4
外部WebAPI(facebook/twitterなど)
  がERRORかえしてきた・・・




                               5
FILE ROCKしてよみとれなかった・・・




                         6
DBのROW/TABLE ROCKされていて
   UPDATEできなかった・・・




                         7
古い外部サーバーにバックアップして
いるんだけど、外部サーバーがメンテ
  中で送信できてなかった・・・




                    8
EC2でサーバー運用していてサーバー
 足そうとしたら、EC2APIのパースに失
  敗したとかって壊れてしまった・・・




                        9
唐突にDNSが名前解決できなく
    なっていた・・・




                  10
いつの間に(APIの)仕様が変わって、
  エラーをはきまくっていた・・・




                      11
なんか作れって言われたんだけど、
期間が短すぎてなんかバグがあったり
よくわからないことが多い気がする・・・




                      12
System is unstable and uncontrolable


    みんなの不満     システム    エンジニアの不満

 そんなことも予想できな               仕様が曖昧で・・・
   かったのかー!                  ベンダーの・・・




          炎上
「仕様がよくない」といえるケースも多いかもしれないが、
  安定的にシステムを運用するは難しいのが現実                 13
例外が通用しないバッチ処理
   Web処理           バッチ処理




   ん?落ちてる?       終わらない?!
 トラフィックが増えたし、
やっぱあの機能重かったね    どういうことなんだ!

 バッチ処理にはバッチ処理なりの要件が存在する
                             14
<要件編>
~バッチ要件とJob Queue~




                    15
【要件編】アジェンダ



• hirobanex的バッチ処理要件
• Job Queueシステムの概要
• 本要件別のJob Queueの機能比較
• TheSchwartz VS Qudo

                        16
hirobanex的バッチ処理要件


•   再実行可能な単位で処理が区切れている
•   途中でdieして止まっていてほしくない
•   どこまで終わったかログがとれている
•   例外が発生したら、実行ケース別にログれる
•   複数回リトライできる
•   リトライする場合ある程度間隔をあける
•   最終的に失敗しても手動で簡単に再実行できる

                            17
素人エンジニアのバッチ処理



なんか、「これ毎月2日に一括処理して
まとめておいて~」って言われたから、
ごにょごにょ一枚のスクリプトに書いて
    実行しったった!!!




                     18
【要件】明確な処理単位



なんか変なところでとまってしまったんだけど、
  よくわからんから最初からやり直し。
 いつになったら帰れるかわからず疲弊中・・・




   一つの処理をメソッドにまとめて
       おけばよかったなぁ・・・

                         19
【要件】スキップ機能

        あれ、終わった~?



    とまってました・・・
            あっそ・・・



dieしたやつスキップして先に進めるようにして
       おけばよかったなぁ・・・

                          20
【要件】ケース別エラーログ

     で、なんで止まったの??



   わかりません・・・
     どうなっているんだ・・・



ちゃんと、エラーログをケース別に吐いて
     おけばよかったなぁ・・・

                      21
【要件】進捗把握

で、とりあえず、どこまで終わった??



たぶん、半分くらい・・・
          ・・・



どこまで終わったかログって
   おけばよかったなぁ・・・

                     22
【要件】Retry設定



  なんかわからんけど、
同じケースでも何回かやると
 うまくいくんだけどなぁ・・・


 何回かリトライする設定にして
    おけばよかったなぁ・・・

                   23
【要件】Retry間隔設定



     短期間に
  何度もリトライしたら
  DB落ちちゃった・・・


リトライの間隔をいい塩梅に設定して
    おけばよかったなぁ・・・

                    24
【要件】再実行な失敗保存

     さすがに、もう終わったよね???


   あ、一部がちょっと・・・
    いいかげんしてよっ!!

最終的に失敗しても楽に再実行できるようにして
       おけばよかったなぁ・・・

                         25
hirobanex的バッチ処理要件まとめ
 要件                      概要
 明確な
         再実行可能な単位で処理が区切れている
処理単位
スキップ
         途中でdieしてとまらないようになっている
 機能

進捗把握     どこまで終わったのかわかる

ケース別
      例外が発生した場合、実行ケース別にログがとれる
エラーログ

Retry設定 複数回リトライできる

 Retry
         リトライする場合ある程度間隔をあける
間隔設定
再実行な
         最終的に失敗した場合でも、手軽に簡単に再実行できる
失敗保存
                                     26
Job Queueシステムの概要①
 Client       Client     Client
Process      Process    Process




           Job Server


Worker       Worker     Worker
Process      Process    Process

           よくあるチャート
                                  27
Job Queueシステムの概要②
   Client                                Client                          Client
  Process
                              2   処理B
                                        Process
                                                      4                 Process
                                  付属情報       処理A結果
 処理方法Aの登録                         処理A
                                                           処理方法Bの登録
            1
$worker->register_function(
                                  付属情報       処理B結果

                                                          $worker->register_function(
  {処理A} => sub {
    my $job = @_;
                                  Job Server                {処理B} => sub {
                                                              my $job = @_;
    =================                                         =================
    warn "hirobanex";             処理B                         warn "nekokak";
    =================             付属情報       処理A結果            =================
    return xxx;                   処理A                         return xxx;
});                               付属情報       処理B結果        });



                                                  3
  Worker                                Worker                          Worker
  Process                               Process                         Process
                Workerに予め登録されている処理を
              Clientが指定し、Workerが非同期で処理                                                  28
本要件別Job Queue機能比較①
 要件       Gearman   Q4M   TheSchwartz   Qudo
 明確な
処理単位        ○       ○        ○          ○
スキップ
 機能         ○       ○        ○          ○
進捗把握        ×       ○        ○          ○
ケース別
エラーログ       ×       ×        ○          ○
Retry設定     ○       ×        ○          ○
 Retry
間隔設定        ○       ×        ○          ○
再実行な
失敗保存        ×       ×        ×          ○
                                               29
本要件別Job Queue機能比較②
 要件       Gearman   Q4M   TheSchwartz   Qudo
 明確な
処理単位        ○       ○        ○          ○
スキップ
                Job Queueを使えば満たされる
 機能         ○       ○        ○          ○
                    ジョブサーバーをジョブが消失しないDBを
進捗把握        ×       ○        ○
                          使えば満たされる      ○
ケース別
エラーログ       ×       ×       ○     ○
                           Q4Mは独自に実装
                           する必要があるが他
Retry設定     ○       ×       ○     ○
                           は実装されているの
 Retry
間隔設定        ○       ×       ○     ○
                             で満たされる
再実行な
失敗保存        ×       ×        ×          ○
                                               30
TheSchwartz VS Qudo①
       要件           TheSchwartz   Qudo


 多様なシリアライザーを使いたい       ×          ○


ジョブが永遠とループするのを防ぐ       ×          ○


最終的に失敗しても楽に再実行できる      ×          ○

                                         31
TheSchwartz VS Qudo②
       要件           TheSchwartz      Qudo


 多様なシリアライザーを使いたい        ×            ○
                      TheSchwartzでも継承とか
                         Class::Triggerとか
 ジョブが永遠とループするのを防ぐ       ×            ○
                      Class::MethodModifierと
                      かがんばればできるけど、
                        Qudoは拡張性が高い



最終的に失敗しても楽に再実行できる       ×            ○
TheSchwartzをすでに使っているところをQudoにリプ
 レイスするほどではないが、新規ならQudoがベスト                     32
<実装編>
~Qudoを使った実装例~




                33
【実装編】アジェンダ
•   インストールとか
•   Qudoのインスタンスの生成
•   処理の定義
•   処理の登録 ~ひとつ場合~
•   処理の登録 ~複数の場合~
•   処理をする ~通常の場合~
•   処理をする ~実際の場合~
•   無限ループの中のエラーハンドリング
•   max_retries = 1でerror時の再登録
•   max_retries > 1でerror時の再登録
•   動作確認テストをする
                                 34
インストールとか
                     モジュール
cpanm Qudo
                     ジョブサーバー

qudo
  --db=my_app_qudo
  --user=root
  --pass=pass
  --rdbms=mysql
  --use_innodb
                               35
Qudoのインスタンス生成
use Qudo;

my $qudo = Qudo->new(                     #WorkerもClientもこのインスタンスを使用
    datasources        => +[
        +{
            dsn       => 'dbi:mysql:my_app_qudo;',
            username => 'root',
            password => 'pass',
        },
                                           Hookに好きな処理を追加できるのが
    ],
    default_hooks      => [qw/                 TheSchwartzに対する優位性
        Qudo::Hook::Serialize::JSON       #引数情報をJSONにシリアライズ
        Qudo::Hook::ForceQuitJob          #予め決めた時間を超えたらdie(ギッハブ)
        MyApp::Hook::NotifyReachMaxRetry #オレオレ例。再実行な失敗保存(後述)
    /],
    manager_abilities => [qw/             #処理可能な処理名(後から追加も可能)
        MyApp::Worker::Simple
        MyApp::Worker::OnceEveryTreeDie
    /],
);
 明確な        スキップ          ケース別            Retry間隔   再実行な   多様なシリ ワーカーの
                   進捗把握         Retry設定
処理単位         機能           エラーログ             設定      失敗保存   アライザー 専有回避
                                                                         36
処理の定義
package MyApp::Worker::OnceEveryTreeDie;   #クラス名が処理名になる
use strict;
use warnings;
use base 'Qudo::Worker';

sub   set_job_status { 1 }     #ジョブの実行結果の記録オプション
sub   max_retries    { 5 }     #リトライする回数
sub   retry_delay    { 5 }     #リトライするときにあける間隔の秒数
sub   grab_for       { 60*5 } #ジョブを他のワーカーからブロックしておく秒数
sub   work {                   #処理内容の定義
      my ($class, $job) = @_;
      # -ここはホントは別クラスにしたほうがテストしやすい--------
      if (int(rand(3)) == 0) {
                                            Qudo::Hook::ForceQuitJobを使っておくと、
          die "error!!";
                                            grab_forの時間で過ぎたら一旦dieしてくれる
      }else{
                                             ので、Workerプロセスが変な爆弾踏んでも処
          print "success!!¥n";
                                                 理から開放されるからひとまず安心
      }
      # ---------------------------------------------------------
      $job->completed;
}
 明確な       スキップ             ケース別             Retry間隔   再実行な   多様なシリ ワーカーの
                    進捗把握          Retry設定
処理単位        機能              エラーログ              設定      失敗保存   アライザー 専有回避
                                                                               37
処理の登録 ~ひとつ場合~
#!/usr/bin/env perl
use strict;
use warnings;
use Qudo;

my $qudo = Qudo->new(...);

$qudo->enqueue(
  'MyApp::Worker::OnceEveryTreeDie', #第一引数で処理名を指定
  +{                                 #第二引数で付属情報を指定
    arg => +{                        #シリアライザーをHookで入れていばRefも渡せる
       OnceEveryTreeDie => 1,
       moge             => 2,
    },
    run_after => Int,
    uniqkey    => Int,
    priority => Int,
  },
});


 明確な      スキップ               ケース別            Retry間隔   再実行な   多様なシリ ワーカーの
                      進捗把握         Retry設定
処理単位       機能                エラーログ             設定      失敗保存   アライザー 専有回避
                                                                            38
処理の登録 ~複数の場合~
my @jobs = (
    ["Func1",{arg => {   hoge   =>   1,   moge   =>   2},   priority   =>   1   }],
    ["Func1",{arg => {   hoge   =>   2,   moge   =>   3},   priority   =>   1   }],
    ["Func2",{arg => {   foo    =>   5,   bar    =>   5},   priority   =>   5   }],
    ["Func2",{arg => {   foo    =>   9,   bar    =>   9},   priority   =>   5   }],
);
bulk_enqueue(¥@jobs);

sub bulk_enqueue {
    my $jobs = shift;

    my $dsn   = $qudo->shuffled_databases;
    my $db    = $qudo->manager->driver_for($dsn);

    my $txn = $db->txn_scope;
        for my $job (@$jobs) {
            $qudo->manager->enqueue(@$job, $dsn);
        }
    $txn->commit;
}
 明確な      スキップ                  ケース別                         Retry間隔    再実行な          多様なシリ ワーカーの
                    進捗把握              Retry設定
処理単位       機能                   エラーログ                          設定       失敗保存          アライザー 専有回避
                                                                                                    39
処理をする ~通常の場合~
# worker.pl perl worker.pl & 的な感じで無限ループプロセスをおいておく
#!/usr/bin/env perl
use strict;
use warnings;
use MyApp::Worker::OnceEveryTreeDie;

my $qudo = Qudo->new(...);

#処理できる処理名を登録
$qudo->manager->register_abilities("MyApp::Worker::OnceEveryTreeDie");

$qudo->work();
-----<Qudoのworkメソッド抜粋>--------------------------
sub work {
    my ($self, $work_delay) = @_;
(中略)
    while (1) { #無限ループ
        sleep $work_delay unless $manager->work_once;
    }
}

 明確な      スキップ               ケース別              Retry間隔   再実行な    多様なシリ ワーカーの
                   進捗把握            Retry設定
処理単位       機能                エラーログ               設定      失敗保存    アライザー 専有回避
                                                                               40
処理をする ~実際の場合~
# worker.pl perl worker.pl &   的な感じで無限ループプロセスをおいておく
#!/usr/bin/env perl
use strict;
use warnings;
use Qudo::Parallel::Manager;

my $worker = Qudo::Parallel::Manager->new(
        databases              => [+{...},...], #Qudoインスタンスの生成と同じ
        default_hooks          => [qw/Qudo::Hook::Serialize::JSON/],
        manager_abilities      => [qw/MyApp::Worker::OnceEveryTreeDie/],
        work_delay             => 1,
        max_workers            => 5,
        min_spare_workers      => 5,
        max_spare_workers      => 5,
        max_request_par_chiled => 5,
        auto_load_worker       => 1,
    );
                    •Forkで高速化
};
                   •メモリリーク対策
$worker->run;      •ジョブの処理中にWorkerをKillしても処理後にとまる対策
 明確な      スキップ             ケース別             Retry間隔   再実行な   多様なシリ ワーカーの
                  進捗把握           Retry設定
処理単位       機能              エラーログ              設定      失敗保存   アライザー 専有回避
                                                                           41
無限ループの中のエラーハンドリング
my $res;                                Qudo::Workerのwork_safelyメソッドを抜粋
eval               #evalトラップ
     $res = $class->work($job);
};
if ( (my $e = $@) || ! $job->is_completed ) {
     if ( $job->retry_cnt < $class->max_retries ) {
         $job->reenqueue(
              {
                 grabbed_until => 0,
                 retry_cnt      => $job->retry_cnt + 1,
                 retry_delay    => $class->retry_delay,
              }
         );
     } else {
         $job->dequeue;
     }
     $job->failed("$e" || 'Job did not ...'); #Qudoのerrorテーブルにエラーを格納
} else {
     $job->dequeue;
}

 明確な     スキップ            ケース別             Retry間隔   再実行な   多様なシリ ワーカーの
                 進捗把握          Retry設定
処理単位      機能             エラーログ              設定      失敗保存   アライザー 専有回避
                                                                          42
max_retries = 1でerror時の再登録
use Qudo;

my $qudo = Qudo->new(...);

my $exceptions = $qudo->exception_list;
my ($db, $exception) = each %$exceptions;

while ( my ($db, $exception) = each %$exceptions ) {
    $qudo->manager->enqueue_from_failed_job(
        $exception, $db
    );
}


                  複数回リトライしていると、リトライしたすべて
             exeption_logテーブルに残ってしまうので、これだと同じ
                     ジョブを何個もreenqueueしてしまう
                               ↓
                            次のページ参照

 明確な        スキップ             ケース別              Retry間隔   再実行な   多様なシリ ワーカーの
                   進捗把握            Retry設定
処理単位         機能              エラーログ               設定      失敗保存   アライザー 専有回避
                                                                              43
max_retries > 1でerror時の再登録①
                                     ジョブの結果を一旦移せるようなテーブルを用意

CREATE TABLE worker_error_log(
    id         int(10) unsigned      NOT NULL auto_increment,
    funcname   varchar(255) binary   NOT NULL,
    arg        mediumblob,
    uniqkey    varchar(255)          DEFAULT NULL,
    priority   int(10) unsigned      DEFAULT NULL,
    retried_fg tinyint(1) unsigned   NOT NULL default 0,
    updated_at timestamp             NOT NULL DEFAULT CURRENT_TIMESTAMP on update
CURRENT_TIMESTAMP,

    PRIMARY KEY    (id),
    KEY funcname   (funcname),
    KEY retried_fg (retried_fg)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;




 明確な      スキップ              ケース別                 Retry間隔   再実行な    多様なシリ ワーカーの
                   進捗把握           Retry設定
処理単位       機能               エラーログ                  設定      失敗保存    アライザー 専有回避
                                                                                    44
max_retries > 1でerror時の再登録②
package MyApp::Worker::Hook::NotifyReachMaxRetry;               独自のHookを用意
use base 'Qudo::Hook';
sub hook_point { 'post_work' }
sub load {
    my ($class, $klass) = @_;

    $klass->hooks->{post_work}->{'notify_reach_max_retry'} = sub {
        my $job = shift;
        #max_retriesを超えてなおかつエラーだったらさっき用意したテーブルに入れる
        if ($job->is_failed && ( $job->funcname->max_retries <= ($job->retry_cnt) )) {
            $db->insert('worker_error_log',{
                funcname => $job->funcname,
                arg      => $job->arg,
                uniqkey => $job->uniqkey,
                priority => $job->priority + 100, #失敗している時点で優先順位は高いはず
            });

             #アラートメールとかする
         }
    };
}
sub unload { delete $_[1]->hooks->{post_work}->{'notify_reach_max_retry'} }
1;

 明確な         スキップ               ケース別                  Retry間隔    再実行な         多様なシリ ワーカーの
                      進捗把握            Retry設定
処理単位          機能                エラーログ                   設定       失敗保存         アライザー 専有回避
                                                                                            45
max_retries > 1でerror時の再登録③
                                                                    再登録する
my @worker_error_log = $db->search('worker_error_log',{retried_fg => 0})->all;

my @jobs = map {
    my $row = $_;
    [$row->funcname,{
        arg      => $row->arg,
        uniqkey => $row->uniqkey,
        priority => $row->priority,
    }];
} @worker_error_log;

my @update_ids = map {$_->id} @worker_error_log;

my $txn = $db->txn_scope;
    $db->update('worker_error_log',
        { retried_fg => 1 },
        { id => { 'in' => ¥@update_ids } }
    );

    bulk_enqueue(¥@jobs);
$txn->commit;

 明確な        スキップ                ケース別                  Retry間隔    再実行な      多様なシリ ワーカーの
                      進捗把握            Retry設定
処理単位         機能                 エラーログ                   設定       失敗保存      アライザー 専有回避
                                                                                         46
動作確認テストをする
use Test::More;
use Qudo;

#qudoのDBをテストでたちあげる(Test::mysqldでもなんでも)
my $qudo = Qudo->new(...);#
subtest 'enqueue' => sub {
    $qudo->enqueue('MyApp::Worker::OnceEveryTreeDie',+{});
    my (undef,$job_count) = %{container('qudo')->job_count()};
    is $job_count,1;
};
subtest 'work' => sub {
    $qudo->manager->register_abilities("MyApp::Worker::OnceEveryTreeDie");
    $qudo->manager->work_once;
    my (undef,$job_count) = %{container('qudo')->job_count()};
    is $job_count,0;
    #実際のMyApp::Worker::OnceEveryTreeDieの中身もテスト?
};
#qudoのテストだちあげたDBをけす

done_testing;
 明確な      スキップ              ケース別               Retry間隔   再実行な    多様なシリ ワーカーの
                   進捗把握           Retry設定
処理単位       機能               エラーログ                設定      失敗保存    アライザー 専有回避
                                                                               47
<デモ編>
~実感!!~




         48
デモ一覧
<メニュー>
• シンプルな処理の例
• 不安定な処理の例
• 複数retry後の失敗Job蓄積の例



<demo sample code>
• https://github.com/hirobanex/QudoSample

                                            49
シンプルな処理の例
- Simpleの処理を見てもらう(lib/MyApp/Worker/Simple.pm)
- enqueue
   - enqueue.plで登録する内容をみてもらう(vi script/simple/enqueue.pl)
   - enqueue(perl script/simple/enqueue.pl)
- ジョブがたまったのをみてもらう(select * from job;)
   - JSONになっているよ
- 処理する(perl ./script/simple/worker.pl)
- ジョブがきえたのをみてもらう
   - select * from job ¥G
   - select * from job_status ¥G




                                                            50
不安定な処理の例
- OnceEveryTreeDieの処理を見てもらう(lib/MyApp/Worker/OnceEveryTreeDie.pm)
- enqueue
   - enqueue.plで登録する内容をみてもらう,複数個いれる(vi
     script/once_over_tree_die/enqueue.pl)
   - enqueue(perl script/once_over_tree_die/enqueue.pl)
- ジョブがたまったのをみてもらう
   - truncate job_status;
   - truncate exception_log;
   - select * from func ;
   - select * from job;
- 処理する(perl ./script/once_over_tree_die/worker.pl)
   - (リトライカウントが増えている)select * from job;
   - (リトライカウントが増えている)select * from job;
   - (リトライカウントが増えている)select * from job;
   - 失敗の記録、10回生功した記録が残っている(select * from job_status;
   - エラーが2回分入っている(select * from exception_log ¥G

                                                                    51
複数retry後の失敗Job蓄積の例
- Dieの処理を見てもらう(lib/MyApp/Worker/Die.pm)
- enqueue
   - enqueue.plで登録する内容をみてもらう(vi script/max_retry/enqueue.pl)
   - enqueue(perl script/max_retry/enqueue.pl)
- ジョブがたまったのをみてもらう
   - select * from func ;
   - select * from job ¥G
- 処理する(perl ./script/max_retry/worker.pl)
   - 何も表示されません
   - (リトライカウントが増えている)select * from job ¥G
- ジョブがきえたのをみてもらう
   - select * from job ¥G
   - リトライした回数分入っている(select * from job_status;)
   - エラー6回分入っている(select * from exception_log ¥G)
- 独自実装に入っているか
   - Hookを確認(lib/MyApp/Worker/Hook/NotifyReachMaxRetry.pm)
   - テーブルを確認(select * from worker_error_log;)
   - reenqueue.plを実行(perl ./script/max_retry/reenqueue.pl)
   - テーブルを確認,retried_fgがたっている(select * from worker_error_log;)
- ジョブに入っているか確認(select * from job;)
                                                                 52
Thanks nekokak(Qudo Auther)!!
     Thanks Hachioji.pm!!
    Thanks Perl Mongers!!




                                53
LTソンとても盛り上がっているので
是非一回見に行って下さいっ!!




                    54

More Related Content

What's hot

規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッドKohsuke Yuasa
 
Javaでトランザクショナルメモリを使う
Javaでトランザクショナルメモリを使うJavaでトランザクショナルメモリを使う
Javaでトランザクショナルメモリを使うKenji Kazumura
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
Synthesijer fpgax 20150201
Synthesijer fpgax 20150201Synthesijer fpgax 20150201
Synthesijer fpgax 20150201Takefumi MIYOSHI
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングKohsuke Yuasa
 
イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術Kohsuke Yuasa
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013Ryo Sakamoto
 
Q4 Mでメッセージキュー
Q4 MでメッセージキューQ4 Mでメッセージキュー
Q4 Mでメッセージキューngi group.
 
Handlerさんコンニチワ
HandlerさんコンニチワHandlerさんコンニチワ
Handlerさんコンニチワyoku0825
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)Hiromu Shioya
 
AutoDock_vina_japanese_ver.2.0
AutoDock_vina_japanese_ver.2.0AutoDock_vina_japanese_ver.2.0
AutoDock_vina_japanese_ver.2.0Satoshi Kume
 
Serviceability Toolsの裏側
Serviceability Toolsの裏側Serviceability Toolsの裏側
Serviceability Toolsの裏側Yasumasa Suenaga
 
AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0Satoshi Kume
 
SQLチューニング入門 入門編
SQLチューニング入門 入門編SQLチューニング入門 入門編
SQLチューニング入門 入門編Miki Shimogai
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会Koichi Sakata
 

What's hot (20)

規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
Javaでトランザクショナルメモリを使う
Javaでトランザクショナルメモリを使うJavaでトランザクショナルメモリを使う
Javaでトランザクショナルメモリを使う
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
Synthesijer fpgax 20150201
Synthesijer fpgax 20150201Synthesijer fpgax 20150201
Synthesijer fpgax 20150201
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミング
 
イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術
 
C++ マルチスレッド 入門
C++ マルチスレッド 入門C++ マルチスレッド 入門
C++ マルチスレッド 入門
 
dm-thin-internal-ja
dm-thin-internal-jadm-thin-internal-ja
dm-thin-internal-ja
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
 
Q4 Mでメッセージキュー
Q4 MでメッセージキューQ4 Mでメッセージキュー
Q4 Mでメッセージキュー
 
Handlerさんコンニチワ
HandlerさんコンニチワHandlerさんコンニチワ
Handlerさんコンニチワ
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)
 
AutoDock_vina_japanese_ver.2.0
AutoDock_vina_japanese_ver.2.0AutoDock_vina_japanese_ver.2.0
AutoDock_vina_japanese_ver.2.0
 
Serviceability Toolsの裏側
Serviceability Toolsの裏側Serviceability Toolsの裏側
Serviceability Toolsの裏側
 
Reconf 201506
Reconf 201506Reconf 201506
Reconf 201506
 
Slide
SlideSlide
Slide
 
AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
SQLチューニング入門 入門編
SQLチューニング入門 入門編SQLチューニング入門 入門編
SQLチューニング入門 入門編
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会
 

Viewers also liked

TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」
TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」
TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」(株)TAM
 
正月発火村に参加して変なJobQueueサーバー作った話
正月発火村に参加して変なJobQueueサーバー作った話正月発火村に参加して変なJobQueueサーバー作った話
正月発火村に参加して変なJobQueueサーバー作った話karupanerura
 
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)karupanerura
 
Asakusa Framework スモールジョブ実行エンジン & Windows対応
Asakusa Framework スモールジョブ実行エンジン & Windows対応Asakusa Framework スモールジョブ実行エンジン & Windows対応
Asakusa Framework スモールジョブ実行エンジン & Windows対応apirakun
 
AZAREA-Clusterセミナー(クラウドEXPO2013春)
AZAREA-Clusterセミナー(クラウドEXPO2013春)AZAREA-Clusterセミナー(クラウドEXPO2013春)
AZAREA-Clusterセミナー(クラウドEXPO2013春)AzareaCluster
 
Asynchronous Messaging入門(第4回実施分)
Asynchronous Messaging入門(第4回実施分)Asynchronous Messaging入門(第4回実施分)
Asynchronous Messaging入門(第4回実施分)Tatsuaki Sakai
 
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」でHinemos
 
PHP & Queue
PHP & QueuePHP & Queue
PHP & Queuesasezaki
 
Asakusa Framework 歴史探訪 & ここ最近の新機能
Asakusa Framework 歴史探訪 & ここ最近の新機能Asakusa Framework 歴史探訪 & ここ最近の新機能
Asakusa Framework 歴史探訪 & ここ最近の新機能apirakun
 
JSON, JSON::PP, and more
JSON, JSON::PP, and moreJSON, JSON::PP, and more
JSON, JSON::PP, and morecharsbar
 
Asakusa バッチの運用を支える技術
Asakusa バッチの運用を支える技術Asakusa バッチの運用を支える技術
Asakusa バッチの運用を支える技術KinebuchiTomo
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいcharsbar
 
2016年のPerl (Long version)
2016年のPerl (Long version)2016年のPerl (Long version)
2016年のPerl (Long version)charsbar
 
Json(::PP) is a-changing
Json(::PP) is a-changingJson(::PP) is a-changing
Json(::PP) is a-changingcharsbar
 
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖Hinemos
 
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理Hinemos
 
Google Cloud Platformでソーシャルゲームを1本出してみた!
Google Cloud Platformでソーシャルゲームを1本出してみた!Google Cloud Platformでソーシャルゲームを1本出してみた!
Google Cloud Platformでソーシャルゲームを1本出してみた!Hasegawa Yusuke
 
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編Amazon Web Services Japan
 

Viewers also liked (20)

TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」
TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」
TAM 新人ディレクター システムスキルアップ プログラム 第5回 「システムドキュメント」
 
Teng tips
Teng tipsTeng tips
Teng tips
 
正月発火村に参加して変なJobQueueサーバー作った話
正月発火村に参加して変なJobQueueサーバー作った話正月発火村に参加して変なJobQueueサーバー作った話
正月発火村に参加して変なJobQueueサーバー作った話
 
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)
Perl RDBMS Programming(DBI/DBIx::Sunnyのはなし)
 
Asakusa Framework スモールジョブ実行エンジン & Windows対応
Asakusa Framework スモールジョブ実行エンジン & Windows対応Asakusa Framework スモールジョブ実行エンジン & Windows対応
Asakusa Framework スモールジョブ実行エンジン & Windows対応
 
AZAREA-Clusterセミナー(クラウドEXPO2013春)
AZAREA-Clusterセミナー(クラウドEXPO2013春)AZAREA-Clusterセミナー(クラウドEXPO2013春)
AZAREA-Clusterセミナー(クラウドEXPO2013春)
 
Asynchronous Messaging入門(第4回実施分)
Asynchronous Messaging入門(第4回実施分)Asynchronous Messaging入門(第4回実施分)
Asynchronous Messaging入門(第4回実施分)
 
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で
【OSC2014】監視もジョブも、クラウド管理も「Hinemos」で
 
PHP & Queue
PHP & QueuePHP & Queue
PHP & Queue
 
Asakusa Framework 歴史探訪 & ここ最近の新機能
Asakusa Framework 歴史探訪 & ここ最近の新機能Asakusa Framework 歴史探訪 & ここ最近の新機能
Asakusa Framework 歴史探訪 & ここ最近の新機能
 
JSON, JSON::PP, and more
JSON, JSON::PP, and moreJSON, JSON::PP, and more
JSON, JSON::PP, and more
 
Asakusa バッチの運用を支える技術
Asakusa バッチの運用を支える技術Asakusa バッチの運用を支える技術
Asakusa バッチの運用を支える技術
 
Oracle GoldenGate Veridata概要
Oracle GoldenGate Veridata概要Oracle GoldenGate Veridata概要
Oracle GoldenGate Veridata概要
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したい
 
2016年のPerl (Long version)
2016年のPerl (Long version)2016年のPerl (Long version)
2016年のPerl (Long version)
 
Json(::PP) is a-changing
Json(::PP) is a-changingJson(::PP) is a-changing
Json(::PP) is a-changing
 
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖
【HinemosWorld2015】B2-3_【テクニカル】Hinemos ver.5.0徹底解剖
 
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理
【HinemosWorld2015】B1-3_【入門】Hinemosではじめるジョブ管理
 
Google Cloud Platformでソーシャルゲームを1本出してみた!
Google Cloud Platformでソーシャルゲームを1本出してみた!Google Cloud Platformでソーシャルゲームを1本出してみた!
Google Cloud Platformでソーシャルゲームを1本出してみた!
 
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編
[AWS Summit 2012] クラウドデザインパターン#5 CDP バッチ処理編
 

Similar to 不安定な環境の中でのバッチ処理~JobQueueシステムQudoを使った事例~

tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1Ryosuke IWANAGA
 
Kink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based languageKink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based languageTaku Miyakawa
 
これからのコンピューティングとJava(Hacker Tackle)
これからのコンピューティングとJava(Hacker Tackle)これからのコンピューティングとJava(Hacker Tackle)
これからのコンピューティングとJava(Hacker Tackle)なおき きしだ
 
分散メモリ環境におけるシェルスクリプトの高速化手法の提案
分散メモリ環境におけるシェルスクリプトの高速化手法の提案分散メモリ環境におけるシェルスクリプトの高速化手法の提案
分散メモリ環境におけるシェルスクリプトの高速化手法の提案Keisuke Umeno
 
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallこれからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallなおき きしだ
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2Preferred Networks
 
ログにまつわるエトセトラ
ログにまつわるエトセトラログにまつわるエトセトラ
ログにまつわるエトセトラ菊池 佑太
 
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)Iwana Chan
 
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -Yukihiko SAWANOBORI
 
Or seminar2011final
Or seminar2011finalOr seminar2011final
Or seminar2011finalMikio Kubo
 
griffon plugin を 実際に作ってみよう #jggug
griffon plugin を 実際に作ってみよう #jgguggriffon plugin を 実際に作ってみよう #jggug
griffon plugin を 実際に作ってみよう #jggugkimukou_26 Kimukou
 
Programming camp 2010 debug hacks
Programming camp 2010 debug hacksProgramming camp 2010 debug hacks
Programming camp 2010 debug hacksHiro Yoshioka
 
泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) 泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) Akihiro Kuwano
 
vImageのススメ(改訂版)
vImageのススメ(改訂版)vImageのススメ(改訂版)
vImageのススメ(改訂版)Shuichi Tsutsumi
 
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料KamezawaHiroyuki
 
Hadoopによるリクルートでの技術調査とその活用
Hadoopによるリクルートでの技術調査とその活用Hadoopによるリクルートでの技術調査とその活用
Hadoopによるリクルートでの技術調査とその活用Chiaki Hatanaka
 
Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011 Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011 Hiro Yoshioka
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)NTT DATA Technology & Innovation
 
NVIDIA Japan Seminar 2012
NVIDIA Japan Seminar 2012NVIDIA Japan Seminar 2012
NVIDIA Japan Seminar 2012Takuro Iizuka
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublicT2C_
 

Similar to 不安定な環境の中でのバッチ処理~JobQueueシステムQudoを使った事例~ (20)

tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1
 
Kink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based languageKink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based language
 
これからのコンピューティングとJava(Hacker Tackle)
これからのコンピューティングとJava(Hacker Tackle)これからのコンピューティングとJava(Hacker Tackle)
これからのコンピューティングとJava(Hacker Tackle)
 
分散メモリ環境におけるシェルスクリプトの高速化手法の提案
分散メモリ環境におけるシェルスクリプトの高速化手法の提案分散メモリ環境におけるシェルスクリプトの高速化手法の提案
分散メモリ環境におけるシェルスクリプトの高速化手法の提案
 
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallこれからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
 
ログにまつわるエトセトラ
ログにまつわるエトセトラログにまつわるエトセトラ
ログにまつわるエトセトラ
 
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)
tokyo.vcl発表資料(VarnishCache3.0新機能とVUPの仕方)
 
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
 
Or seminar2011final
Or seminar2011finalOr seminar2011final
Or seminar2011final
 
griffon plugin を 実際に作ってみよう #jggug
griffon plugin を 実際に作ってみよう #jgguggriffon plugin を 実際に作ってみよう #jggug
griffon plugin を 実際に作ってみよう #jggug
 
Programming camp 2010 debug hacks
Programming camp 2010 debug hacksProgramming camp 2010 debug hacks
Programming camp 2010 debug hacks
 
泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) 泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい)
 
vImageのススメ(改訂版)
vImageのススメ(改訂版)vImageのススメ(改訂版)
vImageのススメ(改訂版)
 
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料
Cgroupあれこれ-第4回コンテナ型仮想化の情報交換会資料
 
Hadoopによるリクルートでの技術調査とその活用
Hadoopによるリクルートでの技術調査とその活用Hadoopによるリクルートでの技術調査とその活用
Hadoopによるリクルートでの技術調査とその活用
 
Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011 Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
 
NVIDIA Japan Seminar 2012
NVIDIA Japan Seminar 2012NVIDIA Japan Seminar 2012
NVIDIA Japan Seminar 2012
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublic
 

不安定な環境の中でのバッチ処理~JobQueueシステムQudoを使った事例~

  • 1. 不安定な環境の中でのバッチ処理 ~DBストア型JobQueueシステムQudoを使った事例~ <メニュー> イントロダクション編 要件編 実装編 デモ編 Hirobanex(Akabane Hiroyuki) 2012-09-28@YAPC::Asia2012
  • 3. バッチ処理とは バッチ処理とは、コンピュータで1つの流れのプログラム群を順次に実行 あらかじめ定めた処理を一度に行 すること。 うことを示すコンピュータ用語。反対語は対話処理またはリアルタ イム処理。 ~(中略)~ バッチジョブは一度設定されると人間の手を 煩わせることなく動作する。そのため入力データもスクリプ トやコマンド行パラメータを通して予め用意される。この点でユー ザーの入力を必要とする対話型プログラムと は対極にある。 Wikipediaより 2
  • 4. ITシステムにまつわるギャップ みんなの期待 システム エンジニアの小言 これで安心、 ミスはありえない!! おいおい・・・ こっちは結構大変 スピーディーに なんだけどなぁ・・・ なんでもできる!! 3
  • 5. エンジニアが直面する様々な現実 • facebookがエラーかえしくるんですけど・・・ • ファイルロックしてよみとれなかった・・・ • DBがロックされていて・・・ • 外部サーバーがメンテ中で・・・ • EC2APIのパースに失敗した・・・ • 唐突にDNSが・・・ • いつの間に(APIの)仕様が変わって・・・ • 構築期間が短すぎて・・・ 4
  • 8. DBのROW/TABLE ROCKされていて UPDATEできなかった・・・ 7
  • 11. 唐突にDNSが名前解決できなく なっていた・・・ 10
  • 14. System is unstable and uncontrolable みんなの不満 システム エンジニアの不満 そんなことも予想できな 仕様が曖昧で・・・ かったのかー! ベンダーの・・・ 炎上 「仕様がよくない」といえるケースも多いかもしれないが、 安定的にシステムを運用するは難しいのが現実 13
  • 15. 例外が通用しないバッチ処理 Web処理 バッチ処理 ん?落ちてる? 終わらない?! トラフィックが増えたし、 やっぱあの機能重かったね どういうことなんだ! バッチ処理にはバッチ処理なりの要件が存在する 14
  • 17. 【要件編】アジェンダ • hirobanex的バッチ処理要件 • Job Queueシステムの概要 • 本要件別のJob Queueの機能比較 • TheSchwartz VS Qudo 16
  • 18. hirobanex的バッチ処理要件 • 再実行可能な単位で処理が区切れている • 途中でdieして止まっていてほしくない • どこまで終わったかログがとれている • 例外が発生したら、実行ケース別にログれる • 複数回リトライできる • リトライする場合ある程度間隔をあける • 最終的に失敗しても手動で簡単に再実行できる 17
  • 20. 【要件】明確な処理単位 なんか変なところでとまってしまったんだけど、 よくわからんから最初からやり直し。 いつになったら帰れるかわからず疲弊中・・・ 一つの処理をメソッドにまとめて おけばよかったなぁ・・・ 19
  • 21. 【要件】スキップ機能 あれ、終わった~? とまってました・・・ あっそ・・・ dieしたやつスキップして先に進めるようにして おけばよかったなぁ・・・ 20
  • 22. 【要件】ケース別エラーログ で、なんで止まったの?? わかりません・・・ どうなっているんだ・・・ ちゃんと、エラーログをケース別に吐いて おけばよかったなぁ・・・ 21
  • 23. 【要件】進捗把握 で、とりあえず、どこまで終わった?? たぶん、半分くらい・・・ ・・・ どこまで終わったかログって おけばよかったなぁ・・・ 22
  • 24. 【要件】Retry設定 なんかわからんけど、 同じケースでも何回かやると うまくいくんだけどなぁ・・・ 何回かリトライする設定にして おけばよかったなぁ・・・ 23
  • 25. 【要件】Retry間隔設定 短期間に 何度もリトライしたら DB落ちちゃった・・・ リトライの間隔をいい塩梅に設定して おけばよかったなぁ・・・ 24
  • 26. 【要件】再実行な失敗保存 さすがに、もう終わったよね??? あ、一部がちょっと・・・ いいかげんしてよっ!! 最終的に失敗しても楽に再実行できるようにして おけばよかったなぁ・・・ 25
  • 27. hirobanex的バッチ処理要件まとめ 要件 概要 明確な 再実行可能な単位で処理が区切れている 処理単位 スキップ 途中でdieしてとまらないようになっている 機能 進捗把握 どこまで終わったのかわかる ケース別 例外が発生した場合、実行ケース別にログがとれる エラーログ Retry設定 複数回リトライできる Retry リトライする場合ある程度間隔をあける 間隔設定 再実行な 最終的に失敗した場合でも、手軽に簡単に再実行できる 失敗保存 26
  • 28. Job Queueシステムの概要① Client Client Client Process Process Process Job Server Worker Worker Worker Process Process Process よくあるチャート 27
  • 29. Job Queueシステムの概要② Client Client Client Process 2 処理B Process 4 Process 付属情報 処理A結果 処理方法Aの登録 処理A 処理方法Bの登録 1 $worker->register_function( 付属情報 処理B結果 $worker->register_function( {処理A} => sub { my $job = @_; Job Server {処理B} => sub { my $job = @_; ================= ================= warn "hirobanex"; 処理B warn "nekokak"; ================= 付属情報 処理A結果 ================= return xxx; 処理A return xxx; }); 付属情報 処理B結果 }); 3 Worker Worker Worker Process Process Process Workerに予め登録されている処理を Clientが指定し、Workerが非同期で処理 28
  • 30. 本要件別Job Queue機能比較① 要件 Gearman Q4M TheSchwartz Qudo 明確な 処理単位 ○ ○ ○ ○ スキップ 機能 ○ ○ ○ ○ 進捗把握 × ○ ○ ○ ケース別 エラーログ × × ○ ○ Retry設定 ○ × ○ ○ Retry 間隔設定 ○ × ○ ○ 再実行な 失敗保存 × × × ○ 29
  • 31. 本要件別Job Queue機能比較② 要件 Gearman Q4M TheSchwartz Qudo 明確な 処理単位 ○ ○ ○ ○ スキップ Job Queueを使えば満たされる 機能 ○ ○ ○ ○ ジョブサーバーをジョブが消失しないDBを 進捗把握 × ○ ○ 使えば満たされる ○ ケース別 エラーログ × × ○ ○ Q4Mは独自に実装 する必要があるが他 Retry設定 ○ × ○ ○ は実装されているの Retry 間隔設定 ○ × ○ ○ で満たされる 再実行な 失敗保存 × × × ○ 30
  • 32. TheSchwartz VS Qudo① 要件 TheSchwartz Qudo 多様なシリアライザーを使いたい × ○ ジョブが永遠とループするのを防ぐ × ○ 最終的に失敗しても楽に再実行できる × ○ 31
  • 33. TheSchwartz VS Qudo② 要件 TheSchwartz Qudo 多様なシリアライザーを使いたい × ○ TheSchwartzでも継承とか Class::Triggerとか ジョブが永遠とループするのを防ぐ × ○ Class::MethodModifierと かがんばればできるけど、 Qudoは拡張性が高い 最終的に失敗しても楽に再実行できる × ○ TheSchwartzをすでに使っているところをQudoにリプ レイスするほどではないが、新規ならQudoがベスト 32
  • 35. 【実装編】アジェンダ • インストールとか • Qudoのインスタンスの生成 • 処理の定義 • 処理の登録 ~ひとつ場合~ • 処理の登録 ~複数の場合~ • 処理をする ~通常の場合~ • 処理をする ~実際の場合~ • 無限ループの中のエラーハンドリング • max_retries = 1でerror時の再登録 • max_retries > 1でerror時の再登録 • 動作確認テストをする 34
  • 36. インストールとか モジュール cpanm Qudo ジョブサーバー qudo --db=my_app_qudo --user=root --pass=pass --rdbms=mysql --use_innodb 35
  • 37. Qudoのインスタンス生成 use Qudo; my $qudo = Qudo->new( #WorkerもClientもこのインスタンスを使用 datasources => +[ +{ dsn => 'dbi:mysql:my_app_qudo;', username => 'root', password => 'pass', }, Hookに好きな処理を追加できるのが ], default_hooks => [qw/ TheSchwartzに対する優位性 Qudo::Hook::Serialize::JSON #引数情報をJSONにシリアライズ Qudo::Hook::ForceQuitJob #予め決めた時間を超えたらdie(ギッハブ) MyApp::Hook::NotifyReachMaxRetry #オレオレ例。再実行な失敗保存(後述) /], manager_abilities => [qw/ #処理可能な処理名(後から追加も可能) MyApp::Worker::Simple MyApp::Worker::OnceEveryTreeDie /], ); 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 36
  • 38. 処理の定義 package MyApp::Worker::OnceEveryTreeDie; #クラス名が処理名になる use strict; use warnings; use base 'Qudo::Worker'; sub set_job_status { 1 } #ジョブの実行結果の記録オプション sub max_retries { 5 } #リトライする回数 sub retry_delay { 5 } #リトライするときにあける間隔の秒数 sub grab_for { 60*5 } #ジョブを他のワーカーからブロックしておく秒数 sub work { #処理内容の定義 my ($class, $job) = @_; # -ここはホントは別クラスにしたほうがテストしやすい-------- if (int(rand(3)) == 0) { Qudo::Hook::ForceQuitJobを使っておくと、 die "error!!"; grab_forの時間で過ぎたら一旦dieしてくれる }else{ ので、Workerプロセスが変な爆弾踏んでも処 print "success!!¥n"; 理から開放されるからひとまず安心 } # --------------------------------------------------------- $job->completed; } 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 37
  • 39. 処理の登録 ~ひとつ場合~ #!/usr/bin/env perl use strict; use warnings; use Qudo; my $qudo = Qudo->new(...); $qudo->enqueue( 'MyApp::Worker::OnceEveryTreeDie', #第一引数で処理名を指定 +{ #第二引数で付属情報を指定 arg => +{ #シリアライザーをHookで入れていばRefも渡せる OnceEveryTreeDie => 1, moge => 2, }, run_after => Int, uniqkey => Int, priority => Int, }, }); 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 38
  • 40. 処理の登録 ~複数の場合~ my @jobs = ( ["Func1",{arg => { hoge => 1, moge => 2}, priority => 1 }], ["Func1",{arg => { hoge => 2, moge => 3}, priority => 1 }], ["Func2",{arg => { foo => 5, bar => 5}, priority => 5 }], ["Func2",{arg => { foo => 9, bar => 9}, priority => 5 }], ); bulk_enqueue(¥@jobs); sub bulk_enqueue { my $jobs = shift; my $dsn = $qudo->shuffled_databases; my $db = $qudo->manager->driver_for($dsn); my $txn = $db->txn_scope; for my $job (@$jobs) { $qudo->manager->enqueue(@$job, $dsn); } $txn->commit; } 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 39
  • 41. 処理をする ~通常の場合~ # worker.pl perl worker.pl & 的な感じで無限ループプロセスをおいておく #!/usr/bin/env perl use strict; use warnings; use MyApp::Worker::OnceEveryTreeDie; my $qudo = Qudo->new(...); #処理できる処理名を登録 $qudo->manager->register_abilities("MyApp::Worker::OnceEveryTreeDie"); $qudo->work(); -----<Qudoのworkメソッド抜粋>-------------------------- sub work { my ($self, $work_delay) = @_; (中略) while (1) { #無限ループ sleep $work_delay unless $manager->work_once; } } 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 40
  • 42. 処理をする ~実際の場合~ # worker.pl perl worker.pl & 的な感じで無限ループプロセスをおいておく #!/usr/bin/env perl use strict; use warnings; use Qudo::Parallel::Manager; my $worker = Qudo::Parallel::Manager->new( databases => [+{...},...], #Qudoインスタンスの生成と同じ default_hooks => [qw/Qudo::Hook::Serialize::JSON/], manager_abilities => [qw/MyApp::Worker::OnceEveryTreeDie/], work_delay => 1, max_workers => 5, min_spare_workers => 5, max_spare_workers => 5, max_request_par_chiled => 5, auto_load_worker => 1, ); •Forkで高速化 }; •メモリリーク対策 $worker->run; •ジョブの処理中にWorkerをKillしても処理後にとまる対策 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 41
  • 43. 無限ループの中のエラーハンドリング my $res; Qudo::Workerのwork_safelyメソッドを抜粋 eval #evalトラップ $res = $class->work($job); }; if ( (my $e = $@) || ! $job->is_completed ) { if ( $job->retry_cnt < $class->max_retries ) { $job->reenqueue( { grabbed_until => 0, retry_cnt => $job->retry_cnt + 1, retry_delay => $class->retry_delay, } ); } else { $job->dequeue; } $job->failed("$e" || 'Job did not ...'); #Qudoのerrorテーブルにエラーを格納 } else { $job->dequeue; } 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 42
  • 44. max_retries = 1でerror時の再登録 use Qudo; my $qudo = Qudo->new(...); my $exceptions = $qudo->exception_list; my ($db, $exception) = each %$exceptions; while ( my ($db, $exception) = each %$exceptions ) { $qudo->manager->enqueue_from_failed_job( $exception, $db ); } 複数回リトライしていると、リトライしたすべて exeption_logテーブルに残ってしまうので、これだと同じ ジョブを何個もreenqueueしてしまう ↓ 次のページ参照 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 43
  • 45. max_retries > 1でerror時の再登録① ジョブの結果を一旦移せるようなテーブルを用意 CREATE TABLE worker_error_log( id int(10) unsigned NOT NULL auto_increment, funcname varchar(255) binary NOT NULL, arg mediumblob, uniqkey varchar(255) DEFAULT NULL, priority int(10) unsigned DEFAULT NULL, retried_fg tinyint(1) unsigned NOT NULL default 0, updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY funcname (funcname), KEY retried_fg (retried_fg) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 44
  • 46. max_retries > 1でerror時の再登録② package MyApp::Worker::Hook::NotifyReachMaxRetry; 独自のHookを用意 use base 'Qudo::Hook'; sub hook_point { 'post_work' } sub load { my ($class, $klass) = @_; $klass->hooks->{post_work}->{'notify_reach_max_retry'} = sub { my $job = shift; #max_retriesを超えてなおかつエラーだったらさっき用意したテーブルに入れる if ($job->is_failed && ( $job->funcname->max_retries <= ($job->retry_cnt) )) { $db->insert('worker_error_log',{ funcname => $job->funcname, arg => $job->arg, uniqkey => $job->uniqkey, priority => $job->priority + 100, #失敗している時点で優先順位は高いはず }); #アラートメールとかする } }; } sub unload { delete $_[1]->hooks->{post_work}->{'notify_reach_max_retry'} } 1; 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 45
  • 47. max_retries > 1でerror時の再登録③ 再登録する my @worker_error_log = $db->search('worker_error_log',{retried_fg => 0})->all; my @jobs = map { my $row = $_; [$row->funcname,{ arg => $row->arg, uniqkey => $row->uniqkey, priority => $row->priority, }]; } @worker_error_log; my @update_ids = map {$_->id} @worker_error_log; my $txn = $db->txn_scope; $db->update('worker_error_log', { retried_fg => 1 }, { id => { 'in' => ¥@update_ids } } ); bulk_enqueue(¥@jobs); $txn->commit; 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 46
  • 48. 動作確認テストをする use Test::More; use Qudo; #qudoのDBをテストでたちあげる(Test::mysqldでもなんでも) my $qudo = Qudo->new(...);# subtest 'enqueue' => sub { $qudo->enqueue('MyApp::Worker::OnceEveryTreeDie',+{}); my (undef,$job_count) = %{container('qudo')->job_count()}; is $job_count,1; }; subtest 'work' => sub { $qudo->manager->register_abilities("MyApp::Worker::OnceEveryTreeDie"); $qudo->manager->work_once; my (undef,$job_count) = %{container('qudo')->job_count()}; is $job_count,0; #実際のMyApp::Worker::OnceEveryTreeDieの中身もテスト? }; #qudoのテストだちあげたDBをけす done_testing; 明確な スキップ ケース別 Retry間隔 再実行な 多様なシリ ワーカーの 進捗把握 Retry設定 処理単位 機能 エラーログ 設定 失敗保存 アライザー 専有回避 47
  • 50. デモ一覧 <メニュー> • シンプルな処理の例 • 不安定な処理の例 • 複数retry後の失敗Job蓄積の例 <demo sample code> • https://github.com/hirobanex/QudoSample 49
  • 51. シンプルな処理の例 - Simpleの処理を見てもらう(lib/MyApp/Worker/Simple.pm) - enqueue - enqueue.plで登録する内容をみてもらう(vi script/simple/enqueue.pl) - enqueue(perl script/simple/enqueue.pl) - ジョブがたまったのをみてもらう(select * from job;) - JSONになっているよ - 処理する(perl ./script/simple/worker.pl) - ジョブがきえたのをみてもらう - select * from job ¥G - select * from job_status ¥G 50
  • 52. 不安定な処理の例 - OnceEveryTreeDieの処理を見てもらう(lib/MyApp/Worker/OnceEveryTreeDie.pm) - enqueue - enqueue.plで登録する内容をみてもらう,複数個いれる(vi script/once_over_tree_die/enqueue.pl) - enqueue(perl script/once_over_tree_die/enqueue.pl) - ジョブがたまったのをみてもらう - truncate job_status; - truncate exception_log; - select * from func ; - select * from job; - 処理する(perl ./script/once_over_tree_die/worker.pl) - (リトライカウントが増えている)select * from job; - (リトライカウントが増えている)select * from job; - (リトライカウントが増えている)select * from job; - 失敗の記録、10回生功した記録が残っている(select * from job_status; - エラーが2回分入っている(select * from exception_log ¥G 51
  • 53. 複数retry後の失敗Job蓄積の例 - Dieの処理を見てもらう(lib/MyApp/Worker/Die.pm) - enqueue - enqueue.plで登録する内容をみてもらう(vi script/max_retry/enqueue.pl) - enqueue(perl script/max_retry/enqueue.pl) - ジョブがたまったのをみてもらう - select * from func ; - select * from job ¥G - 処理する(perl ./script/max_retry/worker.pl) - 何も表示されません - (リトライカウントが増えている)select * from job ¥G - ジョブがきえたのをみてもらう - select * from job ¥G - リトライした回数分入っている(select * from job_status;) - エラー6回分入っている(select * from exception_log ¥G) - 独自実装に入っているか - Hookを確認(lib/MyApp/Worker/Hook/NotifyReachMaxRetry.pm) - テーブルを確認(select * from worker_error_log;) - reenqueue.plを実行(perl ./script/max_retry/reenqueue.pl) - テーブルを確認,retried_fgがたっている(select * from worker_error_log;) - ジョブに入っているか確認(select * from job;) 52
  • 54. Thanks nekokak(Qudo Auther)!! Thanks Hachioji.pm!! Thanks Perl Mongers!! 53