- かつて高いオーバーヘッドのため実用性に乏しかったマイクロカーネルは、現在では普及した IOMMU と共有メモリのおかげで、再び現実的な選択肢になり得る
- ドライバーやサブシステムをユーザー空間に隔離すれば、障害や攻撃の影響範囲を限定し、セキュリティ・信頼性・モジュール性を高められる
- 1980〜90年代には、ユーザー空間プロセスがデバイスに直接アクセスできず、ディスク読み取りのような処理ごとにシステムコールとコンテキストスイッチ、ロック、メモリコピーが伴っていた
- IOMMU と共有コマンドキューを活用すれば、通常パスでコンテキストスイッチ、アドレス空間間コピー、ロックなしに、非同期 IPC とデバイスアクセスを処理できる
- Xen、FreeBSD、Linux DRM のような既存コンポーネントを活用できるため、ハイパーバイザーとシステムサーバーをゼロから作り直す負担も大きくない
マイクロカーネルの構造と隔離効果
- マイクロカーネルは、スケジューリング、I/O デバイスアクセス管理、プロセス間通信(IPC)を除く機能をユーザー空間で実行するカーネル構造である
- サブシステムの隔離は3つの利点をもたらす
- セキュリティ: あるドライバーの脆弱性が、攻撃者にシステム全体ではなく、そのサブシステムやドライバーのアクセス権だけを与える可能性にとどまる
- 信頼性: あるサブシステムのクラッシュが、システム全体ではなく当該部分にだけ影響する
- モジュール性: Linux カーネルチームがすべてのハードウェアドライバーをマージし、各チップの内部動作まで検討しなければならない負担を軽減できる
- Windows がマイクロカーネルシステムだったなら、CrowdStrike のバグは一部の IT セキュリティ担当者によるテレメトリーデータ収集を停止させるだけで済んだかもしれない
過去の性能限界と IOMMU による解決策
- かつてのマイクロカーネルでは、ユーザー空間プロセスが特定のデバイスに直接アクセスできず、処理ごとにシステムコールとコンテキストスイッチが必要で、高コストなロックやメモリコピーも伴っていた
- Machは性能問題のためユーザー空間プロセスを徐々にカーネル内へ移し、最終的には一般的なモノリシックカーネルに近づいた
- 今日の PC には約10年にわたり IOMMU が標準的に搭載されており、共有メモリと組み合わせれば、コア数が十分な通常パスでコンテキストスイッチを完全に排除できる
- わずかなレイテンシを受け入れれば、全体としてもコンテキストスイッチをほぼなくせる
- 仮想化技術ベースのスケジューラーは、Xen ハイパーバイザーに似た形で構成できる
- I/O デバイスアクセスは IOMMU ハードウェアが管理する
- IPC は、プロセス間に共有バッファを割り当て、整数のアトミックな compare-and-swap を提供する方式で実装できる
- 共有バッファをリングバッファ形式のコマンドキューとして使い、開始・終了ポインターをアトミックに更新する
- 通常パスではコンテキストスイッチ、アドレス空間間コピー、ロックなしに非同期メッセージを渡せる。この方式は GPU ドライバーでも広く使われている
ライブラリ構成と既存コードの活用
- プロセスが VM ゲストである環境では、共有ライブラリをプログラム起動時にリンクし、他プロセスで実行する必要がない機能は exokernel 方式でローカルに処理できる
- Electron のように、アプリケーションごとに独自のオペレーティングシステム構成要素を同梱して配布する現在では、メモリ上の重複ライブラリは30年前ほど大きな問題ではない
- 実装に必要な主要な基盤もすでに存在する
- Xen はハイパーバイザー層に必要な機能の大半を備えている
- Mach のようにネットワークとファイルシステムのサーバーを構成しつつ、FreeBSD のコードを取り込んで利用できる
- DRM はすでに非同期コマンドバッファを基盤としているため、Linux のグラフィックスサブシステムをユーザー空間で実行できる
- 便宜上、ディスプレイサーバーとグラフィックスサブシステムを同じプロセスで実行する構成も可能である
1件のコメント
Lobste.rs のコメント
Linux がすべてのドライバを含んでいる理由は、ツリー外カーネルモジュール向けの安定した API がないためであり、そのような API を提供するのにマイクロカーネルが必須というわけではない
すべての Linux ドライバをユーザー空間へ移すという前提でも、内部 API の変更が難しくなるという LKML の不満を見た記憶がある
L4 系カーネルは高速だと知られているのではないかと思う。Redox OS や Fuchsia はどうなのかも気になる
Genode は複数のカーネルをサポートしているが、seL4 などでは笑ってしまうほど性能が悪い。同僚たちが Linux VM を起動してみたところ 32 ビットのみ対応で、半分ほど起動するだけでも数分かかった
NOVA microhypervisor の Genode フォーク が基本プラットフォームになっているのは、実際に動作し、性能も十分だからだ
リングバッファを使っているため、受信側が別のコアですでに実行中なら、2 回目のコンテキストスイッチは不要かもしれない。コンテキストスイッチなしでメッセージを解釈すると受信側がメッセージを検証する必要があり、攻撃面が過度に広がる可能性があるが、カーネル提供の動的ライブラリで緩和できる余地はありそうだ
専門家ではないが、元記事はいくつか重要な考慮点を見落としているように感じる
QNX は高速なマイクロカーネルとして知られているが、何を正しくやったのか気になる
以前、友人とマイクロカーネル、特に QNX の優雅さに魅了され、FireWire ベースの映像処理問題を実装した。コードは単純で見事だったが、壊滅的に遅かった。当時 Linux 用 1394 ドライバに DMA ベースの等時性転送サポートを約 12 時間で追加したところ、性能が大きく改善し、この出来事をきっかけに会社の光学選別装置で Linux を使うことへの懐疑論も消えた
QNX とマイクロカーネル、メッセージパッシングの理想は今でも素晴らしいが、広く定着するには プロセス間データ転送コスト をはるかに下げる必要がある
今は Elixir で Web アプリケーションを作り、QNX が掲げたものと同じようなプロセス分離を享受している。光学処理のように性能が重要な作業ではないので問題ないが、Elixir/BEAM でもデータコピーの問題は同じだ
Mach が当初の構想ほどコンポーネントを完全には独立させられなかったとしても、平凡なモノリシックカーネル になったわけではなく、そのアーキテクチャには今なお利点があると聞いた
古典的な POSIX のファイル一覧ベンチマークのように、すべての項目に対して
readdir()とstat()を呼ぶなら、マイクロカーネルが不利になるのは避けられない。だがio_uringのような バッチ処理 API を使ってシステムコール頻度を下げれば、高レイテンシは大きな弱点ではないかもしれないLinux でもネットワークパケットごとにシステムコールを 1 回ずつ行えば、回線速度には追いつけない。バッチ処理は Linux とマイクロカーネルのどちらにおいても重要だ
この分野の興味深い最新の参入例として HongMeng があるが、残念ながら プロプライエタリソフトウェア だ
データ移動コスト が 1 桁以上大きく下がらない限り、マイクロカーネルが十分な競争力を持つのは難しそうだ
理論的には優雅で整理されているが、現実は複雑なので、その複雑さに対処するにはカーネルもある程度複雑である必要があるのかもしれない
正しいアーキテクチャは好きだが、Linux が支配的な地位に上り詰めたのには、純粋な技術以外の 副次的要因 も大きかったと思う。これを複数の観点から分析した記事を読んでみたい