非同期I/Oのコンテキスト数は/proc/sys/fs/aio-nr
で確認でき/proc/sys/fs/aio-max-nr
に達すると、io_setup システムコールの戻り値に EAGAIN が返される。
$ cat /proc/sys/fs/aio-nr 0 $ cat /proc/sys/fs/aio-max-nr 65536
MySQLで遊んでいたら以下のようなエラーに遭遇してプロセスが停止しまいました。ググるとわかるのですが上記で挙げたmaxの数値になってしまっための模様です。
EAGAIN: The specified maxevents exceeds the user's limit of available events.
InnoDBにおける非同期I/O
パラメータの値をあげれば良いって話ですがせっかくなのでInnoDBがどこで非同期I/Oを使ってるの?って思ったので調べてみました。MySQL 5.5のInnoDBからLinuxにおいてOSネイティブの非同期I/Oが利用されるようになったらしいです。それまではsimulated AIOという擬似的なAIOを使って非同期IOを行なっていてようです。
(ここからはちょっと怪しいので間違いあればコメントいただけると🙏)
MySQLのコネクションハンドラスレッド(クエリースレッド)はIOリクエストをキューイングするのではなくスレッド自身が非同期IOを発行するようになります(io_submit(2)を実行する)。この要求を処理するのは非同期IOなのでカーネルスレッドが処理を行います。そしてイベントのハンドラが必要になるのでバックグラウンドスレッドのInnoDB バックグラウンドスレッド(IOスレッド)がio_getevents(2)を発行してイベントをハンドリングします。メリットとしてはIOスレッドがハンドリングのみが責務になるのでアプリケーションとしてスレッドを多数生やさずに性能を出すことができる点でしょうか。
ノンブロッキングでも良くない?
select(2)とかepoll(2)でも良くないって一瞬思ったのですがIO完了通知の時点でデータのカーネルスペース->ユーザスペース転送が終わってるので余計なスレッドを別に生やさなくて良かったり速度面とかで有利だから採用されてるのかな?って思いました。がどうなんでしょう。(writeは即戻るだろうしユーザスレッドが増えるだけでメリットはないのかな?)
Poxis AIOの実装あたりは以下の記事がとても詳しくて良かったです。
(追記)
非同期IOの対象になってるのは*.ibdのファイルでselect/epollでの監視は全く意味のないことに書いた後に気づきました。ファイルは常に読み取り可能/書き込み可能なのでなにも効率化されないですね...(この辺もう少し理解進めたい...)
読み込みが可能かどうかを 監視する (より正確にいうと、停止 (block) なしで読むことができるかを 調べる。ファイルの終端 (end-of-file) の場合も、 ファイルディスクリプターは読み込み可能として扱われる)。 writefds に入れられたディスクリプターについては、書き込み用に利用可能な領域があるかを監視する (ただし、大きな書き込みの場合には停止する可能性はある)。
io_uringは採用されるのか?
io_uringはカーネル5.1から登場した機能。buffered IO(open(2)にO_DIRECTフラグを指定していない場合)でも使用可能だったりとLinux AIOの欠点を改善しているio_uringとMySQLの動向が気になったのでみてみました。8.0のベンチマーク結果とかはちょくちょく見つかったのですが採用はまだされてないって認識で合ってるのか不明でしたが開発は進んでいるように見えました。
AIO非対応なファイルシステムの場合
世の中にはあります。(過去に一度だけみたことあるだけだけど...)そういう場合はinnodb_use_native_aio = 0
にすれば良いです。ENOSYS
はこれ以外で見たことないかもです。