VMware Paravirtual SCSI(PVSCSI):仮想マシンのCPU負荷を削減してディスクスループットを向上させる

VMware tutorial - IT technology blog
VMware tutorial - IT technology blog

仮想ディスクがボトルネックになるとき

先月、会社のVMware vSphere 8.0クラスター全体のストレージレイヤーを見直す作業を終えた。きっかけは、データベース(MySQL、PostgreSQL)を動かしているVMが異常に高いI/O waitを継続的に報告していたことだ。CPU ready timeを確認しても問題なく、RAMも十分だったが、ディスクスループットはSANの理論値ベンチマークと比べて60〜70%程度しか出ていなかった。

datastore、HBAドライバー、RAIDポリシーなど、考えられる原因を一つひとつ排除していくうちに、該当するすべてのVMがLSI Logic SASアダプターを使っていることに気づいた。vSphereで新規VMを作成する際のデフォルト設定だ。これは実際のハードウェアをエミュレートするアダプターであり、それこそが問題の原因だった。

PVSCSI(Paravirtual SCSI)に切り替えることで、大部分の問題が解決した。CPU I/O処理は目に見えて低下し、スループットは期待通りのレベルまで向上した。この記事では、その過程を記録する。技術的な理由から実施手順、結果の測定方法まで順を追って説明する。

PVSCSIとLSI Logicの違い

LSI Logic SAS/BusLogicはエミュレートされたアダプターだ。VMkernelは実際のハードウェアデバイスの動作をすべて仮想的に再現する必要がある。ゲストOSからのI/O命令は、オーバーヘッドだらけのエミュレーション層を通過する——割り込みシミュレーション、レジスターエミュレーション、DMAマッピングの仮想化などだ。ゲストOSには特別なドライバーが不要で、実際のハードウェアと通信していると「思い込んでいる」ため、そのまま動作する。

PVSCSIはパラバーチャライズドアダプターだ。ゲストOSはVMware上で動作していることを認識しており、専用ドライバーを使って最適化されたプロトコルでVMkernelと直接通信する。エミュレーション層は存在しない。I/Oリクエストは直接VMkernelに渡るため、消費するCPUサイクルが大幅に削減される。

VMwareが公表したベンチマークによれば、I/O負荷の高いワークロードでは:

  • I/O負荷の高いワークロードでCPUオーバーヘッドが約30〜50%削減
  • シーケンシャル読み書きでスループットが最大20〜30%向上
  • データベースワークロードでランダム4K IOPSが20〜40%改善(ストレージ構成による)

ただし、PVSCSIが常に優れているわけではない。静的なWebサーバーや軽いdev/test環境など、I/Oの少ないVMではほとんど差が出ない。PVSCSIが真価を発揮するのは、データベースサーバー、ファイルサーバー、CI/CDビルドパイプラインを継続的に実行するVMといった、I/O負荷の高いワークロードだ。

PVSCSIを使用するための条件

  • VMware vSphere 4.0以上(またはVMware Workstation 6.5+)
  • ゲストOS: RHEL/CentOS 5+、Ubuntu 10.04+、Windows Server 2003 SP2+(VMware Tools必須)、Windows Vista+(ビルトインドライバーあり)
  • VMware Toolsがインストールされ、最新の状態であること
  • 重要な注意点:Windows Server 2003、RHEL 4などの古いOSはブートイメージにPVSCSIドライバーが含まれていないため、PVSCSIをブートディスクとして使用する場合はドライバーの注入が必要

PVSCSIの設定 — 実践的なステップバイステップ

方法1:vSphere Client(GUI)でアダプターを変更する

1〜2台のVMには最も手軽な方法だ。VMは完全なPower Off状態である必要がある(Suspendではない)。

  1. VMを右クリック → Edit Settings
  2. SCSI Controller 0(または現在のアダプター)をクリック
  3. Change Typeドロップダウン → VMware Paravirtualを選択
  4. OKをクリック → VMをPower On

起動後、WindowsではDevice Managerを開いて「VMware PVSCSI Controller」を確認し、ドライバーが正しくロードされているかチェックする。Linuxの場合はlsmod | grep vmw_pvscsiで確認できる。

方法2:PowerCLIを使って複数のVMを一括変更する

10台以上のVMを手作業でやるのは半日仕事だ。PowerCLIなら数分で終わる:

# vCenterに接続
Connect-VIServer -Server vcenter.yourdomain.com

# 変更対象のVMリストを取得(例:「Production-DB」フォルダー内のすべてのVM)
$vms = Get-VM -Location (Get-Folder "Production-DB")

foreach ($vm in $vms) {
    # 実行中のVMをスキップ
    if ($vm.PowerState -ne "PoweredOff") {
        Write-Warning "$($vm.Name) は実行中です。スキップします..."
        continue
    }

    # PVSCSI以外のSCSIコントローラーを取得
    $scsiCtrl = Get-ScsiController -VM $vm | Where-Object { $_.Type -ne "ParaVirtualSCSI" }

    if ($scsiCtrl) {
        Write-Host "$($vm.Name) のSCSIアダプターを変更しています..."
        Set-ScsiController -ScsiController $scsiCtrl -Type ParaVirtualSCSI
        Write-Host "  完了: $($vm.Name)" -ForegroundColor Green
    } else {
        Write-Host "$($vm.Name) はすでにPVSCSIを使用しています。スキップします。" -ForegroundColor Cyan
    }
}

Disconnect-VIServer -Confirm:$false

