• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Danga::Socketの非同期処理の仕組みとPerlbalで非同期処理するプラグインを書く方法
 

Danga::Socketの非同期処理の仕組みとPerlbalで非同期処理するプラグインを書く方法

on

  • 4,604 views

 

Statistics

Views

Total Views
4,604
Views on SlideShare
4,476
Embed Views
128

Actions

Likes
2
Downloads
6
Comments
0

6 Embeds 128

http://coderwall.com 91
http://hiroki.jp 25
http://www.slideshare.net 8
http://test.hiroki.jp 2
http://webcache.googleusercontent.com 1
http://www.slideee.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Danga::Socketの非同期処理の仕組みとPerlbalで非同期処理するプラグインを書く方法 Danga::Socketの非同期処理の仕組みとPerlbalで非同期処理するプラグインを書く方法 Presentation Transcript

    • YAPC::Asia 2009 Tokyo 2009/9/10 宮下 剛輔
    • 自己紹介
      • 宮下 剛輔( mizzy )
      • ペパボで技術責任者というのをやってます
      • Perl 界一の子だくさん?
        • 11 月に 4 人目が生まれる予定です
    •  
    •  
    • アジェンダ
      • イベント駆動型プログラミングによる非同期処理
      • Danga::Socket の非同期処理の仕組み
      • Perlbal の動作概要
      • Perlbal プラグインでの非同期処理
      • まとめ
    •  
    • イベント駆動型プログラミング
      • イベントを待機し、起こったイベントに従って処理を行うプログラミングパラダイム
      • フロー型プログラミングに対する概念
    • イベントの種類
      • I/O
        • I/O の読込可能 / 書込可能状態でイベント発生
      • タイマー
        • 一定時間後にイベント発生
      • シグナル
        • シグナル受信時にイベント発生
      • 子プロセス
        • 子プロセス終了時にイベント発生
    • メインループ
      • イベント駆動型プログラミングは、「イベント処理登録」 -> 「メインループ突入」という流れ
      • イベントループとも呼ばれる
      • イベント発生の有無をループする度に確認し、発生したイベントに応じた処理を行う
      • イベント処理後ループに戻り、次にイベント発生するまでループを繰り返す
      • このような流れで非同期に処理を行う
    • メインループの例 タイマー処理 I/O イベント待ち I/O イベント処理 ポストメインループ処理
    •  
    • Danga::Socket が対応してるイベント
      • I/O イベント
      • タイマーイベント
    • I/O イベント処理
      • Danga::Socket では以下の I/O 多重化機構に対応している
        • kqueue
        • epoll
        • poll
      • 適切な I/O 多重化機構を自動で選択してくれる
    • epoll の例
      • use Sys::Syscall
      • $epfd = epoll_create (1024);
      • epoll_ctl ( $epfd , EPOLL_CTL_ADD, $fd , EPOLLIN|EPOLLOUT);
      • while (1) { # ここからイベントループ
      • epoll_wait ( $epfd , 1024, $timeout, @events );
      • for $event ( @events ) {
      • # イベントに応じた処理
      • }
      • }
    • Danga::Socket での I/O イベント登録
      • use base ‘Danga::Socket’;
      • sub new {
      • # ファイルディスクリプタを new に渡す
      • $self->SUPER::new( $fd );
      • }
      • sub event_read {
      • # $fd が読込可能になった時に実行
      • }
      • sub event_write {
      • # $fd が書込可能になった時に実行
      • }
    • Danga::Socket での I/O イベント登録 その 2
      • Danga::Socket->AddOtherFds(
      • $fd => sub {
      • # read イベントでの処理
      • },
      • );
    • Danga::Socket での I/O イベント登録 その 3
      • Danga::Socket::Callback->new(
      • handle => $fd ,
      • on_read_ready => sub {
      • # read イベント処理
      • },
      • on_write_ready => sub {
      • # write イベント処理
      • },
      • );
    • Danga::Socket でのタイマーイベント登録
      • Danga::Socket->AddTimer(
      • 10,
      • sub {
      • # 10 秒後に実行される処理
      • },
      • }
    • Danga::Socket でのメインループの開始
      • Danga::Socket->EventLoop();
    • メインループ処理のおさらい タイマー処理 I/O イベント待ち I/O イベント処理 ポストイメインループ処理
    •  
    • Perlbal の動作(リバースプロキシとして利用の場合) BackendHTTP ClientProxy TCPListener Client Server ClientProxy Client BackendHTTP Danga::Socket ベースの オブジェクト
    • Perlbal プラグインの動作 (start_proxy_request フック) BackendHTTP ClientProxy TCPListener Client Server Plugin::Hoge 今回のターゲット
    •  
    • 対象となるフック
      • start_proxy_request フックでの実行を前提として解説していきます
    • 同期処理プラグインの場合 ClientProxy TCPListener Client Server Plugin::Sync Client
    • 非同期処理プラグインの場合 ClientProxy TCPListener Client Server Plugin::Async Client ClientProxy
    • プラグインを非同期にするには?
      • プラグインの処理を Danga::Socket のイベントループに組み込む
        • Danga::Socket ベースのクラスを作成
        • または Danga::Socket::Callback を利用して処理を書く
        • Danga::Socket::AddTimer でタイマー処理しても OK
        • 利用するライブラリにも注意
          • ブロックしないライブラリを使う
          • どうしてもブロックしてしまう処理は、 Gearman::Client::Async で外出し
    • プラグインを非同期にするには?
      • 非同期処理が完了したら、次のフェーズに処理を移す
        • プラグインのコールバックを利用
        • Perlbal 本体の修正も必要
    • 非同期処理するクラス
      • package My::Drizzle ;
      • use base ‘Danga::Socket’ ;
      • use Net::Drizzle ':constants' ;
      • sub new {
      • $self->SUPER::new($fh);
      • $self->watch_read(1);
      • }
      • sub event_read {
      • # DB リクエスト状態確認と完了時のコールバック処理
      • }
    • 注意
      • Danga::Socket::Callback をつかっても OK
      • AddOtherFds は使えない
        • AddOtherFds で登録されたファイルディスクリプタは、イベントループ突入の最初にしか EPOLL_CTL_ADD や EV_ADD されない
      • 直接 epoll_ctl とか呼び出してもいいけど、ポータビリティは低い
    • プラグイン register 処理
      • package Perlbal::Plugin::AsyncDb ;
      • sub register {
      • my ( $class, $svc ) = @_;
      • $svc->register_hook(
      • 'Async' => 'start_proxy_request',
      • &request_db ,
      • );
      • return 1;
      • }
    • 非同期処理クラスの呼び出し
      • sub request_db {
      • my Perlbal::ClientProxy $client = shift ;
      • My::Drizzle->new(
      • callback => sub {
      • # 完了時のコールバック処理
      • },
      • );
      • return 1; # 超重要ポイント!
      • }
    • return 0 の場合 BackendHTTP ClientProxy TCPListener Client Server Plugin::Async Plugin::Async の処理が 終わらないのに次の処理へ
    • return 1 &コールバック処理 BackendHTTP ClientProxy TCPListener Client Plugin::Async 処理を終了して イベントループへ Server return 1 コールバック
    • コールバックで必要な処理
      • ClientProxy の処理が handle_request() の途中で終了してイベントループに戻っている
      • プラグインの処理が完了したら、 ClientProxy の次の処理から再開
      • 停止してるのは、 handle_request() 中の以下のコード
      • return if $svc->run_hook(
      • 'start_proxy_request', $self
      • );
      • この次から処理を再開するようにする
    • コールバック処理
      • my Perlbal::ClientProxy
      • $client = shift ;
      • My::Drizzle->new(
      • callback => sub {
      • $client->{async_complete} = 1;
      • $client->handle_request;
      • },
      • );
    • ClientProxy::handle_request の修正
      • - return if $svc->run_hook(
      • - 'start_proxy_request', $self
      • - );
      • + unless ( $self->{async_complete} ) {
      • + return if $svc->run_hook(
      • + 'start_proxy_request', $self
      • + );
      • + }
      • + $self->{async_complete} = 0;
    •  
    • 非同期処理プラグインを書くポイント
      • 非同期にしたい処理は Danga::Socket のイベントループにつっこむ
      • プラグイン処理が呼び出されたら return 1
      • プラグイン処理が完了したら、コールバックで処理を再開してやる
      • Perlbal 本体の修正も必要
      • プラグインの実行順にも注意
        • return 1 するとそれ以降の同じフックのプラグインは実行されない
    •