SlideShare a Scribd company logo
非同期 I/O  概説 Introduction to Asynchronous I/O AIO, I/O Multiplexing…
今日の目的 非同期 I/O とは何かを知る 非同期 I/O を使うと何がうれしいのかを知る 非同期 I/O を実現する手段(複数)を知る
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
ネ��トワークサーバのお仕事を考えてみる Web サーバとか I/O (ネットワーク I/O 、ディスク I/O )に着目 リクエストを受ける(ネットワーク read ) ディスクからコンテンツを読む(ディスク read ) レスポンスを返す(ネットワーク write )
一般的な I/O の特性 read(2)/write(2) いつでもデータが読める / 書けるとは限らない 準備ができるまで戻らない=待たされる 「 I/O ブロッキング」
ネットワークサーバ ×I/O ネットワークサーバ ネットワーク I/O 、ディスク I/O を伴う I/O ブロッキング I/O で待たされる 単一の処理(リクエスト / レスポンス)を完了するまでに時間がかかる(待たされるので) 単位時間の処理能力が下がる 並行度( concurrent )が下がる
The C10K problem The C10K problem http://www.kegel.com/c10k.html http://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem “ 「 C10K 問題」(クライアント 1 万台問題)とは、ハードウエアの性能上は問題がなくても、あまりにクライアントの数が多くなるとサーバがパンクする問題のこと” 同時処理数を上げるための、 I/O 戦略について説明しているドキュメント
C10K - I/O 戦略 1スレッド:1クライアントで、ブロッキング I/O × 各スレッドでスタックを消費する NPTL の場合 8MB/thread 1スレッド:多クライアントで、ノンブロッキング I/O (I/O 多重化 ) select, poll, epoll, kqueue, /dev/poll 1スレッド:多クライアントで、 AIO POSIX AIO, libaio 非同期 I/O
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
I/O モデルの整理 Synchronous Asynchronous Blocking Non-blocking read/write read/write (O_NONBLOCK) I/O multiplexing I/O 多重化 (select, poll) AIO 非同期 I/O (POSIX AIO, libaio) ~  Boost application performance using asynchronous I/O http://www-128.ibm.com/developerworks/linux/library/l-async/
I/O 多重化とは I/O 可能になった fd の集合を通知するしくみ 通知後に、 read(2),write(2) を行う 実装 select(2) I/O 可否の検査のためにすべての fd を走査する必要があるので、 fd が多いと効率が悪い FD_SETSIZE (Linux だと 1024)  までしか fd を監視できない poll(2) FD_SETSIZE の上限がない select(2) epoll(2) Linux, kqueue(2) FreeBSD, /dev/poll Solaris I/O 可能な fd だけ返却される OS のよって実装がばら��ら-> libevent
AIO とは 非同期に I/O を行うしくみ 通知時にはすでに read や write が完了している read の場合はバッファにデータが入っている 実装 POSIX AIO http://opengroup.org/onlinepubs/009695399/basedefs/aio.h.html Linux,  FreeBSD ,  Mac OS X , Solaris, HP-UX, AIX libaio http:// lse.sourceforge.net/io/aio.html Linux 独自の実装
I/O 多重化  vs AIO select(2) はブロックする  ※タイムアウトは指定可能 通知後に read(2) が必要=コンテキストスイッチ
I/O 多重化  vs AIO ブロックしない=ほかの処理を行える シグナルかコールバックが非同期に呼ばれる 通知時には既にバッファに入ってる
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
AIO の実装 –  Linux 2.6 POSIX AIO – POSIX 準拠 aio_read / aio_write, aio_error, aio_return, … 通知方法は、スレッド( SIGEV_THREAD )とシグナル( SIGEV_SIGNAL )の両方に対応している 実はシステムコールじゃなくてライブラリ関数( librt ) 裏でいくつかスレッドを作ってがんばってるっぽい libaio – Linux 独自 io_queue_init, io_prep_pread / io_prep_pwrite, io_set_callback, io_submit, … http://lse.sourceforge.net/io/aio.html システムコール POSIX AIO より性能は上
AIO の実装 –  FreeBSD 6.2 POSIX AIO – POSIX 準拠 aio_read / aio_write, aio_error, aio_return, … システムコール 通知方法は SIGEV_KEVENT のみ SIGEV_KEVENT: kqueue(2) と kevent(2) で通知 SIGEV_THREAD 、 SIGEV_SIGNAL は使えない><
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
POSIX AIO –  スレッド通知 iocb->aio_fildes = … iocb->aio_buf  = … iocb->aio_nbytes = … iocb->aio_offset = … iocb->aio_sigevent.sigev_notify =  SIGEV_THREAD ; iocb->aio_sigevent.sigev_notify_function =  rd_done ; iocb->aio_sigevent.sigev_value.sival_ptr =  iocb ; aio_read (iocb); /* void  rd_done (sigval_t sigval) */ iocb = (struct aiocb *)sigval.sival_ptr; while ((rc =  aio_error (iocb)) == EINPROGRESS); rc =  aio_return (iocb); char *buf = (void *)iocb->aio_buf; struct aiocb の初期化 aiocb を取り出す データが詰まってる buf 返り値を得る エラー状態を確認 スレッドを起床して通知 コールバック関数 自分自身を格納 非同期処理をリクエスト
POSIX AIO –  スレッド通知/注意点 スレッドセーフ ではない 関数の一覧 http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_01
POSIX AIO –  シグナル通知 iocb->aio_fildes = … iocb->aio_buf  = … iocb->aio_nbytes = … iocb->aio_offset = … iocb->aio_sigevent.sigev_notify =  SIGEV_SIGNAL ; iocb->aio_sigevent.sigev_signo  =  SIGIO_READ ; iocb->aio_sigevent.sigev_value.sival_ptr =  iocb ; aio_read (iocb); /* void  rd_done (int signo, siginfo_t *info, void *context) */ iocb = (struct aiocb *)info->si_value.sival_ptr; while ((rc =  aio_error (iocb)) == EINPROGRESS); rc =  aio_return (iocb); char *buf = (void *)iocb->aio_buf; struct aiocb の初期化 aiocb を取り出す ☚ データが詰まってる buf 返り値を得る エラー状態を確認 シグナルで通知 ☚ 発生シグナルを指定 ☚ 自分自身を格納 非同期処理をリクエスト sigemptyset(&sigact_r.sa_mask); sigact_r.sa_flags = SA_SIGINFO; sigact_r.sa_sigaction =  rd_done ; sigaction( SIGIO_READ , &sigact_r, NULL); シグナル���ンドラ
POSIX AIO –  シグナル通知/注意点 シグナルセーフ である 関数の一覧 http://www.linux.or.jp/JM/html/LDP_man-pages/man7/signal.7.html#lbAH
libaio io_queue_init (AIO_MAXIO, &myctx); struct iocb *ioq[n]; for (i=0; i<=n; i++) { io_prep_pread (iocb, srcfd, iosize, offset); io_set_callback (iocb, rd_done); ioq[i] = iocb; } io_submit (myctx, n, ioq); io_queue_run (myctx); io_queue_wait(myctx, NULL); /* void rd_done(io_context_t ctx,  struct iocb *iocb , long res,…) */ int iosize  = iocb->u.c.nbytes; char *buf  = iocb->u.c.buf; off_t offset = iocb->u.c.offset; 非同期イベント処理-> CB データが詰まってる buf コンテキストの初期化 iocb のセットアップ (read) コールバック関数のセット 非同期処理をリクエスト 非同期処理の完了を待つ
サンプルコードのありか http://klab.klab.org/trac/general/wiki/aio-copy
アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
sival_ptr と sigval_ptr sigval union - /usr/include/sys/signal.h  sival_ptr POSIX, Linux si g val_ptr FreeBSD, Mac OS X /* borrow from lighttpd-1.5.0 */ #if (defined(__FreeBSD__) || defined(__DragonFly__)) #define sival_ptr sigval_ptr #endif
AIO を使っているプロダクト lighttpd-1.5.0 (PRE RELEASE) Linux : libaio (io_submit + io_getevents) POSIX : AIO (SIGEV_THREAD) FreeBSD : × nginx-0.6.4 ( んぎんくす ) Linux : × (たぶん…) FreeBSD : AIO (SIGEV_KEVENT) io_queue_* を使っていない。 が、実は io_queue_* は io_setup や io_getevents のラッパーにすぎない
POSIX AIO で扱えるファイルディスクリプタ regular file 名前付きパイプ ソケット なんでもおk
libaio で扱えるファイルディスクリプタ regular file ソケットはダメ 名前付きパイプもダメ
では、 lighttpd はどこで libaio を使っているのか? tmpfs(/dev/shm/) にファイルを作る tmpfs 上のファイルを mmap(2) する 非同期に、 ファイルからデータを read して、 mmap(2) した領域に write する tmpfs 上のファイルを sendfile(2) でソケットに送る read(2)+write(2) よりも mmap(2)+sendfile(2) のほうが早い。 なぜなら、カーネル内でコピーが行われるから。
レベルトリガとエッジトリガ epoll(2) デフォルト :  レベルトリガ EPOLLET :  エッジトリガ
レベルトリガとエッジトリガ レベルトリガ 越えている間はイベントが起こり続ける エッジトリガ 超えた / 下回ったときだけイベントが起こる ★ ★ ★ ★ ★ ★ ★ ★
レベルトリガとエッジトリガ レベルトリガ 越えている間はイベントが起こり続ける エッジトリガ 超えた / 下回ったときだけイベントが起こる ★ ★ ★ ★ ★ ★ ★ ★
Syslets, Threadlets Syslets, Threadlets (≧2.6.24) http://lwn.net/Articles/219954/ http://www.cuspy.org/blog/2007/07/25/ “ Syslets” はカーネル内で小さなプログラムを動作させるための手段であり、システムコールを非同期かつユーザー空間から出ずに実行する方法です。 “ Threadlets” はユーザー空間で非同期のコードを実行するメカニズムと同類です。 どちらのケースでも、コードの問い合わせがブロックしない限り同期的に実行されますが、もし何かを待たなければならない場合カーネルはスレッドを生成し ( スペアのスレッドが再利用される場合もある ) 、ユーザー空間でそのスレッドを実行します。 このパッチの最初の動機はメンテナンスに大変な手間が掛かる  AIO  のアプローチを使わずに、完全な非同期  I/O  を実装を可能にすることでした。 以来、 syslets  と  threadlets  はシステムコールの非同期実行を可能にしただけでなく、より多くのアプリケーションの対応が可能となりました。
参考文献 The C10K problem http://www.kegel.com/c10k.html http://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem Boost application performance using asynchronous I/O / IBM developerWorks http://www-128.ibm.com/developerworks/linux/library/l-async/ Kernel Asynchronous I/O (AIO) Support for Linux http:// lse.sourceforge.net/io/aio.html
おしまい

