tkokamoの日記

HPCの研究開発なのでそんなことをかきたい

virtio(vhost)の概要

48-146407
kvmなどの仮想化環境において、ゲストOSのネットワークやディスクI/Oを早くするために、virtioと呼ばれる準仮想化ドライバドライバを用いることがある。
今回は、あまり技術的に細かい部分には突っ込まず、なぜゲストOSのI/Oが遅いのか、なぜvirtioを用いると速くなるのか簡単に整理してみた。

virtio(vhost)の反映の仕方(virt-manager)

virtio-net(vhost-net)の場合

virt-managerを開いてvirtioを反映させたいVMをを開く。VMのコンソールのメニューで[表示]→[詳細]を選択し、NICのデバイスモデルをvirtioにし、適用を押せばよい。この時、すでにVMが起動している場合、一度シャットダウンしてからでないと反映されない。

f:id:tkokamo:20140818193231p:plain

システムのバージョンに依存すると思われるが、virtioを適用していても実際にはvhost-netを用いている可能性がある。これらの違いについては後述するが、確認をしたい場合には、ターミナルから以下のコマンドを実行して

$ ps ax | grep vhost
 4964 ?        Sl     0:04 qemu-system-x86_64 -enable-kvm /*途中省略*/ vhost=on,vhostfd=25 /*省略*/

vhost=onとなっていればvhost-netを使っていることになる。

通常のOSとゲストOSのI/Oの違い

通常のOSにおけるI/OとゲストOSにおけるI/Oの違いを最初に考えてみる。

f:id:tkokamo:20140819010811p:plain

 上の図で、通常のOSでは、アプリケーションがシステムコールを行なうと(①)、カーネルに制御が移る。そして、カーネルが処理を行なった後(③)で、アプリケーションに戻ってくる(④)。
 これと同じ処理を仮想化環境(kvmの場合を考える)で行なおうとすると非常に大変になってくる(上手の右)。まず通常のOSと同様にゲストOS上のアプリケーションが(ゲストOSの)システムコールを行なうと(①)、ゲストカーネルに制御が移る。この時、ネットワークのI/Oの場合であれば、ゲストカーネルがネットワークコントローラのレジスタを書き換えようとする(②)。しかし、ゲストOSが勝手にハードウェアをいじることができてしまうと、勝手にホストのシステムの状態を変えることができてしまうので、危険である。そのため、CPUが例外を発生させ、KVMに制御を移す(③)。KVMでは、ゲストOSのI/Oを処理する時のデバイスのエミュレーションは、qemuによって行なうので、KVMからqemuに対して制御が移る(④)。qemuは、例外の発生の原因に応じてデバイスのエミュレーションを行なうが、このときの⑤~⑧の処理の流れは、通常のOSの場合の処理と概ね同じである。qemuは、デバイスのエミュレーションを行なった後にkvmに制御を戻し(⑨)、kvmはゲストカーネルに処理を戻す(⑩)。最後に、ゲストOSのアプリケーションに戻ってくることで処理が完了する(⑪)。
 kvmでは、仮想化環境を構築するために、CPUによる仮想化支援機構を用いている。ここでは細かく言及しないが、この仮想化支援機構によって、ゲストOSのモード(VMX non root mode)とVMMのモード(VMX root mode)に切り替えながら処理を行なうことで、従来の仮想化支援を用いない場合に比べて、比較的容易に仮想化環境を構築することができる。上図では、ゲストOSとホスト間を行き来している数だけ状態の切り替えが生じている。この状態の切り替えには1000サイクル程度かかる(ハイパーバイザの作り方~ちゃんと理解する仮想化技術~ 第11回 virtioによる準仮想化デバイス その1「virtioの概要とVirtio PCI」)。実際のネットワークなどのI/Oでは、複数回デバイスのレジスタに書き込みを行なう必要があり、この度に①~⑪までの処理を行なう必要があるので、オーバーヘッドが非常に多い。

virtioとvhost

このオーバーヘッドを削減するために、virtio、そしてvhostという方法が考えられている。
 virtioでは、qemuとゲストOS間で共有メモリを用意し、一定のデータを溜める。そして、実際に処理を行なう時に、VMMに制御を移し処理を行なうことで、VMX non root modeとVMX root modeのモードの遷移数を減らし、オーバーヘッドの削減を実現している。その一方で、virtioでは、デバイスのエミュレーションにqemuを用いている。そのため、実際にデータの処理を行なう場合に、userlandとkernellandで状態の遷移が起きる(上の図では④~⑨)ため、性能の低下を招く懸念がある。
 これに対し、vhostではゲストOSとホストのカーネル間で共有メモリを用いることで、qemuを介さず処理を行なうことで、virtioに比べ更なる実行速度の改善を図っている。

性能比

 実際にどの程度性能が上がるかが
https://www.nic.ad.jp/ja/materials/iw/2012/proceedings/d1/d1-Asama.pdf
に示されている。
 準仮想化ドライバを用いない場合とvirtio-netを用いた場合ではTCPの送信で17~20倍、UDPの送信で9~12倍という高い速度改善が見られる(受信についても、十分に速度が改善している)。
 一方、virtio-netとvhost-netでは概ねvhost-netの方が高いスループットを示しているが、そうでもないものもある。

今後、細かい部分に触れることができればいいなぁ