非同期I/Oの謎

<非同期I/Oの謎>
ペンネーム: ベロ

明けましておめでとうございます。

今回は、以前のメルマガの補足検証となります。(どうしてもメルマガにて公開しておき
たかったので、無理を言って公開させてもらいました)

以前、弊社メルマガ(ASMLibに関する検証 その6 *1)にてASMLibの非同期I/Oに関する検証
を行っていました。そこで、各プロセスがファイルをオープンする際のモードおよび
ファイルの読み込み、書き込みのファンクションをトレースしています。また、検証用の
簡単なCのコードも掲載していました。

*1) https://www.insight-tec.com/mailmagazine/ora3/vol421.html

一部、読者の方から「この検証結果では分かりづらい」「そもそも非同期I/Oとは?」など
ご意見を頂きましたので、振り返って、Oracleの非同期I/Oの動作について再検証を行い
ました。

検証環境は以下の通りです。

OS: Oracle Enterprise Linux 5.5 (64bit)
Oracle: Oracle 11.2.0.1 Enterprise Edition (64bit)

* 今回の検証はLinux限定の検証です

まず、OS(libaioライブラリを含む)による非同期I/Oがどのように動作しているか簡単な
コードで確認します。

今回確認用に使用したソースはLinux Foundationにあるaiocp(*2)を使用しました。

*2) http://devresources.linuxfoundation.org/daniel/AIO/aiocp.c

aiocpの処理内容はざっと以下の通りです。

1. コピー元ファイルのopen
2. コピー先ファイルのopen
3. 1に対してreadを非同期I/Oで要求し、その完了をコールバック関数で待ち受ける
4. 3のread要求が完了した場合、コールバック関数が呼ばれ、さらに2に対して非同期で
   write要求が発行される
5. write要求も完了時にはコールバック関数が呼ばれる
6. 全てのread/writeの要求が発行された場合、その完了を待って終了

* libaio経由のI/Oはio_submit(2)とio_getevents(2)となります

つまり、処理の重いwriteの間に処理の軽いreadを多く発行させて、全体のスループット
を上げることを期待したサンプルと言えます。以下、本当にそうなっているか確認して
みます。

1. aiocpのソースを取得してコンパイルします。

$ wget http://devresources.linuxfoundation.org/daniel/AIO/aiocp.c  
$ gcc -laio -o aiocp aiocp.c  

2. コピー元ファイルの作成

$ dd if=/dev/zero of=srcfile bs=1M count=10
* 今回は、10MBのファイルを別ファイルにコピーするテストを実施します。その際の
  ブロックサイズはOracleのブロックサイズと合わせ8KBとしました。

3. ファイルのオープンモードにO_SYNCとO_CREATを付与して実行

$ time ./aiocp -d -b 8K -f O_SYNC -f O_CREAT srcfile dstfile
real    0m1.360s
user    0m0.002s
sys     0m0.123

4. ファイルのオープンモードにO_SYNC、O_DIRECTとO_CREATを付与して実行

$ time ./aiocp -d -b 8K -f O_SYNC -f O_DIRECT -f O_CREAT srcfile dstfile
real    0m0.403s
user    0m0.000s
sys     0m0.061s

なぜ、2種類のテストを実施したかというと、libaioによる非同期I/OはO_DIRECTが付与
された場合のみ実行されます。なので、O_DIRECTオプションの有無でaiocpの実行速度
が異なっているわけです。

では、Oracleでは、このファイルのオープンモード(ファイルシステムに対して)とI/O
の制御はどこで行われているか?

これは、filesystemio_optionsで制御されています。(デフォルトはnoneとなっていま
す) filesystemio_optionsはnone|directio|asynch|setallから選択します。

none:     ファイルのオープンモードは変更しない(かつlibaio経由のシステムコール
          を発行しない)
directio: ファイルのオープンモードはO_DIRECTが付与される。libaio経由のシステム
          コールは発行しない
asynch:   ファイルのオープンモードはnoneと同一。libaio経由のシステムコールが
          発行される
setall:   ファイルのオープンモードはO_DIRECTが付与される。かつlibaio経由のシス
          テムコールが発行される

* 各オプションによるファイルのオープンモードやシステムコールの差異はstrace
  コマンドをdbwrプロセス等にかけてみることで確認できます。

以下のブログに詳細を記載しています。
http://kojishinkubo.blogspot.com/2010/09/unbreakable-enterprise-kernelio.html

ここで、最初にテストしたaiocpコマンドの結果を思い出してみましょう。

非同期I/Oが実行されるのはlibaio経由のシステムコール(io_submit(2)とio_getevents(2))
を使用する。かつファイルのオープンモードがO_DIRECTとなっていること。でした。

ということで、ファイルシステムを利用中で、dbwr/lgwrの書き込みスループットを上げ
たい場合には、filesystemio_optionsをsetallにしないと効果なしと言えそうです。

昨年からのもやもやが解消! 恵比寿より