Your SlideShare is downloading. ×
0
YAPC::Asia 2009 Tokyo 2009/9/10 宮下 剛輔
自己紹介 <ul><li>宮下 剛輔( mizzy ) </li></ul><ul><li>ペパボで技術責任者というのをやってます </li></ul><ul><li>Perl 界一の子だくさん? </li></ul><ul><ul><li>1...
 
 
アジェンダ <ul><li>イベント駆動型プログラミングによる非同期処理 </li></ul><ul><li>Danga::Socket の非同期処理の仕組み </li></ul><ul><li>Perlbal の動作概要 </li></ul>...
 
イベント駆動型プログラミング <ul><li>イベントを待機し、起こったイベントに従って処理を行うプログラミングパラダイム </li></ul><ul><li>フロー型プログラミングに対する概念 </li></ul>
イベントの種類 <ul><li>I/O </li></ul><ul><ul><li>I/O の読込可能 / 書込可能状態でイベント発生 </li></ul></ul><ul><li>タイマー </li></ul><ul><ul><li>一定時間...
メインループ <ul><li>イベント駆動型プログラミングは、「イベント処理登録」 -> 「メインループ突入」という流れ </li></ul><ul><li>イベントループとも呼ばれる </li></ul><ul><li>イベント発生の有無をル...
メインループの例 タイマー処理 I/O イベント待ち I/O イベント処理 ポストメインループ処理
 
Danga::Socket が対応してるイベント <ul><li>I/O イベント </li></ul><ul><li>タイマーイベント </li></ul>
I/O イベント処理 <ul><li>Danga::Socket では以下の I/O 多重化機構に対応している </li></ul><ul><ul><li>kqueue </li></ul></ul><ul><ul><li>epoll </li...
epoll の例 <ul><li>use  Sys::Syscall </li></ul><ul><li>$epfd  =  epoll_create (1024); </li></ul><ul><li>epoll_ctl ( $epfd , ...
Danga::Socket での I/O イベント登録 <ul><li>use   base  ‘Danga::Socket’; </li></ul><ul><li>sub   new  { </li></ul><ul><li>#  ファイルデ...
Danga::Socket での I/O イベント登録 その 2 <ul><li>Danga::Socket->AddOtherFds( </li></ul><ul><li>$fd  =>  sub  { </li></ul><ul><li>#...
Danga::Socket での I/O イベント登録 その 3 <ul><li>Danga::Socket::Callback->new( </li></ul><ul><li>handle   =>  $fd , </li></ul><ul>...
Danga::Socket でのタイマーイベント登録 <ul><li>Danga::Socket->AddTimer( </li></ul><ul><li>10, </li></ul><ul><li>sub  { </li></ul><ul><...
Danga::Socket でのメインループの開始 <ul><li>Danga::Socket->EventLoop(); </li></ul>
メインループ処理のおさらい タイマー処理 I/O イベント待ち I/O イベント処理 ポストイメインループ処理
 
Perlbal の動作(リバースプロキシとして利用の場合) BackendHTTP ClientProxy TCPListener Client Server ClientProxy Client BackendHTTP Danga::Sock...
Perlbal プラグインの動作 (start_proxy_request フック) BackendHTTP ClientProxy TCPListener Client Server Plugin::Hoge 今回のターゲット
 
対象となるフック <ul><li>start_proxy_request フックでの実行を前提として解説していきます </li></ul>
同期処理プラグインの場合 ClientProxy TCPListener Client Server Plugin::Sync Client
非同期処理プラグインの場合 ClientProxy TCPListener Client Server Plugin::Async Client ClientProxy
プラグインを非同期にするには? <ul><li>プラグインの処理を Danga::Socket のイベントループに組み込む </li></ul><ul><ul><li>Danga::Socket ベースのクラスを作成 </li></ul></u...
プラグインを非同期にするには? <ul><li>非同期処理が完了したら、次のフェーズに処理を移す </li></ul><ul><ul><li>プラグインのコールバックを利用 </li></ul></ul><ul><ul><li>Perlbal ...
非同期処理するクラス <ul><li>package   My::Drizzle ; </li></ul><ul><li>use   base   ‘Danga::Socket’ ; </li></ul><ul><li>use   Net::D...
注意 <ul><li>Danga::Socket::Callback をつかっても OK </li></ul><ul><li>AddOtherFds は使えない </li></ul><ul><ul><li>AddOtherFds で登録されたフ...
プラグイン register 処理 <ul><li>package   Perlbal::Plugin::AsyncDb ; </li></ul><ul><li>sub   register  { </li></ul><ul><li>my  (...
非同期処理クラスの呼び出し <ul><li>sub   request_db  { </li></ul><ul><li>my  Perlbal::ClientProxy $client =  shift ; </li></ul><ul><li>...
return 0  の場合 BackendHTTP ClientProxy TCPListener Client Server Plugin::Async Plugin::Async の処理が 終わらないのに次の処理へ
return 1 &コールバック処理 BackendHTTP ClientProxy TCPListener Client Plugin::Async 処理を終了して イベントループへ Server return 1 コールバック
コールバックで必要な処理 <ul><li>ClientProxy の処理が handle_request() の途中で終了してイベントループに戻っている </li></ul><ul><li>プラグインの処理が完了したら、 ClientProxy...
コールバック処理 <ul><li>my  Perlbal::ClientProxy  </li></ul><ul><li>$client =  shift ; </li></ul><ul><li>My::Drizzle->new( </li><...
ClientProxy::handle_request の修正 <ul><li>-  return   if  $svc->run_hook( </li></ul><ul><li>-   'start_proxy_request', $self...
 
非同期処理プラグインを書くポイント <ul><li>非同期にしたい処理は Danga::Socket のイベントループにつっこむ </li></ul><ul><li>プラグイン処理が呼び出されたら return 1 </li></ul><ul>...
 
Upcoming SlideShare
Loading in...5
×

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

3,271

Published on

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,271
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
7
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

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

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

    Clipping is a handy way to collect important slides you want to go back to later.

×