More Related Content

Aio

  • 1. 非同期 I/O 概説 Introduction to Asynchronous I/O AIO, I/O Multiplexing…
  • 2. 今日の目的 非同期 I/O とは何かを知る 非同期 I/O を使うと何がうれしいのかを知る 非同期 I/O を実現する手段(複数)を知る
  • 3. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 4. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 5. ネットワークサーバのお仕事を考えてみる Web サーバとか I/O (ネットワーク I/O 、ディスク I/O )に着目 リクエストを受ける(ネットワーク read ) ディスクからコンテンツを読む(ディスク read ) レスポンスを返す(ネットワーク write )
  • 6. 一般的な I/O の特性 read(2)/write(2) いつでもデータが読める / 書けるとは限らない 準備ができるまで戻らない=待たされる 「 I/O ブロッキング」
  • 7. ネットワークサーバ ×I/O ネットワークサーバ ネットワーク I/O 、ディスク I/O を伴う I/O ブロッキング I/O で待たされる 単一の処理(リクエスト / レスポンス)を完了するまでに時間がかかる(待たされるので) 単位時間の処理能力が下がる 並行度( concurrent )が下がる
  • 8. The C10K problem The C10K problem http://www.kegel.com/c10k.html http://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem “ 「 C10K 問題」(クライアント 1 万台問題)とは、ハードウエアの性能上は問題がなくても、あまりにクライアントの数が多くなるとサーバがパンクする問題のこと” 同時処理数を上げるための、 I/O 戦略について説明しているドキュメント
  • 9. C10K - I/O 戦略 1スレッド:1クライアントで、ブロッキング I/O × 各スレッドでスタックを消費する NPTL の場合 8MB/thread 1スレッド:多クライアントで、ノンブロッキング I/O (I/O 多重化 ) select, poll, epoll, kqueue, /dev/poll 1スレッド:多クライアントで、 AIO POSIX AIO, libaio 非同期 I/O
  • 10. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 11. I/O モデルの整理 Synchronous Asynchronous Blocking Non-blocking read/write read/write (O_NONBLOCK) I/O multiplexing I/O 多重化 (select, poll) AIO 非同期 I/O (POSIX AIO, libaio) ~ Boost application performance using asynchronous I/O http://www-128.ibm.com/developerworks/linux/library/l-async/
  • 12. I/O 多重化とは I/O 可能になった fd の集合を通知するしくみ 通知後に、 read(2),write(2) を行う 実装 select(2) I/O 可否の検査のためにすべての fd を走査する必要があるので、 fd が多いと効率が悪い FD_SETSIZE (Linux だと 1024) までしか fd を監視できない poll(2) FD_SETSIZE の上限がない select(2) epoll(2) Linux, kqueue(2) FreeBSD, /dev/poll Solaris I/O 可能な fd だけ返却される OS のよって実装がばらばら-> libevent
  • 13. AIO とは 非同期に I/O を行うしくみ 通知時にはすでに read や write が完了している read の場合はバッファにデータが入っている 実装 POSIX AIO http://opengroup.org/onlinepubs/009695399/basedefs/aio.h.html Linux, FreeBSD , Mac OS X , Solaris, HP-UX, AIX libaio http:// lse.sourceforge.net/io/aio.html Linux 独自の実装
  • 14. I/O 多重化 vs AIO select(2) はブロックする ※タイムアウトは指定可能 通知後に read(2) が必要=コンテキストスイッチ
  • 15. I/O 多重化 vs AIO ブロックしない=ほかの処理を行える シグナルかコールバックが非同期に呼ばれる 通知時には既にバッファに入ってる
  • 16. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 17. AIO の実装 – Linux 2.6 POSIX AIO – POSIX 準拠 aio_read / aio_write, aio_error, aio_return, … 通知方法は、スレッド( SIGEV_THREAD )とシグナル( SIGEV_SIGNAL )の両方に対応している 実はシステムコールじゃなくてライブラリ関数( librt ) 裏でいくつかスレッドを作ってがんばってるっぽい libaio – Linux 独自 io_queue_init, io_prep_pread / io_prep_pwrite, io_set_callback, io_submit, … http://lse.sourceforge.net/io/aio.html システムコール POSIX AIO より性能は上
  • 18. AIO の実装 – FreeBSD 6.2 POSIX AIO – POSIX 準拠 aio_read / aio_write, aio_error, aio_return, … システムコール 通知方法は SIGEV_KEVENT のみ SIGEV_KEVENT: kqueue(2) と kevent(2) で通知 SIGEV_THREAD 、 SIGEV_SIGNAL は使えない><
  • 19. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 20. POSIX AIO – スレッド通知 iocb->aio_fildes = … iocb->aio_buf = … iocb->aio_nbytes = … iocb->aio_offset = … iocb->aio_sigevent.sigev_notify = SIGEV_THREAD ; iocb->aio_sigevent.sigev_notify_function = rd_done ; iocb->aio_sigevent.sigev_value.sival_ptr = iocb ; aio_read (iocb); /* void rd_done (sigval_t sigval) */ iocb = (struct aiocb *)sigval.sival_ptr; while ((rc = aio_error (iocb)) == EINPROGRESS); rc = aio_return (iocb); char *buf = (void *)iocb->aio_buf; struct aiocb の初期化 aiocb を取り出す データが詰まってる buf 返り値を得る エラー状態を確認 スレッドを起床して通知 コールバック関数 自分自身を格納 非同期処理をリクエスト
  • 21. POSIX AIO – スレッド通知/注意点 スレッドセーフ ではない 関数の一覧 http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_01
  • 22. POSIX AIO – シグナル通知 iocb->aio_fildes = … iocb->aio_buf = … iocb->aio_nbytes = … iocb->aio_offset = … iocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL ; iocb->aio_sigevent.sigev_signo = SIGIO_READ ; iocb->aio_sigevent.sigev_value.sival_ptr = iocb ; aio_read (iocb); /* void rd_done (int signo, siginfo_t *info, void *context) */ iocb = (struct aiocb *)info->si_value.sival_ptr; while ((rc = aio_error (iocb)) == EINPROGRESS); rc = aio_return (iocb); char *buf = (void *)iocb->aio_buf; struct aiocb の初期化 aiocb を取り出す ☚ データが詰まってる buf 返り値を得る エラー状態を確認 シグナルで通知 ☚ 発生シグナルを指定 ☚ 自分自身を格納 非同期処理をリクエスト sigemptyset(&sigact_r.sa_mask); sigact_r.sa_flags = SA_SIGINFO; sigact_r.sa_sigaction = rd_done ; sigaction( SIGIO_READ , &sigact_r, NULL); シグナルハンドラ
  • 23. POSIX AIO – シグナル通知/注意点 シグナルセーフ である 関数の一覧 http://www.linux.or.jp/JM/html/LDP_man-pages/man7/signal.7.html#lbAH
  • 24. libaio io_queue_init (AIO_MAXIO, &myctx); struct iocb *ioq[n]; for (i=0; i<=n; i++) { io_prep_pread (iocb, srcfd, iosize, offset); io_set_callback (iocb, rd_done); ioq[i] = iocb; } io_submit (myctx, n, ioq); io_queue_run (myctx); io_queue_wait(myctx, NULL); /* void rd_done(io_context_t ctx, struct iocb *iocb , long res,…) */ int iosize = iocb->u.c.nbytes; char *buf = iocb->u.c.buf; off_t offset = iocb->u.c.offset; 非同期イベント処理-> CB データが詰まってる buf コンテキストの初期化 iocb のセットアップ (read) コールバック関数のセット 非同期処理をリクエスト 非同期処理の完了を待つ
  • 26. アジェンダ 非同期 I/O を使う理由 非同期 I/O とは? AIO の実装を紹介 AIO の使い方 落穂ひろい
  • 27. sival_ptr と sigval_ptr sigval union - /usr/include/sys/signal.h sival_ptr POSIX, Linux si g val_ptr FreeBSD, Mac OS X /* borrow from lighttpd-1.5.0 */ #if (defined(__FreeBSD__) || defined(__DragonFly__)) #define sival_ptr sigval_ptr #endif
  • 28. AIO を使っているプロダクト lighttpd-1.5.0 (PRE RELEASE) Linux : libaio (io_submit + io_getevents) POSIX : AIO (SIGEV_THREAD) FreeBSD : × nginx-0.6.4 ( んぎんくす ) Linux : × (たぶん…) FreeBSD : AIO (SIGEV_KEVENT) io_queue_* を使っていない。 が、実は io_queue_* は io_setup や io_getevents のラッパーにすぎない
  • 29. POSIX AIO で扱えるファイルディスクリプタ regular file 名前付きパイプ ソケット なんでもおk
  • 30. libaio で扱えるファイルディスクリプタ regular file ソケットはダメ 名前付きパイプもダメ
  • 31. では、 lighttpd はどこで libaio を使っているのか? tmpfs(/dev/shm/) にファイルを作る tmpfs 上のファイルを mmap(2) する 非同期に、 ファイルからデータを read して、 mmap(2) した領域に write する tmpfs 上のファイルを sendfile(2) でソケットに送る read(2)+write(2) よりも mmap(2)+sendfile(2) のほうが早い。 なぜなら、カーネル内でコピーが行われるから。
  • 32. レベルトリガとエッジトリガ epoll(2) デフォルト : レベルトリガ EPOLLET : エッジトリガ
  • 33. レベルトリガとエッジトリガ レベルトリガ 越えている間はイベントが起こり続ける エッジトリガ 超えた / 下回ったときだけイベントが起こる ★ ★ ★ ★ ★ ★ ★ ★
  • 34. レベルトリガとエッジトリガ レベルトリガ 越えている間はイベントが起こり続ける エッジトリガ 超えた / 下回ったときだけイベントが起こる ★ ★ ★ ★ ★ ★ ★ ★
  • 35. Syslets, Threadlets Syslets, Threadlets (≧2.6.24) http://lwn.net/Articles/219954/ http://www.cuspy.org/blog/2007/07/25/ “ Syslets” はカーネル内で小さなプログラムを動作させるための手段であり、システムコールを非同期かつユーザー空間から出ずに実行する方法です。 “ Threadlets” はユーザー空間で非同期のコードを実行するメカニズムと同類です。 どちらのケースでも、コードの問い合わせがブロックしない限り同期的に実行されますが、もし何かを待たなければならない場合カーネルはスレッドを生成し ( スペアのスレッドが再利用される場合もある ) 、ユーザー空間でそのスレッドを実行します。 このパッチの最初の動機はメンテナンスに大変な手間が掛かる AIO のアプローチを使わずに、完全な非同期 I/O を実装を可能にすることでした。 以来、 syslets と threadlets はシステムコールの非同期実行を可能にしただけでなく、より多くのアプリケーションの対応が可能となりました。
  • 36. 参考文献 The C10K problem http://www.kegel.com/c10k.html http://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem Boost application performance using asynchronous I/O / IBM developerWorks http://www-128.ibm.com/developerworks/linux/library/l-async/ Kernel Asynchronous I/O (AIO) Support for Linux http:// lse.sourceforge.net/io/aio.html