vSphere のメモリー活用の仕組みについて

別の所で使おうと思っていたネタですが、そちらではどうなるかわからないのでとりあえずこっちで書いてみます。

# vSphere を含めた仮想化環境のメモリーの話
仮想化環境のメモリー管理はいろいろな種類があるのですが、SE でもそれを理解していないでインフラの設計・運用管理をしている人を多く見かけるので、vSphere ネタとしてちょっと書いてみました。ご興味あればお読みください。

# 仮想化環境でメモリーを活用する技術は
物理サーバーでは、サーバー1台1台個々にメモリーを持って専有して使っていました。そして、物理サーバー全盛の時代ではハードウエアの開発速度も速く、ちょっと間を置くと性能や容量が倍とか一桁違っていたりとかが良くありました。そのような時代の中、物理ハードウエアの上でそれらの余裕あるリソースを使って仮想的にコンピューターをエミュレーションして使うという考え方が出てきて、今は仮想化の世界では主流になっている VMware 製品もこの時期に登場しています。
最初のころはメモリー空間をそのままアサインして使ったり、空いているブロックをやり取りしながら使ったりしていたので、やはりメモリー容量はそれなりに必要でしたが、ハードウエアのアシストもあって今はメモリーも効率的に使われるようになりました。私も最初に使い始めた VMware Workstation 1.0 登場が 1999年で、それから20年でここまで技術が進みつは思っていなかったのですが、こういうところが「技術」は楽しい部分です。
では、まず仮想メモリーの前に一般的なメモリー管理について簡単に説明します。メモリー管理方式にはページングとセグメントの2つの方式があって、それぞれ動きが異なります。

## ページング方式
ページングは連続したメモリー空間を「ページ」という固定長の単位で扱い、そのページをOSがアプリケーションに割り当てていくという形をとっていて、OSはページテーブルを使って割り当てのマッピングを管理します。アプリがいっぱい動いてメモリーが足りなくなるとOSはメモリーページの中から最近アクセスが無くて内容の変更も行われていないページを見つけ、そのページをディスクに書き出して（ページスワップ）ページを解放します。これは Windowsで言えば「仮想メモリ」が該当します。オペレーティングシステムの基本の仕組みであってもちろん Linux でも実装されているので目にする方は多いと思います。（そして、Linux で OOM Killer で泣いた人も・・・）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/12fda5dd-141e-cab2-4d68-8a407b6d4b70.png)
ページングの発動時は実際にはアプリの処理は停止されています。要するに簡単に書くと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/ee51d3cf-9901-c37e-bcf6-02a654121142.png)
のような動作をします。

##セグメント方式
セグメント方式は、メモリー空間の管理が可変長というところがページング方式と異なります。メモリー空間自体は全体が可変長セグメントで管理されて、そのセグメントの最初からのオフセットでメモリーを利用する形をとり、個々のセグメント同士を別々に管理ができるので相互のメモリー領域の保護という用途で使われたりしていました。（昔私も使っていた IBM System/38 ～ AS/400 の流れがそのようなメモリー管理だったと思います。）
セグメント方式は単体で使われるということより、ページング方式と組み合わされて使われるのがほとんどで、今の仮想化ではまさにセグメント方式とページング方式のハイブリッドで使われています。ざっくりと書いてみるとこんなイメージです。（実際にはもっと複雑です。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/b7412116-9a80-e76c-5b68-b2e549f8ae1d.png)
インテルの x86 CPU はセグメントとオフセットというリニアなアドレス空間を持たない CPU のため、大規模なメモリー空間を扱うような環境には不向きな構造を持っていたため、メモリーをアクセスできる空間を仮想的なセグメント単位で扱うようにして大きなメモリー空間を扱えるようにしています。この大きなメモリー空間が 4GB として設定されたため、32bit x86 CPUは最大メモリーが 4GB しか扱えず、32bit OS はシステムが使う領域以外のアドレス空間しか使えなくなっているので、どんなにメモリーを搭載しても 3GBちょっとしか使えなかったわけです。

