レッドハットが考えるNFV環境向けのチューニング

レッドハットでコンサルタントをしております織と申します。赤帽エンジニア Advent Calendar 2019の5日目のエントリーです (6日目の方が先に出ちゃいましたが)。 本記事では、「レッドハットが考えるNFV環境向けのチューニング」についてご紹介します。

前提

NFV環境向けのレッドハットの製品は、現時点ではOpenStackが相当します。レッドハットの考えるOpenStackを使ったNFV環境とはどういうものかというと、

  • KVMホスト(OpenStackコンピュートノード)上でSR-IOVもしくはOVS-DPDKを使い
  • 仮想マシン上でDPDKのアプリをぶん回し
  • ショートパケットの通信でなるべくパケットをドロップしない

というユースケースを想定しています。

仮想マシン上で稼働するDPDKアプリがパケットを落とさないようにするためには、DPDKのPMD(Poll Mode Driver)にアサインしたVCPUが止まることなくパケットを転送し続ける必要があります。 「仮想マシンの中で止まることなくパケットを転送し続ける」のは意外と難しく、

  1. 仮想マシンのVCPUを処理するQEMUスレッドが、Linuxカーネルのスケジューリングによって別の物理CPUコアにマイグレートした
  2. 仮想マシンのVCPUがアサインされた物理CPUコアに対して、何か(カーネルスレッド等)が割り込んだ

等が原因となってパケ落ちが発生します。

RHOSPには「Network Functions Virtualization Planning and Configuration Guide」というドキュメント1があり、ここに記載された手順にしたがって環境を構築すると、a., b. のような事象が可能な限り発生しないようにカーネル等のパラメータをチューニングします。

ガイドに記載された内容は、TripleOに慣れていないと何をしているのかわかりにくいのですが、乱暴にまとめると

  • カーネル起動パラメータに isolcpus=... を指定し 2
  • tunedのプロファイルで cpu-partitioning を使う

という設定をコンピュートノードに対して施します。以下、この内容について少し掘り下げて見てみます。

isolcpus

通常Linuxカーネルは、CPUの負荷状況に応じて、プロセスを実行する物理コアを移動することがあります。 カーネル起動パラメータisolcpusでコア番号を指定すると、その物理コアにスケジュールされたプロセスは、CPUの負荷状況が変わっても別の物理コアに再スケジュールされなくなります。

もともとReal TIme処理用に実装されたisolcpusを指定することで、上記 a. の事象を回避します。

tunedのcpu-partitioningプロファイル

実はisolcpusだけだと、上記 b. の事象は回避できません。b. の事象を回避するために、様々な細かいチューニングをこっそりとやってくれるのがtunedのcpu-partitioningプロファイルです。

tunedは、設定したプロファイルに応じてRHELの各種パラメータを動的に変更してくれます。あらかじめ用意されているプロファイルは下記になります。

# tuned-adm list
Available profiles:
- balanced                    - General non-specialized tuned profile
- cpu-partitioning            - Optimize for CPU partitioning
- desktop                     - Optimize for the desktop use-case
- hpc-compute                 - Optimize for HPC compute workloads
- latency-performance         - Optimize for deterministic performance at the cost of increased power consumption
- network-latency             - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance
- network-throughput          - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
- powersave                   - Optimize for low power consumption
- throughput-performance      - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
- virtual-guest               - Optimize for running inside a virtual guest
- virtual-host                - Optimize for running KVM guests
Current active profile: virtual-guest

cpu-partitioningプロファイルでどういう設定が適用されるかは、/usr/lib/tuned/cpu-partitioning/tuned.conf を見ればわかります。 おおざっぱにまとめると、以下のようなチューニングを実施してくれます。

  • latency-performanceプロファイルの設定を適用する (CPU Governerをperformanceにしたり、スケジューラや仮想メモリ周りのsysctlパラメータを設定したり)
  • network-latencyプロファイルの設定を適用する (Transparent Hugepageを禁止したり、NUMAバランシングを禁止したり、ネットワーク関連のsysctlパラメータをいくつか設定したり)
  • sysctlで下記の設定をする (ハング判定のタイムアウトを延ばすとか(nosoftlockupしてますが)、NMIウォッチドッグの停止とか、仮想メモリの統計情報のアップデート間隔を延ばすとか、タイマー割り込みのスケジューリングとか)
kernel.hung_task_timeout_secs = 600
kernel.nmi_watchdog = 0
vm.stat_interval = 10
kernel.timer_migration = 1
  • sysfsに対して下記の値を設定する (カーネルのworker threadのスケジューリング)
    • /sys/devices/virtual/workqueue/cpumask に関しては、同じ設定をするようにdracutの pre-udev フックを仕込む (起動初期、カーネルモジュールの初期化等のworker threadのスケジューリング)
/sys/bus/workqueue/devices/writeback/cpumask = <isolcpusで指定した以外のコア>
/sys/devices/virtual/workqueue/cpumask = <isolcpusで指定した以外のコア>
/sys/devices/system/machinecheck/machinecheck*/ignore_ce = 1
  • systemd(/etc/systemd/system.conf)に対して下記を設定する (systemdが起動するサービスのスケジューリング)
CPUAffinity = <isolcpusで指定した以外のコア>
  • /etc/sysconfig/irqbalance に下記を設定する (IRQ処理しないCPUコアの指定)
IRQBALANCE_BANNED_CPUS=<isolcpusで指定したコア>
  • /proc/sys/kernel/sched_domain/cpu*/*/flags のフラグをクリアする (スケジューラドメイン内でのロードバランスの禁止)
  • カーネルモジュール kvm のパラメータを設定する (kvmclock_periodic_sync=0) (kvmclockの同期をやめる)
  • カーネルモジュール kvm_intel のパラメータを設定する (ple_gap=0) (Pause Loop Exitingの制御)
  • サービス ksm, ksmtuned を停止する (Kernel Samepage Mergingを使わない)
  • /proc/irqに対してisolcpusで指定した以外のコアを設定する (IRQを処理するCPUコアの指定)
    • /proc/irq/default_smp_affinity
    • /proc/irq/*/smp_affinity
  • qemu, dpdk/pmd以外の稼働中の全プロセスに対して、isolcpusで指定した以外のコアを設定するよう sched_setaffinity(2) を発行
  • カーネル起動パラメータに下記を追加してinitramfsを再作成 (Scheduling-clock割り込みやRCUコールバックのスケジューリングとかsoft lockupのログ禁止とか)
nohz=on nohz_full=<isolcpusで指定したコア> rcu_nocbs=<isolcpusで指定したコア> tuned.non_isolcpus=<isolcpusで指定した以外のコア> intel_pstate=disable nosoftlockup

参考文献

関連情報が下記のKnowledge Baseに載っていますので、もし興味があればご参照ください。3


  1. 現時点での最新バージョンのRHOSP15(upstreamのSteinに相当)だとこちら

  2. ガイドにしたがってTripleO Heat TemplateのHeat Environment Fileを記述すると、isolcpusの他にDPDKで必要なhugepageやSR-IOVで必要なIOMMUに関するカーネル起動パラメータも設定されますが、詳細は割愛します

  3. 実はこのKnowledge BaseからリンクされているBugzilla#1497182に、本エントリに記載したパラメータを設定するにいたった事情や議論が書かれていてとてもおもしろいのですが、このBugzillaエントリは残念ながら「中の人フラグ」がついたBugzillaアカウントじゃないと見ることができません…もしどうしても読みたい方はぜひレッドハットに入社してください!

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。