Linuxメモリ管理の最先端を探る
小崎 資広
2008/5/22
VM(仮想メモリ)の改善
昔からのLinuxユーザーの方は、カーネル2.4の時代に、一時期VM(仮想メモリ)が不安定で悩まされていたことを覚えている方もいるかもしれません。
現在のVMは、Andrea Arcangeliの作成した割とシンプルな設計なVMに、Rik van Rielの作成したページフレームからページテーブルエントリを逆引きするためのreverse mappingという機能を追加したものが基本となっています。
これは、コードの複雑さと性能の間でバランスの取れた、なかなか評判のいいものだったのですが、カーネル2.6の登場から約5年がたち、だんだんアラが目立つようになってきました。
というのも、当時は一般的なパソコンのメモリ量は256M〜512Mbytes程度で、サーバでも4Gbytesの壁を超えるようなマシンはまれでした。しかし、DRAMの急激な低価格化に加え、Linuxが急速にハイエンド市場に受け入れられていったことにより、いまや1Tbyte(テラバイト)のメモリを搭載したサーバも登場しています。これだけスケールアップしてしまうと、設計当時とはボトルネックの見積もりがずれてしまっているわけです。
Rik van Rielは、搭載メモリ量が100Gbytesを超えたあたりから、現在のVMではスケーラビリティの問題が発生すると主張しています。
現在のアルゴリズムでは、ページフレーム回収が動作するとページフレームのLRUリスト(注2)を走査し、最近アクセスされていない(Access bitが立っていない)ページを探します。ところが、メモリ量が増えるとその分メモリ不足が発生しにくくなり、ページフレーム回収がまれにしか動きません。すると、いざページフレーム回収論理が動作したときには、非常に多くのページにAccess bitが立っていることになります。
注2:LRUとはLeast Recently Usedの略であり、ざっくりいうと、最後にアクセスされた時刻を基にソートされているようなデータ構造のことを示します。キャッシュについては、使っていないデータから破棄することが望ましいので、多くのOSがLRUの派生アルゴリズムをメモリ管理に採用しています |
さて、ここで簡単な計算をしてみましょう。x86_64 Linuxでは、ページの大きさは4kbytes、ページディスクリプタの大きさは64byteです。すると、メモリを100Gbytes搭載したシステムでは2621万4400ページ(=100Gbytes/4kbytes)がシステムに存在し、ページディスクリプタが1600Mbytes(=100Gbytes/4kbytes×64bytes)のメモリを使用することになります。
つまり、すべてのページにAccess bitが立っている状態でページフレーム回収処理が呼ばれると、2500万回以上のロックの取得解放処理を伴う、1600Mbytesのランダムメモリアクセスが発生するわけです。何となく重そうな処理であることは容易に想像いただけるでしょう(もちろんこの計算は非常に大ざっぱなものです。実際にはもっと複雑なことをしているので、さらに遅くなります)。
また、さらに悪いことに、近年CPUのマルチコア化が進み、CPU数が多いサーバが増えてきました。これは通常のケースでは性能を向上させますが、上記のようなワーストケースでは非常に多くのロック競合が発生し、パフォーマンスが劇的に劣化してしまいます。
この問題に対する解答として、Rik van RielとLee SchermerhornがVM pageout scalability improvementsパッチセットを提案しています(実は筆者も開発に参加していて、筆者のパッチもたくさんマージされているので思い入れがあります)。
このパッチセットは、主に以下の2つの改善をしています。
1点目は、mlockされたメモリの管理方法の改善です。いままではmlockされたページも通常のページと同じように、LRUにつながっていました。しかしmlockされているページがスワップアウトされることは決してありません。これをチェックするのは、純粋にCPUサイクルの無駄です。
そのため、回収不可能なページを管理する新しいLRUリストを新設し、mlockされたページをそちらに移せば、ページフレーム回収を高速化できます。これはほかのOSで当たり前のように行われている最適化ですが、Linuxでは行われていなかったのです。
2点目は無名ページ管理の改善です。これだけメモリが増えるとスワップはまず発生しないので、無名ページのチェックの負荷が相対的に大きくなってしまいました。そのためファイルキャッシュと無名ページの管理LRUを分離し、普段はファイルキャッシュを管理するLRUだけをチェックするようにしました。
また無名ページ管理LRUの無名ページの特性に合わせて、deactivateの論理を修正しています。無名ページは常にプロセスにマップされているので、ファイルキャッシュと同じように「マップされているページのページテーブルエントリのAccess bitが立っていたらactive listに移動」というルールを用いると、ほぼすべてのページがactive listに移動してしまい、回収が非効率になってしまうためです。
VMの改善 |
Linuxを使っていてスワップ発生とともに急激に応答性が悪化した経験のある人は、このパッチによって幸せになれるかもしれませんね。
このパッチはまだ-mmにもマージされていませんが、将来が楽しみですね。
仮想化関連の改善
近年、仮想化技術が急速に普及してきており、LKMLにも仮想化関連のパッチがしばしば投稿されるようになりました。
■MMU notifier
これはKVMコミュニティから出てきた提案で、2008年早々にAndrea Arcangeliがスタートさせました。
KVMでは、shadow pteという仕組みを使ってゲストOSのメモリを管理するのですが、ホストOSでは、このshadow pteが参照しているメモリをスワップアウトすることはできませんでした。もしそれをしてしまうと、ゲストOSから見るとカーネルすら知らない間にメモリがスワップアウトされてしまうことになり、正常に動作できないからです。
しかし、ゲストOSの中にはあまり参照されていないページも大量にあります。これらをスワップアウトしたいという要求がありました。
この問題を解決するために出てきたのがこのMMU notifierです。動作原理は簡単で、Linuxはページをスワップアウトさせるときにまずページをアンマップし、pteを無効化します。ここにフックを仕込んでおいて、ゲストOSに通知を上げることができれば、ゲストOSのメモリ管理が破たんすることなくスワップが実現できます。
これに反応したのがChristoph Lameterで、「SGIはそれを実現できるXPMEMというパッチを持っているので、KVMもそれを使うのがよい」と提案しました。
XPMEMというのはSGIのスパコンで使われているカーネル拡張です。特殊なハードウェアと組み合わせることにより、クラスタの別マシンのメモリをネットワーク越しにmmapして、アプリケーションが搭載メモリをはるかに超えるメモリにアクセスできるという発想の、その強引さに感動が止まらないすてきな機能です。
その後、議論は一進一退を繰り返しています。両機能が統合されたパッチができかけると別の誰かがパッチが複雑過ぎると苦情をいうので、なかなか話がまとまりません。個人的には、SGIのRequirementが特殊過ぎて余人には理解し難いのが一番の原因だと思っていますが……。
現在までに、Andrea Arcangeli、Christoph Lameter、Nick Piggin、Rusty Russellの4人がそれぞれ別のMMU notifierパッチを提案しており、オープンソース特有のガチンコ・パッチバトルが繰り広げられています。早く議論がまとまって-mmにマージされるといいですね。
期待の新機能、memcgroup
■memcgroup
これは、2007年で一番盛り上がった機能かもしれません。memcgroupは、SolarisのZone/Containerに相当する機能であり、システム内に仮想的なパーティションを作り、特定のプロセスの集合が使用できるメモリ量を制限できる機能です。大きなくくりでは「Yet Another Virtualization」といえるかもしれません。
主にBalbir Singh、Pavel Emelyanov、KAMEZAWA Hiroyukiの3人によって開発・メンテナンスされています。余談ですが、Pavel EmelyanovはOpenVZの開発者で、今後OpenVZはmemcgroup上のミドルウェアに移行するのではないかといわれています。
使い方は簡単で、cgroupファイルシステムをマウントしたうえで、
# mkdir /cgroups/gruop0 |
のように実行すると「group0」という名前のグループに自プロセスを登録し、そのグループのメモリ使用量の上限を4Mbytesに制限することができます。
Xenなどの仮想化機能に比べた利点はいくつかありますが、
- OSを2段重ねにするよりも軽い、速い
- システムディスクを別に用意する必要がないのでお手軽
- 使い方が簡単なのでミスが起きにくい
- 制限値の動的な変更が簡単
といったところでしょうか。別のいい方をすると、「ホストOSもゲストOSもLinuxなら、わざわざ仮想マシンを用意するメリットは少ない」という哲学に基づくアプローチなのだと思われます。
いわゆる仮想マシンの仕組み |
memcgroupはもっとシンプルになる |
この方式ですと、DVDを焼くのが失敗しないようにメモリをパーティショニングしたい、といったカジュアルな用途にも使えるわけで、デスクトップユーザーも取り込める可能性がありそうです。
この機能は2.6.25でマージされました。もっとも、マージされたのは基本機能のみであり、さまざまな拡張および性能改善が活発に議論されています。たぶんあと何カ月かすると拡張も一段落つくと予想されます。その時期になれば、もう少し詳しくcgroupの詳細や勘所を書くことができるかもしれません。期待していてください。
2/2 |
|
|
||||
|
連載 Linux Kernel Watch |
Linux Squareフォーラム Linuxカーネル関連記事 |
連載:Linux Kernel Watch(連載中) Linuxカーネル開発の現場ではさまざまな提案や議論が交わされています。その中からいくつかのトピックをピックアップしてお伝えします |
|
連載:Linuxファイルシステム技術解説 ファイルシステムにはそれぞれ特性がある。本連載では、基礎技術から各ファイルシステムの特徴、パフォーマンスを検証する |
|
特集:全貌を現したLinuxカーネル2.6[第1章] エンタープライズ向けに刷新されたカーネル・コア ついに全貌が明らかになったカーネル2.6。6月に正式リリースされる予定の次期安定版カーネルの改良点や新機能を詳しく解説する |
|
特集:/procによるLinuxチューニング[前編] /procで理解するOSの状態 Linuxの状態確認や挙動の変更で重要なのが/procファイルシステムである。/procの概念や/procを利用したOSの状態確認方法を解説する |
|
特集:仮想OS「User
Mode Linux」活用法 Linux上で仮想的なLinuxを動かすUMLの仕組みからインストール/管理方法やIPv6などに対応させるカーネル構築までを徹底解説 |
|
Linuxのカーネルメンテナは柔軟なシステム カーネルメンテナが語るコミュニティとIA-64 Linux IA-64 LinuxのカーネルメンテナであるBjorn Helgaas氏。同氏にLinuxカーネルの開発体制などについて伺った |
|
|
- 【 pidof 】コマンド――コマンド名からプロセスIDを探す (2017/7/27)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、コマンド名からプロセスIDを探す「pidof」コマンドです。 - Linuxの「ジョブコントロール」をマスターしよう (2017/7/21)
今回は、コマンドライン環境でのジョブコントロールを試してみましょう。X環境を持たないサーバ管理やリモート接続時に役立つ操作です - 【 pidstat 】コマンド――プロセスのリソース使用量を表示する (2017/7/21)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、プロセスごとのCPUの使用率やI/Oデバイスの使用状況を表示する「pidstat」コマンドです。 - 【 iostat 】コマンド――I/Oデバイスの使用状況を表示する (2017/7/20)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、I/Oデバイスの使用状況を表示する「iostat」コマンドです。
|
|