# vSphere 仮想化環境のメモリー管理は
vSphere といえども x86（今は x86_64）の上で動く限りにはインテルのメモリー管理の制限に引っ掛かります。ただ他のOSとは異なり仮想マシンの下のHypervisor層として動くため、物理ハードウエアを効率よく使う部分は vSPhere Hypervisor (ESXi) が行ってくれます。そのため、よほどではない限り物理ハードウエア側のメモリー管理の影響で、仮想マシン側にトラブルを引き起こすということがありません。物理の時代はメモリーが足りなかったりするとすぐに業務システムに影響が出てしまうのが当たり前でしたが、vSphere などを仮想化環境を使っている場合は複数の仮想マシンが動いていて相互にメモリーを融通しながら動作するので、すべての仮想マシンで必要なメモリー容量の合計より少ないメモリーしか搭載していないハードウエア上でも、業務システムのスローダウンを引き起こすことはほとんどなくなりました。
この vSPhere Hypervisor (ESXi) が行っているメモリーを効率的に扱う仕組みには、以下の４つのものがあります。

* 透過的ページシェアリング
* バルーニング
* メモリー圧縮
* VMkernelスワップ

それぞれのメモリー活用方法は以下のようになります。

## 透過的ページシェアリング
仮想化環境では一つの物理サーバーの上に全く同じOSの仮想マシンが動作することが多いはずです。例えばWindows Server 2019だらけとか、Red Hat Enterprise Linux 8 だらけとか、仮想デスクトップであれば Windows 10 Enterprise ばっかりとかです。この場合、それぞれのメモリーに対して使わない領域を他に融通するような使い方をしても、全体として必要なメモリー容量はそれぞれの仮想マシンの合計になります。でも、発想の転換！！同じメモリーパターンで変更されないページを共有してしまえば、必要となるメモリー容量を削減できます。これが透過的ページシェアリングです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/864f25ef-6587-8cfb-16f8-659063e7f2fc.png)
現在はセキュリティの理由でデフォルトは OFF になっていますが、自社専用の環境で使う場合は有効にすると効果が見られます。特にオンプレミスで Horizon 環境を使っている場合には効果的です。

## バルーニング
ページングの所ではコンピュータの上のアプリケーションはメモリーを割り当てられていてもすべてを使っているわけではなく、足りなくなったらその部分をページスワップして他に使わせるということをしていると説明しましたが、それを仮想マシンに対して行っているものがバルーニングです。
バルーニングの場合はvSphere Hypervisor（ESXi）で仮想マシンからの要求に対してメモリー割り当て不足が起きそうになった場合に、仮想マシンの中から割り当てられているメモリーで使われていないところ（inactive memory）を見つけ出し、その部分を他の仮想マシンに使わせてしまいます。そしてメモリーをはぎとられた仮想マシンはinactive memoryがページアウト（Windows ではページスワップと呼んでいたものと同じ動作です）しないようにinactive memoryメモリーの状態を固定します。これで仮想マシンの性能を落とさずに仮想マシン間でメモリーの貸し出しを実現しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/58b07292-e7b2-7b5c-1b2f-a304400d4598.png)

ただ、ここで重要なこととして、inactive memoryはページアウトしないように固定はするのですが、メモリーをはぎ取られた仮想マシンで急にメモリー需要が増大してinactive memoryのエリアまで使う必要が発生した場合は急に対応ができないため、場合によっては仮想マシン自体に影響が出てしまう場合があります。具体的には Linux などの場合はメモリーを使おうとしてもその領域をバルーニングドライバが「既に使っていますよ」と通知してしまうので、場合によっては Linux のOS保護の仕組みから、プロセスの中でメモリーを多く使用しているプロセスが OOM Killer で落とされてしまうことがあります。そのため、パフォーマンスが落ちないしメモリーを効率に使えるからバルーニングは許容しようとしてしまうと、意図しないメモリー利用の増大でどれかの仮想マシンのどれかのプロセスが突然落とされてトラブルになるということも考えられますので、バルーニングはあくまでも緊急避難的な仕組みであり、物理サーバーのメモリーは必要な容量実装を実装するというのを基本にするのが賢明です。


