AWS VPC内のLinuxでは、拡張ネットワーキング(Enhanced Networking)という機能が使えます。利用条件はあるものの、この機能を有効にするだけでネットワークが速くなるので有用なのですが、何がどれくらい速くなるのか気になったので計測してみました。
この機能自体は2013年末に発表されたものなので、目新しくはないです。ただ、公式の説明やその辺の情報を調べても、イマイチ情報がわかりやすくまとまっていない部分があったので、設定についてもまとめ直してみました。
デフォルトと拡張ネットワーキングの性能比較
この機能のON/OFFによって、変化するのは通信のレイテンシであり、最大Bandwidthが変わるわけではありません。また、インスタンスタイプによってレイテンシの変化量が変わるわけでもありません。そのため、ここで載せるのは1つのインスタンスタイプにおいて、バージョン違いを含めた4種類のネットワークドライバを使った、ping $host -c10 による通信の平均時間となっています。
また、ping の一発目は通信経路の把握のために時間を要するため、それを計測値から削るために二度目の実行結果を採取しています。
各種ネットワークドライバのping平均値(ms)
ネットワークドライバについて
ethtool -i eth0 でみると driver 項目に表示されるのですが、デフォでは vif という値になります。ixgbevf というのは、拡張ネットワーキングを利用するために必要な、カーネルモジュールの名前です。今回、4つも計測したのは、AWS公式で 2.14.2 以上の使用を推奨しているからです。これは、モジュールのソースコードを探しに行くと見つかるREADMEに書いているのですが、このバージョンでパフォーマンスの改善が行われたため、と思われます。それ以外のバージョンのChangeLogは、ほぼディストリビューション対応とBugfixでした。
そういう事情があり、以下4つとしました。
計測値の考察
見ての通り、ixgbevf は vif同士 に比べてレイテンシが40%程度に抑えられており、優秀であることがわかります。また、片方のみが ixgbevf でも片道分の効果があることがわかります。ixgbevf のバージョン違いは、そこまで違いはみられませんが、負荷状況によって差がでるかもしれません。もし拡張ネットワーキングを有効にする意志がある場合、その手間を考えると 2.12.x のままにしておく理由もなく、また、READMEを見る限りメジャーバージョンが変わるわりにリスクに関わる変化は少ないと思われるため、最新バージョンを採用してしまってよさげです。
インスタンスごとの誤差について
ここでは一例しか掲載しませんでしたが、何度か新規に立ち上げ直して計測してみたところ、vif-vif のping平均速度が 0.28~0.40 程度の誤差を確認しました。ブラックボックスなので推測ですが、単に起動した位置が少し近かったり遠かったりして、経由するスイッチの数が変わっただけだと思われます。むしろ、0.5ms 以下に安定しているのは凄いことです。自分のところのネットワークで計測したらわかるのですが、0.1ms台って、L2スイッチ1つ分程度の近さだったりするので、それがクラウド上で設定を入れ込むだけで常時 0.1ms台 になるというのだから垂涎ものであります。
実践での効果予測
レイテンシが40%になるから、ユーザー体感が60%向上する、なんてわけはないんですが、じゃあどのくらいよくなるかというと……例えば、あるアプリケーションのいちリクエストの処理において、MySQLへクエリを100発行するとします。仮に、デフォネットワークと拡張ネットワークの差異を 0.20ms とすると、合計でなんと 20ms もの処理時間短縮ができるというわけです!!
・・・これをみて、フーン(鼻ほじ)全体1~2秒のうちの20msでしょ~、とか感じちゃう人は、仕事に対する姿勢が勿体無いとしかいいようがありません。
設定を入れるだけで 20ms/req 短縮されるということは!
日に 1,000,000 リクエスト受けるとして!!
合計で 20,000,000 ms = 2万秒/日 ものユーザーストレスを削減できるのだ!!!
実際にはもっといろんな箇所で短縮されるし、PVも多いでしょうから、万秒どころか億秒兆秒以上ありますよワンチャン!!
・・・みたいなノリで仕事してます。ハイ。
真面目な方に戻すと、RDS / ElastiCache などは Amazon Linux AMI で運用されているとしたら、指定のインスタンスタイプにすることで多分、同様の効果を得られると思われます。ただ、指定タイプが C3/C4/D2/I2/M4/R3 なので、ちょっとしたKVSのためだけに r3 にするかというと、もったいない感じなので、この辺はあまり意識しないで、ついでに恩恵を受けられているだろう程度に知っておけばよさげです。
拡張ネットワーキングの設定手順
公式の説明
ほぼほぼ全てがこの辺で説明されています。が、様々なディストリビューションの説明があるために、必要な手順は揃っていても、説明が若干わかりづらくなってる気がしたので、CentOS7の場合の設定についてまとめ直します。
ネットワークインターフェース名を永続的にする
EC2の公式CentOS7イメージなどから、該当するインスタンスタイプでHVMインスタンスを起動した後、最初にやるべきことはネットワークインターフェース名を永続的にすることです。公式の説明だけではチンプンカンプンなので、この辺のページを読んでおいた方がよいです。CentOS7 は systemd-219 なので、該当します。手順はこんな感じです。
1 2 3 4 5 6 7 8 9 10 |
# systemd/udev のバージョン確認 # 197以上なら「予測可能な名前の機能」が有効なため、対処が必要 rpm -qa | grep -e '^systemd-[0-9]\+\|^udev-[0-9]\+' # GRUB設定に追加 # 「予測可能な名前の機能」は net.ifnames=0 で無効化できる sed -i '/^GRUB_CMDLINE_LINUX/s/"$/ net.ifnames=0"/' /etc/default/grub # 実際に利用される設定に反映 grub2-mkconfig -o /boot/grub2/grub.cfg |
これが必要な理由は、次手順において拡張ネットワーキングを利用することを宣言して再起動すると、利用するネットワークデバイスが変更され、ネットワークインターフェース名が変わってしまうからです。eth0 だったのが、例えば ens3 とか eno1 だとかいうヤツになり、IPアドレスが無効な状態になってSSHできなくなります。
拡張ネットワーキングの属性を有効化する
作業するインスタンスをいったん停止し、ステータスを stopped にします。そして、どこでもいいので aws コマンドを打てるサーバーに移動します。そして、stopped中のインスタンスに対して、拡張ネットワーキング利用の宣言をします。宣言に必要な role は ec2:ModifyInstanceAttribute です。
1 2 3 4 5 6 7 8 9 |
# 最初は sriovNetSupport の値は空 aws ec2 describe-instance-attribute \ --instance-id i-0123abcd --attribute sriovNetSupport \ --region ap-northeast-1 # sriovNetSupport に simple を設定 aws ec2 modify-instance-attribute \ --instance-id i-0123abcd --sriov-net-support simple \ --region ap-northeast-1 |
この時点では、以下コマンドを打つとまだ有効でないのがわかりますが、
1 2 3 4 5 6 7 8 |
# デフォの 2.12.1 を確認できる modinfo ixgbevf # モジュールはあっても、デバイスが対象ではないとlsmodに出てこない lsmod | grep ixgbevf # driver が vif ethtool -i eth0 |
再起動してから同様の確認をすると、モジュールが有効になっていることを確認できます。
1 2 3 4 5 6 7 |
reboot # モジュールが有効になったことがわかる lsmod | grep ixgbevf # driver が ixgbevf ethtool -i eth0 |
ixgbevfのバージョンアップとDKMS利用
ソースから普通にコンパイルすることも可能ですが、/lib/modules あたりでカーネルバージョンとパスが関連してしまうため、いつかカーネルのバージョンを上げた時に、知らぬうちに無効になってしまう、ということが考えられます。そのため、DKMSを利用することで、カーネルバージョンアップ+再起動した時点で、自動的に更新して追随してくれるようになります。DKMSを使わないというのもアリっちゃアリですが、このご時世、カーネルに致命傷が見つかることが稀によくあるので、基本的には必須、よっぽどの確信やら自信やらがあるならば、といったところでしょう。
手順はこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# せっかくなので最新に yum update reboot # dkmsのインストール yum -y install epel-release yum -y install dkms # ixgbevfソースのダウンロード(dkmsの都合で /usr/src である必要アリ) cd /usr/src wget -O ixgbevf-3.1.2.tar.gz "http://downloads.sourceforge.net/project/e1000/ixgbevf%20stable/3.1.2/ixgbevf-3.1.2.tar.gz" tar xzf ixgbevf-3.1.2.tar.gz cd ixgbevf-3.1.2 # dkms用の設定 cat <<'EOT' > dkms.conf PACKAGE_NAME="ixgbevf" PACKAGE_VERSION="3.1.2" CLEAN="cd src/; make clean" MAKE="cd src/; make BUILD_KERNEL=${kernelver}" BUILT_MODULE_LOCATION[0]="src/" BUILT_MODULE_NAME[0]="ixgbevf" DEST_MODULE_LOCATION[0]="/updates" DEST_MODULE_NAME[0]="ixgbevf" AUTOINSTALL="yes" EOT # モジュールとネットワークの確認 modinfo ixgbevf ethtool -i eth0 # インストール dkms add -m ixgbevf -v 3.1.2 dkms build -m ixgbevf -v 3.1.2 dkms install -m ixgbevf -v 3.1.2 # モジュールが更新されたのを確認 modinfo ixgbevf # 再起動してネットワークのdriverがixgbevf 3.1.2 になったのを確認 reboot ethtool -i eth0 |
運用について
イメージを保存する
ここからは、レシピを当てたり、手動設定したりがあるでしょうが、この時点でいったんAMIとしてイメージを保存しておきましょう。拡張ネットワーキングの属性は、イメージの中に保存されるので、次にそのイメージから起動すれば、ONの状態で始めることができます。パッケージにするか否か
ixgbevf をRPMパッケージにすることは可能っちゃ可能なのですが、DKMSを必須とした場合、結局パッケージインストール時にDKMSでインストールを走らせるという、わけのわからないモノになってしまいます。また、その動作確認には再起動、もしくはネットワークインターフェースのDOWN/UPが必要なので、レシピ適応後の自動テストにおいて標準的なやり方を押し通すことは難しくなってしまいます。
そういった事情を鑑みて、こういったイメージやOSの根幹に関わる部分はパッケージ化せず、レシピのデフォルトイメージとして扱う前の手動設定として運用することがベターであると思われます。
自動テストするか否か
設定を手動にしてレシピと切り離してしまうと、もしかしたら運用ミスで設定の入れ忘れが発生するかもしれません。そのため、設定は作業手順に沿って行うけど、自動テストのレシピは書く、というくらいがよさそうです。例えば、特定のインスタンスタイプの場合、ethtool -i eth0 の driver が ixgbevf であることを確認する、といったような感じで。
いろいろ調べていると、/etc/modprobe.d/ixgbevf.conf が必須であるような情報や(調整値はあります)、net.ifnames=0 をなんとなく設定している雰囲気があったりで、情報の錯綜が感じられたため、今回まとめ直してみました。
根幹部分のためサービスイン時に適用していることが望ましいですが、デフォ運用のサービスを拡張ネットワーキングに変更することができれば、レスポンス速度が向上したり、CPU I/O wait が減少するような、心が洗われるグラフ変化に出会えるかもしれません。