SR-IOV enabledな c3/i2 インスタンス使うときのNICドライバのパラメータをどうしたらいいかわからなかったので軽く検証してみた。
NICのドライバパラメータ(InterruptThrottleRate)をチューニングすることで、例えばHAProxyを使ってるような高pps環境でCPUの割り込み負荷を削減できる。
ELBの代わりにHAProxy使ってる噂は結構聞いたりする。
- クックパッドでのVPC移行について
- Cookpad's deployment and auto scaling // Speaker Deck
前提
c3インスタンス
SR-IOV
SR-IOVは、XenやKVMのようなハイパーバイザ型仮想化環境におけるネットワークI/Oを高速化するための技術。
ゲストOSが直接NICにアクセスできるようにすることで以下の様なコストを削減できる。
- NIC・ゲストOSプロセス間でのパケットコピーコスト (NIC -> ホストOS -> ゲストOSカーネル -> ゲストOSユーザプロセス)
- NIC・ゲストOS間の割り込みコスト(NIC -> ホストOS -> ゲストOS)
- ハイバーバイザがNICをソフトウェアエミュレーション(VMM)するコスト
今回はそんなに関係なくてこれを使うためのドライバのパラメータ(InterruptThrottleRate)をどうするのがいいのかという話。
ixgbevf ドライバパラメータ
For the best performance, enable dynamic interrupt throttling for the installed driver as follows:
$ echo "options ixgbevf InterruptThrottleRate=1,1,1,1,1,1,1,1" > /etc/modprobe.d/ixgbevf.conf
Note that this is the typical location for ixgbevf.conf, but your Linux distribution might differ.
Enabling Enhanced Networking on Linux Instances in a VPC - Amazon Elastic Compute Cloud
ixgbevfパラメータのInterruptThrottleRateが1に設定されている。(8個あるのは8個あるNICのポートごとに設定できるため)
ixgbevfのREADMEによると、InterruptThrottleRateは、CPUへの秒間割り込み回数を設定する。
InterruptThrottleRate が小さければ、CPUの割り込み(softirq)負荷が小さくなるが、レイテンシは上がる可能性がある。
逆に、InterruptThrottleRate が大きければ、CPUの割り込み負荷が大きくなるが、レイテンシは下がる可能性がある。
つまり、CPU負荷が高くて困る場合は、InterruptThrottleRate を小さくするような設定にすればよい。
InterruptThrottleRateとして、0,1,3, 100-100000の4種類の値が設定できる。
- 0: 割り込み回数を制限しない
- 1: トラフィックの性質に応じて割り込み回数を調節する
- 3: 1と同じく動的調節するが、割り込み回数は低めに調節されそう
- 100-100000: 指定した値がそのまま最大秒間割り込み回数 (ただしコード読むと Valid Range: 956-488281 とか書いてあってコンフリクトしてるので注意)
"トラフィックの性質"には以下の3つがある。
- "Bulk traffic", for large amounts of packets of normal size
- "Low latency", for small amounts of traffic and/or a significant percentage of small packets
- "Lowest latency", for almost completely small packets or minimal traffic
モード'1'は、"Lowest latency"だと70000まで段階的に増加する。
モード'3'は、"Bulk traffic"だと4000になり、"Low latency" or "Lowest latency"だと20000まで段階的に増加する。
Webサービスで使用するようなHAProxyの用途だと、小さいパケットの個数が多いので、おそらく"Low latency" or "Lowest latency"になる。
AWSの推薦設定であるモード'1'の場合、InterruptThrottleRateが70000まで増加し、割り込み回数がかなり多い設定になる。
Webサービス環境の場合、HPC分野ほどレイテンシがシビアではないはずので、モード'3'にするか、低めの値(4000とか)固定で試してみる。
補足
ドライバのソースコード読んだ感じ、動的モードでは次回のrateの決定に指数移動平均が使われてる。
Dynamic interrupt throttling is only applicable to adapters operating in
MSI or Legacy interrupt mode, using a single receive queue.
今回のような高性能NICだと、動的モードは適切でないと書いているようにもみえる。
トラフィック性質の判定ロジック
timepassed_us = q_vector->itr >> 2;
bytes_perint = bytes / timepassed_us;
switch (itr_setting) {
case lowest_latency:
if (bytes_perint > 10) {
itr_setting = low_latency;
}
break;
case low_latency:
if (bytes_perint > 20) {
itr_setting = bulk_latency;
}
else if (bytes_perint <= 10) {
itr_setting = lowest_latency;
}
break;
case bulk_latency:
if (bytes_perint <= 20) {
itr_setting = low_latency;
}
break;
}
検証
ベンチマーク内容
c1.xlarge 15台から c3.xlarge 1台にTCPコネクションを張った状態で、CPU利用率、スループットおよびレイテンシを計測した。
OSはc1.xlarge、c3.xlarge両方ともCentOS 6.3。
- コネクションを張るためのアプリケーションとしてTCPのベンチマークツールである iperf v2.0.5 を選んだ。
- コネクション数は1ホストあたり10本で、合計150コネクションにした。
- もっとコネクションを張れるけど、iperf のサーバの出来があまりよくなくて、コネクションを増やすと極端にスループットが落ちていく。
- iperf はそもそも複数ホストからのコネクションに想定してなさそう(一応動作はする
- 帯域はあんまりちゃんと測れてない感じがする
- 最初 iperf v3 を試したが、1対1のコネクション要求しか受け付けなかった
- レイテンシは、別ホストから
ping -i 0.2
で50回のICMPパケットを投げて、最小/平均/最大値を計測した。
- ホスト数と1ホストあたりのコネクション数の組み合わせはいくつか試した結果、最もsoftirqの高い組み合わせにした。
- CPU利用率は mpstat -P ALL 1 とかしつつ、softirqのピーク値で比較した。
- ドライバのパラメータは modprobe ixgbevf で有効になるが、有効にしたのちに疎通がなくなるのでインスタンスを再起動しなければならない。
y_uuki@test025 ~]$ iperf --version
iperf version 2.0.5 (08 Jul 2010) pthreads
c3.xlarge ホストに iperf のサーバを立てて、c1.xlarge から iperf クライアントで接続する。
softirq を高めるために、バッファサイズを40バイト(デフォルトは8kB)で固定した。
Webサービス環境に近づけるために、なるべく pps を増やしたいので Nagle アルゴリズムを切ってる。
サーバ
||
iperf -s -N -p 5000
||<
クライアント
||
iperf -c 10.12.226.156 -N -l 40 -p 5000 -P 10
||<
ixgbevf ドライバパラメータ
秒間のNIC - CPU間割り込み数を変化させて計測した。
2つの自動調節モードと最小値で比較した。
dynamic モード (AWS推薦値。モード'1')
options ixgbevf InterruptThrottleRate=1,1,1,1,1,1,1,1
02:46:26 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
02:46:27 AM all 0.30 0.00 5.04 0.00 0.30 11.57 0.00 0.00 82.79
02:46:27 AM 0 1.52 0.00 15.15 0.00 1.52 59.09 0.00 0.00 22.73
02:46:27 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
02:46:27 AM 2 0.00 0.00 8.57 0.00 0.00 0.00 0.00 0.00 91.43
02:46:27 AM 3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
rtt min/avg/max/mdev = 0.080/0.456/1.902/0.360 ms
- CPU0 の softirq が60%程度になってる。
dynamic conservativeモード(モード'3')
自動調節されるが、dynamicモードより割り込み数が低めに設定される。
options ixgbevf InterruptThrottleRate=3,3,3,3,3,3,3,3
02:38:46 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
02:38:47 AM all 0.00 0.00 0.26 0.00 0.26 10.00 0.00 0.00 89.49
02:38:47 AM 0 0.00 0.00 1.02 0.00 1.02 39.80 0.00 0.00 58.16
02:38:47 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
02:38:47 AM 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
02:38:47 AM 3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
rtt min/avg/max/mdev = 0.080/0.475/1.096/0.330 ms
- CPU0 のsoftirq が dynamic モードの60%から40%程度に低下した。
- レイテンシはあまり変わっていない。
1000 (ほぼ最小値)
options ixgbevf InterruptThrottleRate=1000,1000,1000,1000,1000,1000,1000,1000
03:21:13 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
03:21:14 AM all 0.00 0.00 0.78 0.00 0.00 1.83 0.00 0.00 97.39
03:21:14 AM 0 1.09 0.00 2.17 0.00 0.00 7.61 0.00 0.00 89.13
03:21:14 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
03:21:14 AM 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
03:21:14 AM 3 0.00 0.00 1.03 0.00 0.00 0.00 0.00 0.00 98.97
rtt min/avg/max/mdev = 0.084/0.469/1.043/0.301 ms
- CPU0 の softirq が 8%程度となりかなり低下した。
- レイテンシはなぜかあまりかわらない。
帯域
複数ホストからコネクション張ると、ちゃんと帯域を測れてない気がするので、1:1で帯域測ったところ、InterruptThrottleRateにかかわらず、21Mbps程度だった。
バッファサイズ小さくしてるので、帯域の絶対値は低い。
結論
CPU負荷削減したいときは、InterruptThrottleRate を 1000 にすればよい。
ただし、レイテンシの計測方法がかなり雑で ping を投げてるだけなので、安全側に倒して dynamicモード ('3') でいいかもしれない。
追試するなら
- iperf使ってるとコネクション張れなくていらつくので、ちゃんとしたやつを使う
- weighttp x N台 - HAProxy - Nginx でコネクション張りまくる
- 帯域は、https://gist.github.com/joemiller/4069513 みたいな感じでみる (最初からこれで見るべきだった。)
- レイテンシは weighttp のレスポンスタイムでみる
- 帯域(pps) もレイテンシも悪くならなければ最小値でよさそう
資料