## メモリー圧縮
バルーニングでもメモリーが足りない場合は、メモリー圧縮を行います。メモリー圧縮は仮想マシンのメモリー空間が足りないためディスクにスワップさせる処理に入ることが確定的になった場合、そのメモリーページをディスクにスワップさせずに圧縮してメモリー上に置いておくという動作をします。ディスクに書き出すのではなくメモリー上に圧縮して置いてあるのでパフォーマンスに対するインパクトを最小限に抑えることができるのですが、メモリー圧縮の効果が見られない場合はメモリー圧縮を断念してディスクにスワップアウトをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/a2c9149f-a331-e84a-74b6-ca80f89084a4.png)
ディスクにスワップアウトすることも場合によっては発生するので、この状態にならないようにvSphere Hypervisor (esxI) のメモリー管理をすることが重要です。

## VMkernel スワップ
メモリー活用の最後の手段、VMkernel スワップは文字通り物理ディスクにメモリーページをスワップします。動作としては優先順位の低い仮想マシンのメモリーをVMkernelによりスワップアウトします。そして、仮想マシンのゲストOSはページアウトを認識しませんので（vSphere Hypervisor (ESXi) の機能でのスワップアウトなので）、ゲストOSがメモリーにアクセスするたびにディスクに書き出されたスワップファイルに対しスワップイン・アウトを繰り返すことになり、結果として物理ディスク I/O 負荷が増加してしまい、結果として仮想化環境全体の性能ダウンが発生します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/1f75f49b-f240-2636-f1d5-4a66b4a77f44.png)

# 仮想化環境のメモリー管理の要点（仮想マシン視点）
ここまでは vSphere 側の視点でメモリー管理を書きましたが、仮想マシン側の視点でも注意するべき点があります。これは最初で書いたゲストOSのメモリー管理での「ページスワップ」のことで、ここを物理マシンの時代と同じように許容したサイジングで仮想マシンにしてしまうと、仮想マシンの負荷が上がってメモリーが足りなくなってページスワップが発生したりすると、これは即仮想化環境全体のディスク I/O 増加につながってしまいます。そのため、仮想マシンではメモリーを多く設定するとともに、ページングファイル無しに設定するなど「ページスワップ」させないのを基本にしてメモリーのサイジングすることが重要です。特に仮想デスクトップ環境を展開する場合は、仮想デスクトップのメモリー割り当てを 2GB とかに設定してしまうこともありますが、最近の Microsoft Office ではそれではメモリーは足りないため、多くのアプリを動かすとすぐにページスワップ発生を招いてしまいます。この時、HDDストレージを使っている場合は性能劣化が顕著になるのですぐにわかるのですが、Flashストレージを使っていると意外と気づかずに、多くの仮想デスクトップを展開・運用し始めて初めて問題に直面する場合とかも出てくるようになります。このあたり、基本は
* 仮想マシンのゲストOSではページスワップしないように設計する
* vSphere 側ではバルーニングが発生しないように必要なメモリー容量を設計する
* メモリー不足＝ディスク I/O 増大につながるので、ストレージは可能な限り性能の良いものを選択し、ストレージへのパスも帯域をしっかり確保できるようにして、イレギュラー時にも耐えられるように設計する
* パフォーマンス劣化時にゲストOSでSCSIタイムアウトが発生していたら、それはディスク I/O 増大による仮想マシンのディスクアクセス遅延が発生していることで、その原因はアプリだけではなくゲストOSのメモリー不足によるページスワップの可能性もある
ということをしっかり理解していく必要があると思います。
メモリーについてはまだまだ奥深いのですが、今回はここまでにします。

# 参考情報
最新の vSphere 7 でも、大きくは変わらないと思います。

* VMware vSphere 5 のメモリ管理および監視の図 (2017642)
https://kb.vmware.com/s/article/2017642?lang=ja

* vSphere Monitoring and　 erformance
https://docs.vmware.com/en/VMware-vSphere/7.0/vsphere-esxi-vcenter-server-70-monitoring-performance-guide.pdf