調査
他のワークロードでも再現するのか?
以前の検証では PostgreSQL のデータベースとベンチマークツールを異なる VP で動作させたときに性能劣化していました。
PostgreSQL のベンチマークはデータベースとベンチマークツールの間で通信があります。ここにポイントがあるのではないかと仮説を立てました。
そこで、プロセス間の通信があるワークロードとして、Apache HTTP Server と Apache Bench を同一もしくは異なる VP で動作させたときにパフォーマンスの差異が出るかを確認しました。
検証環境 1 を利用しました。
-- 同一 VP で動作
# taskset -c 0 httpd -k start
# taskset -c 0 ab -c 1 -n 1000000 http://localhost/
-- 異なる VP で動作
# taskset -c 0 httpd -k start
# taskset -c 1 ab -c 1 -n 1000000 http://localhost/
動作 VP |
Requests per second |
同一 |
3575.65 |
異なる |
2720.01 |
Apache のベンチマークでも同一 VP で動作させた方が高い性能となりました。この結果より、プロセス間通信のあるワークロードを異なる VP で動作させたときに性能劣化する可能性が強まりました。
ルートスケジューラ固有の問題なのか?
マニュアルには下記の記載があります。
サーバー システムでのルート スケジューラの使用
現時点では、サーバー上の Hyper-V でのルート スケジューラの使用は推奨されていません。これは、多くのサーバー仮想化のデプロイで一般的なさまざまなワークロードに対応するためのパフォーマンス特性がまだ完全に特徴付けられたり調整されていないためです。
Hyper-V Hypervisor のさまざまな種類のスケジューラを理解して使用する | Microsoft Learn
以前の検証ではこれを根拠として、ルートスケジューラの調整不足の可能性があるとしました。
以前の検証以降の調査でこのような記述も見つけました。
ルートスケジューラが有効になっている場合のコンテキストスイッチは、他のハイパーバイザースケジューラの実装に比べてコストがかかります。
引用元:インサイドWindows 第7版 下 (マイクロソフト公式解説書)
以前の検証でも PostgreSQL のベンチマークを 異なる VP で動作させたとき、コンテキストスイッチが増加していました。これがルートスケジューラでの性能に影響を与えた可能性があります。
そこで、ハイパーバイザースケジューラの違いによって、性能にどのような影響があるかを検証しました。
検証環境 2 を利用し、Apache, PostgreSQL のベンチマークで比較します。ベンチマークで比較した値は Apache が Requests per second、PostgreSQL が TPS です。
-- 同一 VP で動作
# taskset -c 0 httpd -k start
# taskset -c 0 ab -c 1 -n 1000000 http://localhost/
-- 異なる VP で動作
# taskset -c 0 httpd -k start
# taskset -c 1 ab -c 1 -n 1000000 http://localhost/
-- select1.pgbench ファイルの中身
SELECT 1;
-- 同一 VP で動作
$ taskset -c 0 pg_ctl start -D /usr/local/pgsql/data/
$ taskset -c 0 pgbench -f /home/postgres/select1.pgbench -c 1 -j 1 -n -T 180 testdb
-- 異なる VP で動作
$ taskset -c 0 pg_ctl start -D /usr/local/pgsql/data/
$ taskset -c 1 pgbench -f /home/postgres/select1.pgbench -c 1 -j 1 -n -T 180 testdb
≪Apache≫
スケジューラ |
同一 VP |
異なる VP |
従来スケジューラ |
3192.26 |
3051.46 |
ルートスケジューラ |
2947.49 |
1854.98 |
≪PostgreSQL≫
スケジューラ |
同一 VP |
異なる VP |
従来スケジューラ |
30746.633136 |
19519.17893 |
ルートスケジューラ |
29655.280981 |
5663.156913 |
従来スケジューラにおいても異なる VP で動作させたときにパフォーマンス低下がみられました。ただし、Apache ではその低下幅が小さかったです。
この結果より、異なる VP でのパフォーマンス低下はルートスケジューラ固有の問題と言えないことが分かりました。
パフォーマンス低下の原因は何か?
検証環境 2 での Apache, PostgreSQL のベンチマークと LP の測定結果を掲載します。
LP はパフォーマンスモニターの "Hyper-V Hypervisor Logical Processor" カテゴリより、以下のカウンタを測定しました。
測定項目 |
カウンタ名 |
ゲスト実行時間 [%] |
% Guest Run Time |
ハイパーバイザー実行時間 [%] |
% Hypervisor Run Time |
コンテキストスイッチ [回数/秒] |
Context Switches/sec |
≪Apache, 従来スケジューラ≫
測定項目 |
同一 VP |
異なる VP |
リクエスト [回数/秒] |
3192.26 |
3051.46 |
ゲスト実行時間 [%] |
28.363 |
33.882 |
ハイパーバイザー実行時間 [%] |
0.900 |
3.174 |
コンテキストスイッチ [回数/秒] |
2341.129 |
26765.782 |
≪Apache, ルートスケジューラ≫
測定項目 |
同一 VP |
異なる VP |
リクエスト [回数/秒] |
2947.49 |
1854.98 |
ゲスト実行時間 [%] |
31.232 |
30.055 |
ハイパーバイザー実行時間 [%] |
1.913 |
13.638 |
コンテキストスイッチ [回数/秒] |
6087.158 |
58926.69 |
≪PostgreSQL, 従来スケジューラ≫
測定項目 |
同一 VP |
異なる VP |
TPS |
30746.633136 |
19519.17893 |
ゲスト実行時間 [%] |
27.951 |
28.137 |
ハイパーバイザー実行時間 [%] |
0.569 |
9.246 |
コンテキストスイッチ [回数/秒] |
1534.912 |
80417.244 |
≪PostgreSQL, ルートスケジューラ≫
測定項目 |
同一 VP |
異なる VP |
TPS |
29655.280981 |
5663.156913 |
ゲスト実行時間 [%] |
28.677 |
22.924 |
ハイパーバイザー実行時間 [%] |
1.041 |
20.864 |
コンテキストスイッチ [回数/秒] |
3422.084 |
87479.341 |
これらの結果より、以下の考察を導きました。
- 同一 VP / 異なる VP 間での違い
- 異なる VP で動作するとパフォーマンスが低下する
- ゲスト実行時間には差異がある場合もない場合もある
- 異なる VP で動作するとハイパーバイザー実行時間が大きくなる
- 異なる VP で動作するとコンテキストスイッチ頻度が大きくなる
- 従来スケジューラ / ルートスケジューラ間での違い
- 同一 VP で比較するとルートスケジューラのほうが若干パフォーマンス低下する
- 異なる VP で比較するとルートスケジューラのほうが大幅にパフォーマンス低下する
- ルートスケジューラでコンテキストスイッチ頻度が大きくなる
これらの結果より、ハイパーバイザー実行時間とコンテキストスイッチ頻度が大きくなると、パフォーマンスは低下する傾向にあるようです。
「インサイド Windows 第7版 下」のルートスケジューラの節でこんな説明がありました。
ゲストVPが現在の物理プロセッサで最後に実行された場合、スケジューラはゲストVPスレッドをすぐにディスパッチできます。それ以外の場合、スケジューラは、ゲストPVが最後に実行されたプロセッサにフラッシュ要求を送信し、リモートプロセッサがVPコンテキストをフラッシュするのを待つ必要があります。
引用元:インサイドWindows 第7版 下 (マイクロソフト公式解説書)
※「ゲストPV」は「ゲストVP」の誤字と思われます。
これがコンテキストスイッチの事であれば、フラッシュ処理によるオーバーヘッドでパフォーマンス低下を説明できそうです。
以前の記事で VP と LP の対応は動的に決定することを確認しました。
Hyper-V で論理プロセッサの利用状況は環境やワークロードに左右される - ぱと隊長日誌
パフォーマンスを高めるためには VP と LP の対応をなるべく固定化することが理想のように思えます。これをしないのは仮想環境が CPU のオーバーコミットを前提とし、VP と LP の対応を動的にすることで柔軟性を高めたのでは…?と推測しています。ただ、こちらに関して裏付ける資料を見つけることはできませんでした。
CPU指定なしでスレッド数を変化させるとどうなるか?
ここまでは taskset コマンドで CPU(仮想マシンの VP)を指定してきました。ここでは通常通り、VP を指定せずに測定します。
以下の条件を組み合わせて、検証環境 2 で測定を行いました。
# httpd -k start
-- 1クライアント
# ab -c 1 -n 1000000 http://localhost/
-- 4クライアント
# ab -c 4 -n 1000000 http://localhost/
-- select1.pgbench ファイルの中身
SELECT 1;
$ pg_ctl start -D /usr/local/pgsql/data/
-- 1クライアント
$ pgbench -f /home/postgres/select1.pgbench -c 1 -j 1 -n -T 180 testdb
-- 4クライアント
$ pgbench -f /home/postgres/select1.pgbench -c 4 -j 4 -n -T 180 testdb


ベンチマークの傾向だけで見ればルートスケジューラと従来スケジューラは似ています。
スケジューラの違いをベンチマークの成績で比較します。Apache はルートスケジューラより従来スケジューラの成績が良いです。PostgreSQL はスレッド数が少ないときに、ルートスケジューラより従来スケジューラの成績が良いです。
スレッド数の観点でベンチマークの成績を比較します。Apache はスレッド数に応じて徐々に向上しています。PostgreSQL は 4 スレッドを境に大きく変化しました。


スケジューラの違いを Apache の例で比較します。従来スケジューラよりルートスケジューラでコンテキストスイッチ頻度が多いです。ハイパーバイザー実行時間はルートスケジューラのほうが2倍超となっています。


スケジューラの違いを PostgreSQL の例で比較します。スケジューラが異なってもコンテキストスイッチ頻度はほぼ同じです。ハイパーバイザー実行時間はルートスケジューラのほうが2倍程度となっています。
このように、スケジューラとベンチマークによって結果は大きく異なりますが、共通点を見出せました。ハイパーバイザー実行時間とコンテキストスイッチ頻度が減ればベンチマークの成績は良くなること。そして、ハイパーバイザー実行時間とコンテキストスイッチ頻度の間には相関がありそうだということです。