io_uringのサンプルを試してみた

はじめに

io_uring について以下の素晴らしい入門記事を知ったので試してみたメモです。

サンプルソースコード shuveb/io_uring-by-example: A companion repository for the io_uring by Example article series README に書いてありますが Linux カーネル 5.5 以上が必要となります。

Hacker News のスレッド Io_uring By Example: cat, cp and a web server with io_uring | Hacker News

環境構築

自宅サーバーの Ubuntu 18.04 LTS に linux-generic-hwe-18.04 を入れていますが、これの Linux カーネルは 5.3.x です。この環境に mainline のカーネルは入れたくなかったので別に環境を作ることにしました。

Ubuntu 19.10 を Ubuntu 20.04 LTS beta にアップグレード

別の自宅サーバーで Ubuntu 19.10 があったのでこれをアップグレードしました。

How To Upgrade Ubuntu To 20.04 LTS Focal Fossa - LinuxConfig.org の手順を参考にしました。

まず元のバージョンで最新にします。

$ sudo apt update 
$ sudo apt upgrade
$ sudo apt dist-upgrade
$ sudo apt autoremove
$ sudo apt install update-manager-core

の後

$ sudo do-release-upgrade

No new release found となりました。

$ sudo do-release-upgrade -d

を試すと先に再起動をするようメッセージが出たので、再起動後再度実行したら Ubuntu 20.04 LTS Focal Fossa beta のダウンロードとインストールが始まりました。

TUI のインストーラーで途中何回か設定ファイルをパッケージので上書きするか聞かれたので、差分を確認しつつ選択しました。

Ubuntu 20.04 LTS のインストールが終わったら再起動して、 Linux カーネルのバージョンを確認すると 5.4.x でした。 apt show linux-generic-hwe-20.04 も同じバージョンでした。まだリリース前だからですかね。

mainline のカーネルをインストール

How to Install Kernel 5.6 in Ubuntu / Linux Mint | UbuntuHandbook を参考にインストールしました。

上の記事に赤背景で警告が書かれていますが、 mainline カーネルは Ubuntu 提供のドライバーやパッチが含まれておらず、サポート対象外で、本番利用には不適切とのことですのでご注意ください。

今回のマシンは検証用環境なので気兼ねなく mainline カーネルを入れてみました。

Index of /~kernel-ppa/mainline/v5.6 から amd64 の -all-generic の deb をダウンロードしました。

$ curl -LO https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.6/linux-headers-5.6.0-050600_5.6.0-050600.202003292333_all.deb
$ curl -LO https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.6/linux-headers-5.6.0-050600-generic_5.6.0-050600.202003292333_amd64.deb
$ curl -LO https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.6/linux-headers-5.6.0-050600-generic_5.6.0-050600.202003292333_amd64.deb
$ curl -LO https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.6/linux-modules-5.6.0-050600-generic_5.6.0-050600.202003292333_amd64.deb

その後以下のコマンドでインストールしました。

sudo dpkg -i *.deb

liburing の deb のビルドとインストール

axboe/liburing を見ると debian というディレクトリがあったので` ローカルで deb パッケージをビルドしてインストールしました。

$ git clone https://github.com/axboe/liburing
$ cd liburing

build-essentialmk-build-deps を使うために必要なパッケージをインストールします。

$ sudo apt install build-essential devscripts equivs

liburing のビルドに必要なパッケージをインストールするためのパッケージをビルド、インストールします。

$ sudo mk-build-deps -i

dpkg -l liburing-build-deps でインストールされたことを確認します。

作成された liburing-build-deps_0.4-2_all.deb を親ディレクトリに移動します。

$ mv liburing-build-deps_0.4-2_all.deb ..

liburing の deb パッケージをビルドします。

$ dpkg-buildpackage -b --no-sign

完了したら ls ../*.deb で作成されたパッケージを確認し、インストールします。

$ sudo dpkg -i ../liburing1_0.4-2_amd64.deb ../liburing-dev_0.4-2_amd64.deb

また liburing-build-deps パッケージはアンインストールしておきます。

$ sudo dpkg -e ../liburing-build-deps_0.4-2_all.deb

サンプルのビルドと実行

shuveb/io_uring-by-example: A companion repository for the io_uring by Example article series01_regular_cat02_cat_uring はディレクトリに cd して以下のようにビルドしました。

$ cc main.c

実行は ./a.out 対象ファイル名 です。

03_cat_liburing, 04_cp_liburing, 05_webserver_liburing は liburing が必要なので以下のようにビルドします。

$ cc main.c -luring

実行は以下のようにします。

05_webserver_liburing のサンプル内には Linux kernel 5.5 has support for readv, but not for recv() or read() というコメントがありますが 5.6 ではサポートされているので、書き換えて試してみたいところです。

io_uring に期待しているわけ

私見ですが今考えていることをメモ。

nginx には大変お世話になっていますが、複数のワーカープロセスの構成はちょっと面倒だと思っています。これのせいでワーカープロセスをまたいで状態を保持するには共有メモリを使う必要があるからです。 すると RocksDB のようなプロセス内にエンベッドするようなキーバリューストアは使いにくいです。

nginx は結局一部ではマルチスレッドが導入されているので、単一プロセスでマルチスレッドだったら良かったのにと思いますが、おそらく歴史的経緯だろうから仕方ないかと思っています。

で、 io_uring が無かったときはファイル操作はスレッドプールで同期I/Oを実行してepollなどでさばくしかなかったわけですが、 io_uring でファイル操作もネットワーク通信も出来るようになると、スレッドプール無しの単一プロセス構成でもスケールするのではないかと予想しています。

CPU メインの処理がある場合は別として、 I/O がほとんどというアプリケーションであれば io_uring のサブミッションポートに投げて、コンプリーションポートから受け取ってまたサブミッションポートに投げての繰り返しぐらいしかしないからです。

そしてアプリケーションは単一プロセスでもカーネル側で複数CPUコアを活用して処理してくれるのではないかと期待しています。

で、スレッドが不要になると C 言語でも十分書きやすいのではないかと目論んでいます。 仕様がしっかり固まった部分は C 言語で書いて、いろいろ変えたいところは LuaJIT FFI で書くという併用が良さそうかと思っています。

というわけで io_uring の今後が楽しみです。