実践的な注意点として、一度に全部Power Onしないこと。3〜5台ずつバッチ処理し、ログとディスクパフォーマンスを確認してから次に進もう。ドライバーの問題が発生した場合でも、すぐに気づけるし、何十台もまとめてではなく少数のVMだけロールバックすれば済む。

方法3:.vmxファイルを直接編集する(VMware Workstation / Fusion)

# VMの.vmxファイルを検索
find ~/vmware -name "*.vmx" | grep "VMName"

# ファイルを開いてscsi0.virtualDevの行を見つけ、以下を変更:
#   scsi0.virtualDev = "lsisas1068"
# 変更後:
#   scsi0.virtualDev = "pvscsi"

sed -i 's/scsi0.virtualDev = "lsisas1068"/scsi0.virtualDev = "pvscsi"/' /path/to/vm.vmx

その後、VMware Workstationを起動して通常通りVMをPower Onする。

変更後の確認 — Linuxゲストの場合

# PVSCSIドライバーがロードされているか確認
lsmod | grep vmw_pvscsi
# vmw_pvscsi            36864  4

# ディスクコントローラーの情報を確認
lspci | grep -i scsi
# VMware PVSCSI SCSI Controller

# ddコマンドでディスクの基本速度を確認
dd if=/dev/zero of=/tmp/test_io bs=1M count=1024 oflag=direct
# 1073741824 bytes (1.1 GB) copied, 2.84 s, 378 MB/s

fioを使った実際のベンチマーク

より正確に計測するために、I/Oベンチマークの標準ツールfioを使用した:

# fioのインストール
apt install fio        # Ubuntu/Debian
yum install fio        # CentOS/RHEL

# テスト1: シーケンシャル書き込み(ログ書き込み・バックアップを想定)
fio --name=seq-write \
    --ioengine=libaio \
    --rw=write \
    --bs=1M \
    --numjobs=4 \
    --size=2G \
    --runtime=60 \
    --group_reporting \
    --filename=/tmp/fio_test

# テスト2: ランダム4K読み込み(データベースIOPSを想定)
fio --name=rand-read \
    --ioengine=libaio \
    --rw=randread \
    --bs=4k \
    --iodepth=64 \
    --numjobs=4 \
    --size=2G \
    --runtime=60 \
    --group_reporting \
    --filename=/tmp/fio_test

PostgreSQLを動かしているVM(vSphere 8.0、NVMeデータストア)での実際の比較結果:

  • LSI Logic SAS:ランダム4K読み込み 〜85K IOPS、CPU I/O wait 〜12%
  • PVSCSI:ランダム4K読み込み 〜118K IOPS、CPU I/O wait 〜6%

CPU waitが12%から6%に半減した——これが最も印象的だった。以前はCPUサイクルの半分がI/O待ちで「足止め」されていたことになる。解放されたリソースにより、PostgreSQLは実際のクエリ処理により多くのリソースを充てられるようになった。

Proxmoxの視点から — PVSCSIをより深く理解する

個人のラボ環境をVMwareからProxmoxに移行したとき、いくつかの興味深い違いに気づいた。ProxmoxはPVSCSIの代わりにVirtIO SCSIをパラバーチャルアダプターとして採用している。原理は同じだが実装が異なる。Proxmoxでも、VirtIOを有効にしていなければ、ディスクパフォーマンスはLSI LogicをエミュレートしているVMwareと同様に低下する。

得られた教訓:パラバーチャライゼーションは「VMware独自の機能」ではなく、すべての本格的なハイパーバイザーが実装すべきI/O最適化アーキテクチャだ。VMwareはそれをPVSCSIと呼び、KVM/ProxmoxはVirtIOと呼ぶ。本質は同じで、どちらもエミュレーションのオーバーヘッドという共通の問題を解決している。

PVSCSIへの変更を避けるべきケース

  • ビルトインドライバーのない古いOSのブートディスク:Windows Server 2003、RHEL 4はブートディスクを変更する前に、WinPEまたはinitramfsにPVSCSIドライバーを注入する必要がある。この作業に慣れていない場合は、ブートディスクはLSI Logicのままにして、データディスクだけPVSCSIに変更する方が安全だ。
  • I/Oの少ないテスト/開発用VM:静的なWebサーバーや軽い開発環境のためにダウンタイムをとってアダプターを変更する価値はない。
  • メンテナンスウィンドウがない場合:SCSIアダプターの変更にはVMの完全なPower Offが必要だ。スケジュールを明確に設定し、事前に関係者へ通知すること。

まとめ

PVSCSIの魅力はここにある——追加のハードウェアも新しいライセンスも不要で、その存在を知って設定を一つ変えるだけでいい。それにもかかわらず、「デフォルトでそう設定されていたから、誰も変えなかった」という理由で、多くの本番環境がいまだにLSI Logicで動き続けている。

I/O負荷の高いワークロード(データベース、ビルドサーバー、VM内で動作するNFSサーバー)を持つVMwareクラスターを管理しているなら、SCSIアダプタータイプの監査を優先すべきだ。各VMのダウンタイムはわずか数分だが、モニタリングダッシュボード上で改善をすぐに確認できる。

最後のヒント:PVSCSI切り替え後は、キュー深度(queue depth)も確認すること。PVSCSIのデフォルトのキュー深度はLSI Logicより大きい(デバイスあたり256対32)。データストアに独自の制限がある場合、キューの飽和を防ぎ同じデータストアを共有する他のVMへの影響を避けるために、ESXiホストのDisk.SchedNumReqOutstandingパラメーターを追加チューニングする必要があるかもしれない。

Share: