Archive for the ‘Xen’ tag
Oracle VMをCisco UCS + Palo(M81KR)で検証しました
8/6のOracle VM Forumで発表させていただきましたが、Oracle VMとCisco UCSを組み合わせて検証しました。検証の焦点はCisco UCSに装着したCNA, 「Palo」ことM81KRを認識できるかということと、その性能です。
M81KRはmezzanine cardですが一枚のM81KRで最大128個の仮想NICを作成できるところがポイントです。さらにOS側には特段SR-IOV対応等は必要ありません。OSはM81KRで作成された仮想NICを普通のPCIデバイスとして認識します。
Cisco UCS M81KR 仮想インターフェイス カード
結論から言うとまず認識に関してはまったく問題ありませんでした。
Oracle VM Serverでlspciコマンドを実行し、認識しているPCIデバイスを確認するとM81KRで作成した仮想NICは下記のように表示されます。
[root@vmserver]# lspci 0c:00.0 Ethernet controller: Cisco Systems Inc 10G Ethernet NIC (rev a2) 0d:00.0 Ethernet controller: Cisco Systems Inc 10G Ethernet NIC (rev a2) 0e:00.0 Ethernet controller: Cisco Systems Inc 10G Ethernet NIC (rev a2) 0f:00.0 Ethernet controller: Cisco Systems Inc 10G Ethernet NIC (rev a2) 10:00.0 Ethernet controller: Cisco Systems Inc 10G Ethernet NIC (rev a2)
lspciの出力は、デバイスから得られるPCI IDと、/usr/share/hwdata/pci.idsに格納されているPCI IDを照合してデバイス名を表示しています。したがってlspciでデバイス名が得られたからといってドライバがこのデバイスを認識しているかどうか(つまりNICとして使用可能な状態かどうか)は別問題です。
M81KRが作成する仮想NICを利用するにはenicというドライバが必要になります。これはまだ多くのLinuxディストリビューションには含まれていないため、別途Ciscoさんのサイトからダウンロードしてインストールする必要があります。RHEL5.x, OEL5.xであればRPMが用意されています。しかし今回僕も初めて気がつきましたが、Oracle VM Server 2.2.1はこのenicドライバを標準でインストールしてあります。なのでM81KRで作成した仮想NICはOracle VM Serverからは別途ドライバをインストールせずともNICとして正しく認識され、ethX, xenbrXが自動的に作成されます。
一方、この仮想NICを有効活用するにはPCI Passthroughが効果的でしょう。その場合はこのデバイスに対するドライバが必要となるのはゲストOS(仮想マシン)の方です。Passthrough設定を行うとVM Server(つまりdom0)からはそのNICは見えなくなります(ただし依然としてlspciの出力には現れます)。したがってPassthroughした先のゲストOSでこのNICを利用するにはゲストOS側にenicドライバをインストールする必要があります。
RHEL5.x, OEL5.xではenicドライバはバンドルされていませんが、RHEL6.x, OEL6.xでは標準でバンドルされるようです。
2010年8月時点ではOracle VM ServerでのPCI Passthroughは公式サポートされていません。チャレンジャーな方は下記に手順を紹介しますのでトライしてみてください。
Oracle VM Serverで上記の仮想NICをPassthroughするにはまずUCSの該当ブレードでVT-d(I/O Virtualization)がEnabledとなっていることを確認します。
次にOracle VM Serverのgrub.confを編集してI/O Virtualizationを有効にしてOSを再起動します。
title Oracle VM Server-ovs (xen-64-3.4.0 2.6.18-128.2.1.4.25.el5ovs)
root (hd0,0)
kernel /xen-64bit.gz dom0_mem=547M iommu=pv
module /vmlinuz-2.6.18-128.2.1.4.25.el5xen ro root=UUID=f1b13de3-adb2-4b5a-a6e9-a8beda1b4f73
module /initrd-2.6.18-128.2.1.4.25.el5xen.img
OSが起動したら下記のコマンドでI/O Virtualizationが有効化されていることを確認します。
[root@vmserver]# xm dmesg | grep 'I/O virtualisation' (XEN) I/O virtualisation enabled (XEN) I/O virtualisation for PV guests enabled
次にmodprobe.confに下記の記述を追加し、再起動を行います。これはdom0からPCIデバイスを隠蔽するための設定です。(0000:0c:00.0はdom0用に残しておきます)
install enic /sbin/modprobe pciback ; /sbin/modprobe --first-time --ignore-install enic options pciback hide=(0000:0d:00.0)(0000:0e:00.0)(0000:0f:00.0)(0000:10:00.0)
ifconfig -a等でインターフェースを確認してみるとと、先ほどまでこれらの仮想NICにひもづいて作成されていたethXやxenbrXがなくなるはずです。
その代わりにPCIデバイスはPassthrough用にプールされています。xmコマンドで確認可能です。
[root@vmserver]# xm pci-list-assignable-device 0000:0d:00.0 0000:0e:00.0 0000:0f:00.0 0000:10:00.0
ここにリストされているPCIデバイスはゲストOSにPassthrough可能になっています。仮想マシンの設定ファイルを編集してPCIデバイスを割り当てます。ここではPVHVMを使用しています。
単なるHVMでももちろん可能ですが、PVMの場合はPVMのgrub.confにも少し設定が必要です。
ネットワークの内部構成は下図のようになります。
.png)
[root@vmserver]# vi /OVS/running_pool/oel55-phvm-01/vm.cfg
acpi = 1
apic = 1
builder = 'hvm'
device_model = '/usr/lib/xen/bin/qemu-dm'
disk = ['file:/OVS/running_pool/oel55-phvm-01/System.img,hda,w']
kernel = '/usr/lib/xen/boot/hvmloader'
keymap = 'en-us'
memory = 1000
name = 'oel55-phvm-01'
on_crash = 'restart'
on_reboot = 'restart'
pae = 1
serial = 'pty'
timer_mode = '2'
uuid = '313105b6-15ac-d7ea-de41-0ef0a90d302a'
vcpus = 4
vif = ['bridge=xenbr0,mac=00:16:3E:42:C7:A9,type=netfront'] #これはPVドライバを利用したインターフェース
vif_other_config = []
pci = ['0000:0d:00.0'] #PCI Passthroughの設定
vnc = 1
vncconsole = 1
vnclisten = '0.0.0.0'
vncpasswd = ''
vncunused = 1
これでゲストOSを起動します。まだゲストOSにenicドライバをインストールしていない場合はインストールします。
ドライバ:http://tools.cisco.com/support/downloads/go/ImageList.x?relVer=1.3%281e%29&mdfid=283004074&sftType=Unified+Computing+System+%28UCS%29+Tools+and+Drivers+Bundle&optPlat=Linux&nodecount=2&edesignator=null&modelName=Cisco+UCS+B200+M2+Blade+Server&treeMdfId=282558030&treeName=Unified+Computing&modifmdfid=&imname=&hybrid=Y&imst=N&lr=Y
*アカウントが必要です
[root@guest]# rpm -ivh kmod-enic-1.3.1c-rhel5u5.x86_64.rpm
そしてlspciコマンドで仮想NICをPCIデバイスとして認識できているか確認します。
[root@guest]# lspci | grep Cisco 00:03.0 Ethernet controller: Cisco Systems Inc VIC Ethernet NIC (rev a2)
ドライバをロードしてネットワークインターフェースが認識されることを確認します。
[root@guest]# ls /sys/class/net
eth0 lo sit0
[root@guest]# modprobe enic
[root@guest]# ls /sys/class/net
eth0 eth1 lo sit0
あとはいつも通りネットワークインターフェースを設定するだけです。
性能値についてはOracle社のポリシー上公開できないのですが、かなりの値が期待できると思っていただいて間違いないでしょう。また、スピードが速い、というだけでなくdom0へのCPUインパクトが激減(というかほぼゼロ)になるのが素晴らしいところです。
Xenでメモリをオーバーコミットする(Transcendent Memoryセットアップ編)
概要
- 管理者は多かれ少なかれメモリをある程度オーバープロビジョニングする
- 結果、性能は確保されるものの定常的に使われていないメモリが出てくる
- これを特にサーバ仮想化環境で見ると相当量のメモリが「未使用」となり、「もし、メモリ割り当てを最適化できればあと数VM収容できるのに」となる。実際、メモリは現在唯一VMの収容数を絶対的に制限するハードリミットとなっている
- この最適化を行うのがTranscendent Memory(以後tmem)。使われていないメモリをかき集めてtmem poolとして再配布可能とする
- ゲストOSはtmemを有効にしてビルドされたカーネルで起動することによって、従来のpage cacheに格納していたページをtmemを使って読み書きするようになる
環境
- Xen: 4.0.0
- ゲストOS: Oracle Enterprise Linux 5.4 x86_64
セットアップ手順
dom0にログインし、Xen(4.0.0)でtmemを有効にする。grub.confを編集してカーネル行に「tmem」を追加しdom0を再起動する
[root@vmserver]# vi /etc/grub.conf
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Xen 4.0.0 (2.6.32.11-1.2.97.xendom0.fc12.x86_64)
root (hd0,0)
kernel /xen-4.0.gz dom0_mem=1024M loglvl=all guest_loglvl=all tmem
module /vmlinuz-2.6.32.11-1.2.97.xendom0.fc12.x86_64 ro root=/dev/mapper/vg_x4-lv_root
module /initramfs-2.6.32.11-1.2.97.xendom0.fc12.x86_64.img
[root@vmserver]# init 6
次にゲストOSにログインしtmemを有効にする。tmemはまだカーネルのメインラインにはマージされていないのでディストリビューションが公開しているカーネルSRPMにtmemパッチ当て、カーネルを再構築する。
tmemパッチ入手先:http://oss.oracle.com/projects/tmem/files/
カーネルSRPM入手先:http://public-yum.oracle.com/repo/EnterpriseLinux/EL5/5/base/x86_64/
公開されているtmemパッチはvanillaカーネル用なのでディストリビューション付属のカーネルに当てるといくつかHunk, Failがでるが手作業で直せるレベルなので手で直す。
[root@guest]# rpm -ivh kernel-2.6.18-194.3.1.0.1.el5.src.rpm [root@guest]# cd /usr/src/redhat/SPECS [root@guest]# rpmbuild -bp kernel-2.6.spec [root@guest]# cd /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.x86_64 [root@guest]# patch -p1 < /var/opt/tmem-linux-2.6.18-xen-855-090408.patch
*4つ程Failするので手作業で直す
[root@guest]# cp configs/kernel-2.6.18-x86_64-xen.config .config
任意だが、わかり易いようにカーネル名を変更しておく
[root@guest]# vi .config CONFIG_LOCALVERSION="-tmem"
[root@guest]# vi Makefile EXTRAVERSION = -194.3.1.0.1.el5xen
ビルドする
[root@guest]# make -j8
*tmemについて有効化するか訊かれるので全て「Y」として有効化する
カーネルモジュールをインストールする
[root@guest]# make modules_install
カーネルをインストールする
[root@guest]# make install
initial ramdiskを作成する
[root@guest]# mkinitrd -v -f initrd-2.6.18-194.3.1.0.1.el5xen-tmem.img 2.6.18-194.3.1.0.1.el5xen-tmem
initial ramdiskをインストールする
[root@guest]# cp initrd-2.6.18-194.3.1.0.1.el5xen-tmem.img /boot/
新しいカーネルで起動するようにgrub.confを編集する
[root@guest]# vi /etc/grub.conf default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Enterprise Linux (2.6.18-194.3.1.0.1.el5xen-tmem) root (hd0,0) kernel /vmlinuz-2.6.18-194.3.1.0.1.el5xen-tmem ro root=/dev/VolGroup00/root rhgb quiet initrd /initrd-2.6.18-194.3.1.0.1.el5xen-tmem.img title Enterprise Linux (2.6.18-164.el5xen) root (hd0,0) kernel /vmlinuz-2.6.18-164.el5xen ro root=/dev/VolGroup00/root rhgb quiet initrd /initrd-2.6.18-164.el5xen.img
再起動し、新しいカーネルで起動する
[root@guest]# init 6
Demo
Reference
- http://lists.xensource.com/archives/html/xen-devel/2009-01/msg00253.html
- http://oss.oracle.com/projects/tmem/
- http://oss.oracle.com/projects/tmem/dist/files/linux-precache-preswap.README.html
- http://oss.oracle.com/projects/tmem/dist/documentation/api/tmemspec-v001.pdf
- http://oss.oracle.com/projects/tmem/dist/documentation/presentations/TranscendentMemoryXenSummit2010.pdf
Xenでメモリをオーバーコミットする(Self-Ballooningセットアップ編)
概要
- self-ballooningはゲストOS自らメモリをある条件に基づいて動的に返却する/獲得ことによって実質的にメモリをオーバーコミットするための仕組み
- xenballoondはゲストOSで動くbashベースのデーモン。これがself-ballooningを制御する
- xenballoondはdom0へのメモリ情報提供を担うことも計画されている
- xenballoondは/proc/meminfoのCommitted_ASの値をベースに最低限必要なメモリ容量を判別する
環境
- Xen: 3.4.0(Oracle VM Server 2.2.1)及び4.0.0(Fedora 12)で確認
- ゲストOS: Oracle Enterprise Linux 5.4 x86_64
セットアップ方法
Xen側には特殊な設定は必要ありません。すべてゲストOSでの作業です。
まず、ゲストOS上でxen-4.0.0.tar.gzをxen.orgからダウンロードし展開します。これはxenのtarボールの中に必要なスクリプトがあるからです。(恐らくXen 3.3以降であれば必要なツールが含まれているはず)
[root@guest]# tar xvfz xen-4.0.0.tar.gz
展開されたディレクトリ中から3つのファイルをそれぞれインストール(コピー)する
[root@guest]# cp xen-4.0.0/tools/xenballoon/xenballon.conf /etc/sysconfig/ [root@guest]# cp xen-4.0.0/tools/xenballoon/xenballond /usr/bin/ [root@guest]# cp xen-4.0.0/tools/xenballoon/xenballond.init /etc/init.d/xenballoond
bashファイルを実行可能なようにパーミッションを変更する
[root@guest]# chmod 755 /usr/sbin/xenballoond [root@guest]# chmod 755 /etc/init.d/xenballoond
必要に応じて設定ファイルを編集する
[root@guest]# vi /etc/sysconfig/xenballoon.conf
*特にXENBALLOON_SELF=falseはtrueに変更する必要がある
xenballoondデーモンを起動する
[root@guest]# service xenballoond start
検証結果
- self-ballooning有効化によって動的にメモリ容量が縮小されるか? => yes
- self-ballooning有効化によって動的にメモリ容量が拡張されるか? => yes(ただしユーザプロセスがメモリを予約した場合。page cacheでは拡張は発動しない)
使用したツール
mem_allocate.c(メモリを確保し、60秒後に解放するツール。適当に作った。)
#include
#include
#include
int main(int argc, char **argv) {
char *str;
int i;
if (argc == 2) {
sscanf(argv[1], "%d", &i);
printf("Allocating %d Bytes for 60 seconds...\n", i);
str = (char *)malloc(i);
memset(str, 1, i);
sleep(60);
free(str);
} else {
printf("This program needs exactly 1 argument.\nYou can set the bulk of RAM to allocate with integer.\n");
}
return 0;
}
Demo
Reference
- xen-4.0.0/tools/xenballoon/xenballoond.README
- http://blog.xen.org/index.php/2008/08/27/xen-33-feature-memory-overcommit/
- http://www.xen.org/files/xensummitboston08/MemoryOvercommit-XenSummit2008.pdf
Xenでメモリをオーバーコミットする(概要編)
サーバ仮想化環境ではいろいろなリソースをオーバーコミットしてリソース稼働率を高めることができます。「オーバーコミット」は、本来的には物理リソース以上のリソースをさもあるかのようにみせかけて擬似的に割り当てることですが、サーバ仮想化環境で言う場合のオーバーコミットとは実際的には「リソースを共有すること」と考える方が正しい解釈であり、意義のある活用方法だと思います。
.png)
XenはCPUに関しては上図のようなオーバーコミットを古くからサポートしています。なので物理的なCPU数が仮想マシン収容数についてハードリミットとなることはありません。同様にネットワーク帯域やディスク帯域は共有することが基本的な考え方なのでこれらについても仮想マシン収容数のハードリミットになることはありません。しかしXenはメモリのオーバーコミットはサポートしないとしていました。したがって物理メモリは唯一仮想マシン収容数を制限するハードリミットということになります。
現在I/Aサーバ用サーバ仮想化技術において、メモリのオーバーコミットには大別すると下記のような実装方法があります。
- SWAPディスク
- ディスクをメモリに模倣して仮想マシンに割り当てる
- しかし実際はディスクなので堪え難い性能劣化が発生する
- 重複排除
- 複数の仮想マシン間で重複するメモリを検出して一つにまとめる
- 同一メモリページが多いと想定される環境(同一構成の仮想マシンを多数起動するような環境)では効果を期待できる
- 重複判定処理にはオーバーヘッドが予想される。加えて、必ずしも重複排除できる可能性が高くない。
- メモリ動的増減(Self-Ballooning)
- 仮想マシンが必要に応じて能動的にメモリを獲得、解放する
- オーバーサイジングされている環境ではかなりの効果を期待できる
- しかし動的なメモリの獲得・解放は必ずしも十分高速でない
実はXenはバージョン3.3からSelf-Ballooningを用いたメモリの実質的なオーバーコミットが利用可能となっています。(ゲストOS側にSelf-Ballooning用ツールをインストールし、デーモンを起動する必要があります。)厳密にはこれはオーバーコミットというよりメモリを「増減」させる機構ですが、結果的には各仮想マシンのドメイン定義ファイルで設定されているメモリ量の総和が物理メモリを超えることができ、オーバーコミットと同様の効果をもたらします。
Self-Ballooningを有効にするとゲストOSは下記のようなことが可能になります。
- 不要なメモリ領域(完全な空き、またはpage cacheに費やされている領域)を識別して能動的にメモリをXenに返却する *厳密には/proc/meminfoのCommitted_ASをベースに解放範囲を特定します
- メモリ確保が必要になった場合、Xenにメモリ割り当て要求を発行して能動的にメモリ領域を獲得する
xm mem-setコマンド等でdom0側からゲストOSのメモリ容量を調整することはよく行われていると思いますが、Self-BallooningではゲストOSが能動的にメモリ増減を行うというところが特徴的です。
ちなみに少し話しはそれますが、Xen 4.0.0においてman xmdomain.cfgをみると下記のように「Xenではメモリオーバコミットはできない」と明記されています。
Xen does not support overcommit of memory, so the total memory of all guests (+ 64 MB needed for Xen) must be less than or equal to the
physical RAM in the machine.
しかし、実際にはSelf-Ballooningによるオーバーコミットは可能です。Xen 4.0.0のtarボールに含まれるxenballoonのREADMEは下記のようにメモリオーバーコミットが可能であると記載されています。
Xenballoond runs in guest domains and both implements selfballooning and provides metrics to dom0 for (future) directed ballooning. Both capabilities provide a foundation for basic “memory overcommit” functionality.
このあたりは個々の開発者でオーバーコミットに対する定義に違いがあることも一因かもしれませんが、どちらかというとXenのmanがあまりきちんとアップデートされていないことが問題な気がします。
さておき、つまるところXenではSelf-Ballooningを用いたメモリオーバーコミットが可能なわけですが、Self-Ballooningには前述の通り「メモリの獲得・解放が高速でない」という問題があります。そして、この問題を解決する手段としてPVM用に「Transcendent Memory」という新機能がXen 4.0.0から組み込まれています。Transcendent Memoryをごく簡単に言うと「物理メモリを複数の仮想マシン間で共有する仕組み」です。
.png)
その実装はXenが余っているメモリを「Transcendenet Memory Pool」というプールにまとめ、そのプールを複数の仮想マシンがクラスタファイルシステムのようなイメージで共有するという仕組みです。ファイルシステムと違うところは仮想マシンは別仮想マシンがTranscendent Memory Poolに保存したデータを閲覧することは当然できないということです。
*別途メモリのデータを共有できるタイプのPoolも実装が予定されています。
また、Transcendent Memoryにはいくつかの用途が考案されていますが現在実装されているのはpage cacheとして利用するという形です。Transcendent Memoryを有効にするには、Xen側で起動オプションを設定しておくことと、ゲストOS側のカーネルがTranscendent Memoryを有効にしてビルドされている必要があります。構築手順について詳しくは別のポストで解説しようと思います。
*ちなみにXen 4.0.0ではPage Sharingという重複排除タイプのオーバーコミット機能も組み込まれています。こちらはHVMのみの対応です。
そしてTranscendent MemoryはSelf-Ballooningと併用することで威力を発揮します。つまりこうなります。
- Self-Ballooningによって仮想マシンは不必要なメモリを能動的に解放する
- 元々空き領域であったメモリやSelf-Ballooningによって解放されたメモリをXenが掻き集めて「Transcendent Memory Pool」を構成する
- 各ゲストOSは自身に最低限必要なメモリ(カーネルやアプリケーションによって予約されている領域)だけを自身の専有メモリとして保持し、その他必要となるメモリ(page cache)についてはTranscendent Memory Poolを利用する
ゲストOSが全てのメモリを専有する従来の形と比べて下記のようなメリットがあります。
まず、Self-Ballooningを有効にすることで多くの仮想マシンはメモリを解放し始めます。これによってよりサーバとして空きメモリが拡大し、より多くの仮想マシンを起動できるようになります。しかしこれだけだと各仮想マシンはメモリ不足によって、あるいはメモリを動的に獲得する処理が遅延することによって性能が劣化する可能性があります。この問題を解決するためにサーバ全体としてある程度の空きメモリを用意しておき、それを遅延なく必要に応じて割り当ててあげる仕組みがTranscendent Memoryです。サーバ全体としてメモリプールを持つことでゲストOSが個別にすべてのメモリを保持する形態よりも少ないメモリで効率的なキャッシングが可能になります。
もちろん環境によって効果に差異はあると思いますが、特にpage cacheを活用するファイルサーバ、アプリケーションサーバではこの二つを組み合わせることによって集約密度を上げながら性能劣化を抑えられる可能性があります。逆にpage cacheを活用しない傾向が強いデータベースサーバではTranscendent Memoryはそれほど効果がないでしょう。ただしSelf-Ballooningで不要なメモリを綺麗に削ぎ落として他の仮想マシンやTranscendent Memory Poolで利用できるようにすることは意義があると思います。
このSelf-BallooningとTranscendent Memoryついて具体的な構築手順を別ポストにて解説しようと思います。
ubuntu-10.04をXenのPVMとして作成する方法
先日公開されたubuntu-10.04 LTSはkernel-2.6.32を採用しており、かつ、pvopsが有効となっています。pvopsが有効になっているLinuxカーネルは同一のカーネルでベアメタル上、HVMとして、またPVMとして稼動することができます。なので今回はまずHVMとしてubuntuを作成し、それをPVMとして起動し直すという手法で進めてみます。環境は下記の通り。
- Xen : Oracle VM Server 2.2.1 (Xen 3.4.0)
- domU : ubuntu-10.04 x86_64
最初にubuntuをHVMとして作成します。これはubuntuのインストレーションISOファイルを使ってOracle VM Managerから作成できます。下図のような感じ。新しい紫のテーマが美しい。
ここはごく一般的な手順なので割愛します。
インストールが終わって再起動が完了したらネットワークまわりをセットアップしてdom0と通信できるようにします。疎通できるようななったら、ubuntuのカーネルとramdiskをdom0に転送します。
[root@ubuntu1004]# scp /boot/vmlinuz-2.6.32-21-generic dom0:/OVS/running_pool/ubuntu1004/ [root@ubuntu1004]# scp /boot/initrd.img-2.6.32-21-generic dom0:/OVS/running_pool/ubuntu1004/
転送が完了したら一旦ubuntuをシャットダウンします。そしてdom0側で仮想マシン定義ファイルをいじります。
[root@vmservero]# vi /OVS/running_pool/ubuntu1004/vm.cfg
*修正後 kernel = 'vmlinuz-2.6.32-21-generic' ramdisk = 'initrd.img-2.6.32-21-generic' root = '/dev/xvda1 ro' disk = [ 'file:/var/ovs/mount/4ED5C364C05246FE8AEE8C0E26D79ACF/running_pool/ubuntu1004/System.img,xvda,w', ] keymap = 'en-us' memory = '1024' name = 'ubuntu1004' on_crash = 'restart' on_reboot = 'restart' uuid = '6fc94c0b-d902-476c-4c8b-0dfd3dadb315' vcpus = 4 vif = [ 'type=netfront, mac=00:16:3E:14:73:5A, bridge=xenbr0', 'type=netfront, mac=00:16:3E:16:E5:F2, bridge=xenbr1', ] vfb = [ 'type=vnc,vncunused=1,vnclisten=0.0.0.0,vncpasswd=' ]
*修正前 acpi = 1 apic = 1 builder = 'hvm' device_model = '/usr/lib/xen/bin/qemu-dm' disk = ['file:/var/ovs/mount/4ED5C364C05246FE8AEE8C0E26D79ACF/running_pool/ubuntu1004/System.img,hda,w', ] kernel = '/usr/lib/xen/boot/hvmloader' keymap = 'en-us' memory = '1024' name = 'ubuntu1004' on_crash = 'restart' on_reboot = 'restart' pae = 1 serial = 'pty' timer_mode = 0 uuid = '6fc94c0b-d902-476c-4c8b-0dfd3dadb315' vcpus = 4 vif = ['type=ioemu, mac=00:16:3E:14:73:5A, bridge=xenbr0', 'type=ioemu, mac=00:16:3E:16:E5:F2, bridge=xenbr1', ] vnc = 1 vncconsole = 1 vnclisten = '0.0.0.0' vncpasswd = '' vncunused = 1
そして仮想マシン(ubuntu)を起動します。起動後、lsmodコマンドでPVM特有のカーネルモジュールがロードされていることを確認します。
[root@ubuntu1004]# lsmod Module Size Used by binfmt_misc 7960 1 ppdev 6375 0 joydev 11072 0 fbcon 39270 71 tileblit 2487 1 fbcon font 8053 1 fbcon bitblit 5811 1 fbcon xen_kbdfront 4249 0 softcursor 1565 1 bitblit xen_fbfront 7225 2 fb_sys_fops 1611 1 xen_fbfront sysimgblt 2547 1 xen_fbfront sysfillrect 3949 1 xen_fbfront xen_netfront 17890 0 syscopyarea 3640 1 xen_fbfront lp 9336 0 parport 37160 2 ppdev,lp xen_blkfront 10697 3
逆に8139cpや8139tooといった物理NIC用のドライバはロードされていないことが確認できます。
例えば修正前の仮想マシン定義ファイルをhvm.cfg, 修正後をpvm.cfgとして保存しておけば起動するときにHVMとして起動するかPVMとして起動するか切り替えることが可能になります。仮想マシンそのものは同じもので。pvops、素敵ですね。
VT-dを使ってXenでPCI-Passthroughを設定する手順
システム環境
- CPU: Intel Core-i7 860
- チップセット: Intel P55 Express
- マザーボード: MSI P55M-SD40
- Xen: 3.4.0
- dom0: Oracle VM Server (Oracle Enterprise Linux 5.3ベース)
- Passthrough対象のdomU: OpenSolaris b134 PVHVM
Xenは既にインストールされているという前提で始めます。/etc/grub.confのkernel行に「iommu=pv」と追記してI/O Virtualizationを有効化します。*これはBIOSでの有効とは異なります。BIOSでI/O Virtualizationを有効にした上でこの設定を行います。参考までにgrub.conf全体を。
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Oracle VM server (2.6.18-128.2.1.4.25.el5xen)
root (hd0,0)
kernel /xen-64bit.gz dom0_mem=564M iommu=pv
module /vmlinuz-2.6.18-128.2.1.4.25.el5xen ro root=UUID=d060bc44-d5d2-49ec-8312-222c761a3746
module /initrd-2.6.18-128.2.1.4.25.el5xen.img
*より一般的にはiommu=1と設定しますが、これではPVM(準仮想化マシン)に対してのPassthroughが有効にならないのでiommu=pvとしています。iommu=pvとすればHVM, PVM双方でPassthroughが有効になります。
ここで一度OSを再起動します。再起動後、xm dmesgコマンドを発行してI/O Virtualizationが有効になったことを確認します。
[root@vmserver]# xm dmesg | grep "I/O virtualisation" (XEN) I/O virtualisation enabled (XEN) I/O virtualisation for PV guests enabled
*ちなみにgrepする場合はvirtualizationではなく上記のようにvirtualisationで引っ掛けてください。
次にdomUにPassthroughしたいPCIデバイスをdom0から隠します。作業の流れとしては、まず対象となるPCIデバイスのBDFを求めます(BDFについて詳しくはこちら)。次にPCIデバイスをdom0から隠すためのカーネルモジュール「pciback」をロードします。そしてsysファイルシステムを使うか、modprobe.confに適当な記述を行うことでPCIデバイスをdom0から隠しdomUにPassthrough可能な状態にします。
BDFはlspciコマンドでPCIデバイスの一覧を表示させ、それっぽいモノを判別します。
[root@vmserver]# lspci
00:00.0 Host bridge: Intel Corporation Clarksfield/Lynnfield DMI (rev 11)
00:03.0 PCI bridge: Intel Corporation Clarksfield/Lynnfield PCI Express Root Port 1 (rev 11)
00:08.0 System peripheral: Intel Corporation Clarksfield/Lynnfield System Management Registers (rev 11)
00:08.1 System peripheral: Intel Corporation Clarksfield/Lynnfield Semaphore and Scratchpad Registers (rev 11)
00:08.2 System peripheral: Intel Corporation Clarksfield/Lynnfield System Control and Status Registers (rev 11)
00:08.3 System peripheral: Intel Corporation Clarksfield/Lynnfield Miscellaneous Registers (rev 11)
00:10.0 System peripheral: Intel Corporation QPI Link (rev 11)
00:10.1 System peripheral: Intel Corporation QPI Routing and Protocol Registers (rev 11)
00:1a.0 USB Controller: Intel Corporation Ibex Peak USB2 Enhanced Host Controller (rev 05)
00:1b.0 Audio device: Intel Corporation Ibex Peak High Definition Audio (rev 05)
00:1c.0 PCI bridge: Intel Corporation Ibex Peak PCI Express Root Port 1 (rev 05)
00:1c.4 PCI bridge: Intel Corporation Ibex Peak PCI Express Root Port 5 (rev 05)
00:1c.5 PCI bridge: Intel Corporation Ibex Peak PCI Express Root Port 6 (rev 05)
00:1d.0 USB Controller: Intel Corporation Ibex Peak USB2 Enhanced Host Controller (rev 05)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev a5)
00:1f.0 ISA bridge: Intel Corporation Ibex Peak LPC Interface Controller (rev 05)
00:1f.2 IDE interface: Intel Corporation Ibex Peak 4 port SATA IDE Controller (rev 05)
00:1f.3 SMBus: Intel Corporation Ibex Peak SMBus Controller (rev 05)
00:1f.5 IDE interface: Intel Corporation Ibex Peak 2 port SATA IDE Controller (rev 05)
01:00.0 VGA compatible controller: nVidia Corporation Unknown device 0a65 (rev a2)
01:00.1 Audio device: nVidia Corporation Unknown device 0be3 (rev a1)
03:00.0 SATA controller: 1b4b:9123 (rev 11)
04:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 03)
手元の環境では増設したSATAコントローラ(赤字)がPassthroughしたいPCIデバイスです。したがって対象のBDFは03:00.0です。が、実際にはこの番号の頭に0000:をくっつけて、『0000:03:00.0」が正式なBDFで、この後もこちらの正式なBDFを使用します。
*ちなみに00:1f.0, 00:1f.2, 00:1f.3, 00:1f.5のように下一桁だけが異なるものはマルチファンクションのPCIデバイスです。この例ではこのPCIデバイスはオンボードのSATAコントローラ・ブリッジで、6ポートのSATAポートを装備しています。そしてこの内4ポートが00:1f.2に属しており、2ポートが00:1f.5に属しています。一度00:1f.2にSSDを一枚差し、00:1f.5にSSDを一枚差して後者だけをdomUにPassthroughできるか試してみましたが、結果はNGでした。Xen 3.4.0とXen 4.0.0両方でトライしましたが、前者は一見うまくいったように見えるのですがその内I/Oエラーやファイルシステムのジャーナルエラーが報告され、domo, domUともフリーズしました。後者は割り当てた瞬間にフリーズが発生しました。DMAのマップがめちゃくちゃになってそうな雰囲気です。
次にpcibackのロードですが、Oracle VM Serverのdom0カーネルでは(恐らく多くの他の環境でも)、pcibackはカーネルに組み込まれてビルドされておらずモジュールとしてビルドされています。この状態ではpcibackはオンラインでmodprobeコマンドによってロードできますが、逆にブート時にカーネルパラメータを渡すことでロードすることはできません。自動的にロードさせたい場合はブートのもう少し後の段階でロードします。具体的にはrc.localかmodprobe.confを少々編集します。今回はrc.localに記載する手順で話を進めます。そしてロードに続けてPCIデバイスをdom0から隠しPassthrough可能にする設定を行います。これらをまとめてrc.localに下記のように記述します。
BDF=0000:03:00.0
# Load pciback
modprobe pciback
# Unbind a PCI function from its driver as necessary
[ ! -e /sys/bus/pci/devices/$BDF/driver/unbind ] || \
echo -n $BDF > /sys/bus/pci/devices/$BDF/driver/unbind
# Add a new slot to the PCI Backend's list
echo -n $BDF > /sys/bus/pci/drivers/pciback/new_slot
# Now that the backend is watching for the slot, bind to it
echo -n $BDF > /sys/bus/pci/drivers/pciback/bind
*pcibackはpvops採用のdom0カーネルではxen-pcibackと名前が変更されています。
*環境によってはPCIデバイスをunbindした瞬間にOSがクラッシュするかもしれません。僕はahciドライバで認識しているデバイスをunbindしたときにこのクラッシュに遭遇しました。これを回避するためにはrc.localではなくmodprobe.confを利用する設定方法が有効でした。ahci等のドライバがデバイスを認識する前にpcibackをロードして該当デバイスを隠蔽することによって回避することができました。詳しくはこちらの2.の手法を参照してください。skgeは手元の環境に合わせて変える必要があります。
設定がうまくいっていれば、xm pci-list-assignable-deviceで確認できます。
[root@vmserver]# xm pci-list-assignable-device 0000:03:00.0
この出力が確認できれば対象のPCIデバイスはPassthroughされる準備が整っています。あとはdomUの設定ファイルにてpci = [ '0000:03:00.0' ]の記述を入れてdomUを起動すればPassthroughが実現できます。参考までに手元のOpenSolaris b134のPVHVMの設定ファイルを掲載しておきます。
acpi = 1
apic = 1
builder = 'hvm'
device_model = '/usr/lib/xen/bin/qemu-dm'
disk = ['file:/var/ovs/mount/4ED5C364C05246FE8AEE8C0E26D79ACF/running_pool/nas/System.img,hda,w',
',hdc:cdrom,r',
]
kernel = '/usr/lib/xen/boot/hvmloader'
keymap = 'en-us'
memory = '1024'
name = 'nas'
on_crash = 'restart'
on_reboot = 'restart'
pae = 1
pci = ['0000:03:00.0']
serial = 'pty'
timer_mode = '0'
uuid = '42d9bfd3-dd90-4b54-a8a0-af90bcc53028'
vcpus = 4
vif = ['bridge=xenbr0,mac=00:16:3E:15:01:3E,type=netfront']
vif_other_config = []
vnc = 1
vncconsole = 1
vnclisten = '0.0.0.0'
vncpasswd = 'secret'
vncunused = 1
正直PCI-Passthroughの設定はなかなかクセがあり、苦労しました。動いたように見えて半日くらいしてからI/Oエラーがでたり、サーバ全体がクラッシュしたり、デバイスによっては隠蔽設定はうまくいくもののxm pci-list-assignable-deviceには表示されなかったり、Xenのバージョンによってかなり挙動が違ったり。下記にPCI-Passthroughにおける教訓を掲載しておきます 。
- マルチファンクションデバイスの一部だけPassthroughしようとしない。Passthroughするときは丸ごと。
- Linuxで確実に動作する鉄板のPCIデバイスを使う。
- Xenは出来る限り新しいバージョンを使う。
- 動いたと思っても油断しない。最低1日はヒートランすべき。
*今回検証した機材の他に、下記の組み合わせでも動作を確認しています。ご参考まで。
- CPU: Intel Core-i7 860
- チップセット: Intel H55 Express
- マザーボード: Intel DH55TC
- Xen: 4.0.0
- dom0: Fedora12 kernel 2.6.32
- Passthrough対象のdomU: OpenSolaris b134 PVHVM
XenのPCI-Passthroughとは?そのユースケースは?
PCI-Passthroughとは、PCIデバイスをごっそりdomU(ゲストOS)に「あげちゃう」手法です。ちなみにPCIデバイスとは主にディスクコントローラであったり、HBAであったり、ネットワークカードであったり、あるいはグラフィックカードであったりします。わかり易くするためにPCIデバイスをディスクに絞って話を進めます。通常XenではディスクをdomUに割り当てる際にはdom0が物理ディスクを一度認識した上で、そのディスクリソースを分配する形でdomUに割り当てるVBD(Virtual Block Device)という形式をとります。
例えばサーバにSATAディスクが接続されているとします。これはオンボードまたは拡張PCIカードのSATAコントローラにSATAケーブルで接続されています。このディスクがdomUに認識される道筋を通常のVBD形式とPCI-Passthroughとで比較したのが下図です。
通常のVBD割り当て
.png)
- ディスク(PCIデバイス)はdom0によって管理され、複数のdomUで共有できる
- domUからのディスクアクセスはdom0を経由して物理デバイスに到達する(一般的に性能劣化が発生する)
- domUはデバイスドライバを使用しない(厳密にはdom0が提供するダミーデバイスと通信するためのドライバを使用する)
PCI-Passthroughの場合
.png)
- PCI-Passthrough対象のSATAコントローラ(PCIデバイス)はdom0に認識させない
- PCI-Passthroughを行うdomUがSATAコントローラ(PCIデバイス)を独占する
- PCI-Passthroughを行うdomUからのディスクアクセスはは自身のデバイスドライバを使用して直接SATAコントローラ(PCIデバイス)、ディスクに到達する(dom0経由によって発生していた性能劣化から解放される)
- domUとローカルマシンのデバイスとの静的な紐付けが行われるため、ライブマイグレーションが出来ないといった制約が発生する
ひとことで言えば、
- PCI-Passthroughを使用すればdomUのディスクアクセスは高速になるが、そのデバイスは一つのdomUによって独占されてしまう。
ということになります。環境によってこれが使えそうかどうかはそれぞれだと思いますが、SATAコントローラが丸ごと一つのdomU専用になってしまうのでは収容できる仮想マシンの台数が大幅に制限されてしまいます。
*厳密には単一のSATAコントローラでもポートがハブ形式になっており複数のPCI識別子(BDF)が割り当てられていることもあるのでその場合はこの限りではない
仮想化とはそもそもH/WとOSを疎結合にすることが大きなメリットの一つでした。その中でPCI-Passthroughのような密結合を引き起こすコンフィグレーションはどのようなシチュエーションで有用なのでしょうか?
僕が考えるユースケースの一つはNASのバーチャルアプライアンスを稼動させる場合です。実際、NexentaStorのようにNAS(NFS, iSCSI)を仮想マシンとして構成することができる製品が存在します。そのような製品では仮想マシンとして高速にディスクにアクセスすることがマストの要件になってきますし、NASバーチャルアプライアンスが使用するディスクを他のdomUと共有するといった必然性は恐らくないでしょう。したがってNASバーチャルアプライアンスのような製品ではPCI-Passthroughは理想的なコンフィグレーションだと思います。
「仮想マシンでNASを構成しようなんて思うか?」という意見が聞こえてきそうですが、例えば僕は今その必要性に迫られています。限られたサーバ資源をフルに活用してフルスペックの仮想化環境を自宅に構築したいと思っています。しかしストレージ専用機、なんてもってのほかですし(費用、スペース、音、電力、等々)、サーバを丸ごとストレージにするのも勿体ない。そんなとき、OpenSolarisのZFSを使ったNASを仮想マシンで構成できればとても効率的ですよね。でも仮想マシンだとI/O系のパフォーマンスに不安がある。そんなときに!このPCI-Passthorughがソリューションになります。具体的にはOpenSolarisをEPT, VT-dが有効なサーバ上にPVHVMとして作成します。そしてSSDをPCI-PassthroughでOpenSolaris PVHVMから直接I/Oできるようにすればベアメタル上のネイティブOSと遜色ないパフォーマンスが確保できます。メモリアクセスや演算処理もVTテクノロジで実際非常に高速に動作します。ネットワークについてもPCI-Passthroughすることは可能ですが、手元の環境ではNICが豊富にあるわけではないのでネットワークアクセスについてはdom0から割り当てたVIFをPVドライバで高速化するという構成です。(そもそも通信は同筐体内という前提ですし)そして同一サーバ上の他のdomUはこのOpenSolaris PVHVMのZFS上に作成します。ZFSの機能を存分に活用してスナップショットによるバックアップ/ロールバック、クローンによる高速プロビジョニング、圧縮、重複排除などの高度なストレージ技術がすべて利用できます。それも物理的にはサーバ一台というオールインワンで。検証環境としては最高に高密度なシロモノとなります。
.png)
また、僕のような変テコな検証環境だけでなく、これからI/Aサーバをストレージとして使用する「Open Storage」という実装が世に広がってくるようになれば、このような構成がフィットするケースが増えてくるのではないかと考えています。
それでは別エントリでこのPCI-Passthroughの構成方法を解説しようと思います。
PVMとPVHVMの性能比較
PVMとは準仮想マシンのことで、より高性能を求めてカーネルがゲストOS専用に改造されています。
一方、HVMとは完全仮想マシンのことで、カーネルには何ら手が加えられていません。
これまでは単純にPVMとHVMの性能を比較すると圧倒的にPVMが勝っていました。HVMで最も性能劣化が顕著なのは下記2点です。
- ネットワーク、ディスクI/O
- メモリ管理
しかしネットワーク、ディスクI/OについてはHVMであっても実はPVドライバを別途インストールすることでPVMと遜色ない性能を確保することが可能でした。
*このHVMにPVドライバをインストールした仮想マシンのことを属にPVHVMと呼んでいます。
問題だったのはメモリ管理です。HVMのゲストOSのメモリアドレスから物理メモリのアドレスを求めるときのオーバヘッドが非常に大きかったのです。しかし実はこれも状況が変わってきています。Intelのコードネーム:Nehalemと呼ばれている新しい(といってもリリースされてもう久しいが)アーキテクチャのCPUは仮想化支援機構を強化しています。その目玉がEPTという機能で、先ほど大きなオーバーヘッドであると言ったHVMのメモリアドレス変換処理を高速化するための機構です。
*ちなみにEPTはHVM用の機構なのでPVMには影響しません。
実際このEPTの効果は様々なテストによって非常に大きいと言われています。そもそもPVMではこのメモリ変換処理を、改造したカーネルによってオーバヘッドを緩和していました。HVMではHypervisorがゲストOSの素のカーネルから発行される物理メモリへのアクセスをトラップして実際のアドレスに修正するというタフな処理を行っていたのでオーバヘッドが大きかったのですが、それがEPTによってHypervisorはそのトラップ&変換処理をCPUに任せることができるようになりました。
そこで気になるにはどれくらい速いのか? ですよね。
ということでEPTの効果が如実に現れるという噂のソフトウェアのコンパイル処理をPVMとPVHVMで行いました。
環境
- 物理CPU:Core i7 860(クアッドコア & Hyper-Threading)
- Hypervisor:Xen 3.4
- ゲストOS:Enterprise Linux 5u4 64bit(vCPUを4つ割り当て)
- カーネル:2.6.18-164
テスト内容
- php-5.3.1をmake -j8として8スレッドでコンパイルし、所要時間を計測
結果
- PVM:55秒
- PVHVM:46秒
ということで確かにPVHVMの方が高速です。HVMがPVMを性能面で上回るというのは以前は考えられないことでしたがEPT恐るべし、です。
これからはXenであってもゲストOSはHVM(PVHVM)を選択することも視野に入れねばなりませんね。
Sunが提供している仮想化技術まとめ
Logical Domains (Ldoms)
- SPARCプラットフォームの”CoolThreads Servers”で利用できるハードウェア仮想化技術 参考:Ldomsのポイント
- サポートされるゲストOS
- Solaris
- 理論的にはLinuxやBSDも動きそうだけどサポートされてるのかは不明
- Oracle Database, RACがサポートされる
Solaris Container
- SolarisのOSパーティション技術。ハードウェアを仮想化するのではなく、OS空間を区切る技術。
- サポートされるゲストOS
- Solaris
- OpenSolaris
- Oracle RACはサポートされない
xVM Server
- Xenベースのハードウェア仮想化技術(ソフトウェアでハードウェア仮想化するの意)
- サポートされるゲストOS
- Solaris 10 5/08以降
- OpenSolaris 2008.05以降
- RHEL 4.6, 5.2
- Windows XP, 2003, 2008
- Oracle RACはサポートされない
なお、デスクトップ仮想化については省略。
ゲストOSでクラッシュダンプを取得するには
現在のところOracle VM上のゲストOSクラッシュダンプを取得したいとき、kdumpは使えなさげです。しかしながらxm dump-coreコマンドを使えば同等のことがもっと簡単に実装できます。
まず、対象のゲストOSのvm.cfg(設定ファイル)を編集してクラッシュ時の動作を設定します。
# vi /OVS/running_pool/GUEST/vm.cfg on_crash = preserve
このように設定することでゲストOSがクラッシュした際に再起動等を行わずにメモリイメージを保持させることができます。
そして実際にクラッシュした際にxm dump-coreでそのメモリイメージをダンプします。
# xm dump-core -C [DOMAIN_ID] [OUTFILE]
これでOUTFILEとしてクラッシュダンプが生成されます。
.png)