Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

AWSネットワークスロットリング徹底トラブルシューティングガイド

By VilmarMar 21, 202422 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

· AWSネットワークの制限を理解しておく重要性

· どのような制限があるのか

· トラフィックはどのようにシェーピングされるのか

· EC2の配置とリソース共有

· 帯域幅スロットリングのトラブルシューティング

インターネット向け送信帯域幅

フロー単位の制限

マイクロバースト

CloudWatchネットワークメトリクスの読み方

· コネクショントラッキングのスロットリング

· ローカルプロキシサービスへのスロットリング

· パケットスロットリングのトラブルシューティング

· 参考資料

AWSネットワークの制限を理解しておく重要性

数多くのAWSサービスのなかでも、EC2インスタンスとEC2ネットワークは、その上に他のAWSサービスの大半が積み上げられる土台であり、現代のデジタルインフラを支えるさまざまなアプリケーションやサービスを下支えしています。ただし、これらインスタンスのパフォーマンスを正しく見極めるには、AWSネットワークの内部、とりわけネットワークスロットリングの仕組みを理解しておく必要があります。ネットワークスロットリングはさまざまな形で表面化し、EC2インスタンスのパフォーマンスとスケーラビリティ、ひいてはAWSエコシステム上の多くのサービスに直接影響します。

AWSは主に2つの仕組みでネットワークスロットリングを実現しています。帯域幅の制限と、PPS(packets per second)の制限です。帯域幅スロットリングは一定時間あたりに転送できるデータ量に作用し、PPSスロットリングは送受信できるネットワークパケット数を制限します。これらはAWSインフラ全体の健全性と効率を維持するために緻密に設計されたものですが、アプリケーションのパフォーマンス最適化やリソース利用効率の改善を進める上では大きな壁になり得ます。

さらに厄介なのは、AWSネットワークスロットリングの一部について公式ドキュメントが十分に整っていない点です。AWSがいつ・どのようにスロットリングを適用するかという具体的な情報は見つけにくく、開発者はフォーラム、ユーザー事例、試行錯誤による検証といった迷路をかき分けながら、自分のサービスへの影響を理解し、対策を講じざるを得ないのが実情です。明確で参照しやすいドキュメントが不足していることが、AWS上でのネットワークパフォーマンス管理と最適化を一段と複雑にしています。

本記事では、断片的に散らばっているAWSネットワークスロットリングの情報をひとつに整理し、AWSがEC2ネットワークに対してどのようにスロットリングを実装しているのかを、わかりやすく体系的に解説します。

どのような制限があるのか

Nitroベースの新しい世代のEC2インスタンスでは、ネットワークスロットリングによってシェーピングされたパケットを示すカウンタとして、AWSがいくつかのメトリクスを公開しています。これらは公式ドキュメントに記載されています [1]。

  • bw_in_allowance_exceeded: インバウンドの集約帯域幅がインスタンスタイプ/サイズの上限を超えたために、キューイングまたはドロップされたパケット数。
  • bw_out_allowance_exceeded: アウトバウンドの集約帯域幅がインスタンスタイプ/サイズの上限を超えたために、キューイングまたはドロップされたパケット数。
  • conntrack_allowance_exceeded: コネクショントラッキングがインスタンスの上限を超え、新規接続を確立できずにドロップされたパケット数。インスタンスとの間のトラフィックでパケットロスが発生する場合があります。
  • conntrack_allowance_available: インスタンスタイプのConnections Trackedアロワンスに到達するまでに、当該インスタンスがあとどれだけの接続を確立できるかを示す数。
  • linklocal_allowance_exceeded: ローカルプロキシサービス向けトラフィックのPPSがネットワークインターフェースの上限を超え、ドロップされたパケット数。DNSサービス、Instance Metadata Service、Amazon Time Sync Serviceへのトラフィックに影響します。
  • pps_allowance_exceeded: 双方向のPPSがインスタンスの上限を超えたために、キューイングまたはドロップされたパケット数。

これらのメトリクスはENAドライバ経由でNitroインスタンスにのみ公開されますが、制限自体はNitroインスタンス固有のものではありません。Xenで仮想化された非Nitroインスタンスにも同様のネットワーク制限が存在します(多くの場合、Nitroインスタンスよりも厳しい値です)。とはいえ、AWSがこの種のカスタムメトリクスを自社のENAドライバ上でしか公開できないのは当然のことと言えます。

これらのカウンタは、インスタンス側から次のコマンドで確認できます。

[root@ip-172-31-82-248 ~]# ethtool -S eth0 | grep allowance
     bw_in_allowance_exceeded: 0
     bw_out_allowance_exceeded: 0
     pps_allowance_exceeded: 0
     conntrack_allowance_exceeded: 0
     linklocal_allowance_exceeded: 0
     conntrack_allowance_available: 136812

トラフィックはどのようにシェーピングされるのか

制限に達したときにトラフィックがどう扱われるかについて、AWSドキュメントの表現は重要です。そこにはパケットがキューイングまたはドロップされると書かれていますが、キューイングがどの程度の時間続くのかは明示されていません。

キューイングなのかドロップなのかをスロットリングの形態として識別する方法はありません。ただし検証してみると、ネットワークトラフィックが制限をわずかに超えた程度であれば、シェーピングはキューイングのみに留まり、その時間も数ミリ秒以内であることが多く、影響はほとんどないことがわかります。

パケットのドロップは制限を大きく超えたときにのみ発生する傾向があり、その場合でもドロップ量がわずかであれば、TCPベースのアプリケーションは失われたパケットの再送だけで容易に回復できることがほとんどです。

また、ネットワークスロットリングに関するENAメトリクスは前回のENAリセット以降のパケット累計値であり、シェーピングされたパケット数の累積を示しています。

これらのカウンタを確認したときに非ゼロの値があったとしても、単に古い値が残っているだけというケースもあるため、必ずしも問題があるとは限りません。状況をより把握しやすくするには、CloudWatch Agent [2] を使ってこれらをCloudWatchメトリクスとしてエクスポートする方法もあります。これにより推移を時系列で可視化でき、カウンタが今も増え続けているのか、また毎秒どの程度のパケットが追加されているのかを把握できます。

EC2の配置とリソース共有

EC2インスタンスは仮想マシンであり、仮想マシンとは本質的に物理ハードウェア上にもう一段重ねた抽象化レイヤーで、複数のテナントで共有されるものです。

大まかな目安として、同じファミリーの中ではEC2インスタンスのサイズが大きくなるほど、他のテナントとハードウェアを共有する度合いが小さくなり、最終的にはそのハードウェアを単独で占有する仮想マシン、もしくはメタルインスタンスそのものになります。

たとえばc5ファミリーの最大サイズであるc5.24xlargeは、配下のホストをほぼ独占している可能性が高く、他テナントとネットワーク制限を分け合うことがありません。つまり、ハードウェア全体の性能を一手に使えるため、より小さいサイズのインスタンスよりもはるかに高いネットワーク制限を持つことになります。

一方、同ファミリー最小のc5.largeは、配下のホストを複数テナントと共有している可能性が高く、ハードウェア性能の1/x(xはそのハードウェアに収容される最大テナント数)しか利用できないことになります。

これらの配置がバックエンドでどう動いているのかは公開されていませんが、一般則として、インスタンスサイズが大きいほどネットワーク制限も高くなると考えてよいでしょう。

さらに、インスタンスから出ていくトラフィックを考える場合、ハイパーバイザーの外側のネットワークスタック、つまり上位のスイッチやルーター由来の制約も加わってくる可能性があります。

AWSのEC2向けネットワークスタックの中身も公開されていませんが、一般的なデータセンターのネットワークスタックは次のような構成になります。

AWSではプレースメント戦略 [3] を定義することができ、これによってインスタンス同士の物理的な距離を制御できます。これはレイテンシだけでなく、フロー単位の帯域幅制限にも影響します。

クラスタープレースメントグループを作成すると、インスタンスは可能な限り近接配置されます。たとえば同一の配下ホスト内、同一のToRスイッチ配下、同一のアグリゲートスイッチ配下、といった具合です。この戦略により、当該プレースメントグループ内のインスタンス間で最低のレイテンシと、フロー単位での最大帯域幅制限が実現できます。

プレースメント戦略を指定しない場合、AWSはキャパシティに応じてインスタンスをランダムに配置します。そのため、運によっては同じToRやアグリゲートスイッチ配下に収まることもあれば、そうならないこともあります。

EC2インスタンスを停止して起動し直すたびに、AWSのインフラ上の異なる場所へ再配置されます [4]。つまり、他のインスタンスの近く(プレースメント内)に配置されることもあれば、遠く(プレースメント外)に配置されることもあり、これがレイテンシとフロー単位の最大スループットに影響するわけです。

この現象が原因で、低レイテンシかつフロー単位で高いスループットを必要とするアプリケーションをホストしていた2台のEC2インスタンスが、たまたまプレースメント内に配置されていたものの、停止/再起動を機にプレースメント外へ移動し、フロー単位の最大スループット低下とレイテンシ増加によって、ある日突然ネットワーク問題に直面した、というケースを実際に何度も見てきました。

こうした事情から、アプリケーションの特性を踏まえ、AWSインフラに対してあらかじめプレースメント戦略を定義しておくことが重要です。

とはいえ、クラスタープレースメントが万能というわけではありません。インスタンスを物理的に近接させればさせるほど、ハードウェア障害が起きたときにすべてが同時に巻き込まれるリスクも高まります。すべてのインスタンスが同じ配下ホスト上にあれば、そのホストに障害が発生した瞬間に全インスタンスが一斉にダウンします。

その代替として、AWSはスプレッドプレースメントグループ戦略も提供しています。これはまったく逆に、インスタンスを物理的に可能な限り離して配置するものです。

帯域幅スロットリングのトラブルシューティング

帯域幅スロットリングはAWSが課すネットワーク制限の中では最も分かりやすいものですが、それでもいくつか厄介なポイントがあります。

まず必要なのは、各インスタンスタイプの実際の帯域幅性能を把握することです。AWSはEC2インスタンスに対し、ベースライン帯域幅バースト上限という2種類の制限を設けています。

ドキュメントで「Up to」と表記されている数値はバースト上限です。その最大帯域幅まで到達できますが、利用できるのはバーストクレジットを使い切るまでの限られた時間だけです。インスタンスサイズが大きいほど配下ハードウェアの共有は少なく、より長くバーストできます。

バーストクレジットを使い切ると、制限はベースライン(バースト上限よりはるかに小さな値)まで下がり、ネットワークスロットリングが発生し始めます。

「25 Gigabit」のように「Up to」を伴わない数値で示されているインスタンスサイズの場合は、それがベースラインの値であり、バースト上限はありません。

一部のインスタンスタイプについては、AWSはドキュメント [5] でベースライン帯域幅とバースト帯域幅の両方を公開していますが、対象は限られたファミリーのみです。

バースト可能なインスタンスでどれくらいの時間バーストできるかは、AWSからは一切公表されていません。ただ、自分でテストすればそれほど難しくなく見極められます。

たとえば自分のAWSアカウントでc5.largeとc5.24xlargeを起動し、iperf3を使うことで、c5.largeインスタンスの制限を確認できます。

[root@ip-172-31-82-248 ~]# iperf3 -c 172.31.23.48 -i 60 -t 480 -P 5
Connecting to host 172.31.23.48, port 5201
[  5] local 172.31.82.248 port 42202 connected to 172.31.23.48 port 5201
[  7] local 172.31.82.248 port 42204 connected to 172.31.23.48 port 5201
[  9] local 172.31.82.248 port 42208 connected to 172.31.23.48 port 5201
[ 11] local 172.31.82.248 port 42212 connected to 172.31.23.48 port 5201
[ 13] local 172.31.82.248 port 42218 connected to 172.31.23.48 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-60.05  sec  11.4 GBytes  1.64 Gbits/sec  19684    376 KBytes
[  7]   0.00-60.05  sec  11.2 GBytes  1.60 Gbits/sec  17814    341 KBytes
[  9]   0.00-60.05  sec  11.5 GBytes  1.65 Gbits/sec  18713    428 KBytes
[ 11]   0.00-60.05  sec  16.8 GBytes  2.40 Gbits/sec  24552    507 KBytes
[ 13]   0.00-60.05  sec  17.0 GBytes  2.44 Gbits/sec  22710    524 KBytes
[SUM]   0.00-60.05  sec  68.0 GBytes  9.72 Gbits/sec  103473
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5]  60.05-120.05 sec  11.4 GBytes  1.64 Gbits/sec  19955    341 KBytes
[  7]  60.05-120.05 sec  11.3 GBytes  1.62 Gbits/sec  18304    428 KBytes
[  9]  60.05-120.05 sec  11.4 GBytes  1.64 Gbits/sec  18976    428 KBytes
[ 11]  60.05-120.05 sec  16.8 GBytes  2.41 Gbits/sec  25220    498 KBytes
[ 13]  60.05-120.05 sec  16.9 GBytes  2.42 Gbits/sec  23265    481 KBytes
[SUM]  60.05-120.05 sec  67.9 GBytes  9.72 Gbits/sec  105720
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 120.05-180.05 sec  11.5 GBytes  1.65 Gbits/sec  19194    454 KBytes
[  7] 120.05-180.05 sec  11.1 GBytes  1.59 Gbits/sec  18328    454 KBytes
[  9] 120.05-180.05 sec  11.5 GBytes  1.64 Gbits/sec  19259    358 KBytes
[ 11] 120.05-180.05 sec  16.7 GBytes  2.39 Gbits/sec  24946    542 KBytes
[ 13] 120.05-180.05 sec  17.1 GBytes  2.45 Gbits/sec  23032    323 KBytes
[SUM] 120.05-180.05 sec  67.9 GBytes  9.72 Gbits/sec  104759
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 180.05-240.05 sec  11.5 GBytes  1.65 Gbits/sec  20069    446 KBytes
[  7] 180.05-240.05 sec  11.2 GBytes  1.60 Gbits/sec  17967    463 KBytes
[  9] 180.05-240.05 sec  11.4 GBytes  1.64 Gbits/sec  18942    323 KBytes
[ 11] 180.05-240.05 sec  16.7 GBytes  2.39 Gbits/sec  24645    498 KBytes
[ 13] 180.05-240.05 sec  17.0 GBytes  2.44 Gbits/sec  22380    507 KBytes
[SUM] 180.05-240.05 sec  67.9 GBytes  9.72 Gbits/sec  104003
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 240.05-300.05 sec  7.89 GBytes  1.13 Gbits/sec  13304    323 KBytes
[  7] 240.05-300.05 sec  7.85 GBytes  1.12 Gbits/sec  12274    498 KBytes
[  9] 240.05-300.05 sec  7.89 GBytes  1.13 Gbits/sec  12763    350 KBytes
[ 11] 240.05-300.05 sec  11.5 GBytes  1.65 Gbits/sec  16480    454 KBytes
[ 13] 240.05-300.05 sec  11.9 GBytes  1.71 Gbits/sec  15472    647 KBytes
[SUM] 240.05-300.05 sec  47.1 GBytes  6.74 Gbits/sec  70293
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 300.05-360.05 sec   878 MBytes   123 Mbits/sec    0    323 KBytes
[  7] 300.05-360.05 sec   879 MBytes   123 Mbits/sec    0    498 KBytes
[  9] 300.05-360.05 sec   878 MBytes   123 Mbits/sec    0    350 KBytes
[ 11] 300.05-360.05 sec  1.31 GBytes   188 Mbits/sec    0    454 KBytes
[ 13] 300.05-360.05 sec  1.31 GBytes   188 Mbits/sec    0    647 KBytes
[SUM] 300.05-360.05 sec  5.20 GBytes   745 Mbits/sec    0
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 360.05-420.05 sec   880 MBytes   123 Mbits/sec    0    323 KBytes
[  7] 360.05-420.05 sec   880 MBytes   123 Mbits/sec    0    498 KBytes
[  9] 360.05-420.05 sec   881 MBytes   123 Mbits/sec    0    350 KBytes
[ 11] 360.05-420.05 sec  1.31 GBytes   188 Mbits/sec    0    454 KBytes
[ 13] 360.05-420.05 sec  1.31 GBytes   188 Mbits/sec    0    647 KBytes
[SUM] 360.05-420.05 sec  5.20 GBytes   745 Mbits/sec    0
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5] 420.05-480.05 sec   782 MBytes   109 Mbits/sec    0    323 KBytes
[  7] 420.05-480.05 sec   933 MBytes   130 Mbits/sec    0    498 KBytes
[  9] 420.05-480.05 sec   932 MBytes   130 Mbits/sec    0    350 KBytes
[ 11] 420.05-480.05 sec  1.31 GBytes   187 Mbits/sec    0    454 KBytes
[ 13] 420.05-480.05 sec  1.31 GBytes   187 Mbits/sec    0    647 KBytes
[SUM] 420.05-480.05 sec  5.20 GBytes   745 Mbits/sec    0
- - - - - - - - - - - - - - - - - - - - - - - - -

上の例は、c5.largeインスタンスからより大きなc5.24xlargeに向けてiperf3を実行したものです(c5.largeの制限が先に来ることを確実にし、それを律速要因として測定するため)。60秒間隔(-i 60)で、合計8分間(-t 480)、5本の並列ストリーム(-P 5)で計測しています。

結果を見ると、最初の5分間はビットレートがおよそ10Gbpsで、これはAWSがc5.largeの値として「Up to」で示している水準と一致しています。ところが5分を過ぎるとビットレートは750Mbpsまで一気に下がります。

これによって、c5.largeインスタンスについて、ドキュメントには明示されていない次の2つの値が判明します。

  • ベースライン帯域幅:750Mbps
  • バースト上限:最大10Gbpsを5分間まで

つまり、c5.largeのベースライン帯域幅は750Mbpsで、最大10Gbpsまでのバーストは5分間のみ可能ということがわかります。

また、ネットワークスロットリングが効き始めると、アウトバウンドの帯域シェーピングを示すENAカウンタも増え始めることが確認できます。

[root@ip-172-31-82-248 ~]# ethtool -S ens5|grep exceeded
     bw_in_allowance_exceeded: 0
     bw_out_allowance_exceeded: 42427304
     pps_allowance_exceeded: 0
     conntrack_allowance_exceeded: 0
     linklocal_allowance_exceeded: 0
[root@ip-172-31-82-248 ~]#

インターネット向け送信帯域幅

EC2インスタンスは、トラフィックの送信元と送信先がいずれもAWS内かつ同一リージョンにある場合に、最大の帯域幅性能を発揮できます。しかし、トラフィックの送信元または送信先がリージョン外、すなわち別のAWSリージョンや、インターネットへルーティングされる場合には事情が変わります。

こうしたケースでは、利用しているインスタンスが大型で32 vCPU以上ある場合、他リージョンやインターネット向けの帯域幅制限はネットワーク帯域幅の50%になります [6]。

32 vCPU未満のインスタンスサイズの場合は、上限は最大5Gbpsで固定されます [6]。

フロー単位の制限

もう一つ見落としがちな帯域幅制限として、AWSはフロー単位で帯域幅を絞っています。フロー単位のスループット最大値は、インスタンスファミリーやサイズに関係なく5Gbpsで、これはハードリミットです [6]。

この制限を超えられる方法は2つしかありません。1つは、送信元と送信先の両インスタンスが同じEC2プレースメント内にあるケースです。これは、両インスタンスを同一のクラスタープレースメントグループに配置するか、本記事のEC2配置のセクションで述べたとおり、運良く同じアグリゲートスイッチ配下に収まることで実現します。

送信元と送信先の両インスタンスが同じEC2プレースメント内にある場合、フロー単位の最大帯域幅は10Gbpsとなります [6]。

もう1つの方法は、対応インスタンスかつ同一サブネット内でENA Expressを利用することで、この場合インスタンス間のフローあたり上限は25 Gbpsになります [6]。

そのほか、可能な限りマルチフロー構成のトラフィックを使うことで、最大の帯域幅性能を引き出せます。これは後述するPPS制限への影響にも有効です。

ここで重要なのは、フロー制限によるスロットリングは、ENAのスロットリングメトリクスのいずれにも現れないという点です。

これもiperf3で簡単に確認できます。プレースメント外にあるc5.large(本来であれば10Gbps到達可能)からc5.24xlargeに向けて単一ストリームを実行すると、フローあたりの最大スループットが5Gbpsで頭打ちになっているのがわかります。

[root@ip-172-31-92-221 ~]# iperf3 -c 172.31.23.48 -t 60 -P 1
Connecting to host 172.31.23.48, port 5201
[  5] local 172.31.92.221 port 42472 connected to 172.31.23.48 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   594 MBytes  4.98 Gbits/sec    0   1.43 MBytes
[  5]   1.00-2.00   sec   592 MBytes  4.97 Gbits/sec    0   1.52 MBytes
[  5]   2.00-3.00   sec   592 MBytes  4.97 Gbits/sec    0   1.52 MBytes

しかし、ENAのスロットリングメトリクスではどのカウンタも増加していません。

[root@ip-172-31-92-221 ~]# ethtool -S ens5|grep exceeded
     bw_in_allowance_exceeded: 0
     bw_out_allowance_exceeded: 0
     pps_allowance_exceeded: 0
     conntrack_allowance_exceeded: 0
     linklocal_allowance_exceeded: 0

これは特に重要なポイントで、フロー制限によるネットワークスロットリングは「サイレント」に発生し、起きていることに気付くのが極めて難しい、ということを意味します。

マイクロバースト

帯域幅スロットリングを考えるうえでもう一つ留意すべきなのが、マイクロバーストです。これは帯域幅の上限にごく短時間だけ達する現象で、なかなか発見しづらいのが特徴です。

典型的なシナリオは、ENAのスロットリングメトリクスは少しずつ増加しているのに、CloudWatchのネットワークトラフィックを見ても帯域幅の上限に達しているようには見えない、というケースです。

AWSのスロットリングは非常に短い間隔で発生します。具体的にどの程度短いかは公開されていませんが、私自身、サブ秒単位の計測でなければマイクロバーストを捉えられなかった事例を経験しています。

一方、CloudWatchはデフォルトでは5分間隔のデータポイントで、詳細モニタリングを有効にしてようやく1分間隔まで短縮できる程度です。

バーストがあまりに短いと、CloudWatchの5分間隔の中で平均化されてしまい、見えなくなることもあります。

最も簡単な対処は、トラフィックのピークが見えなくてもAWSのENAカウンタを正と信じることです。CloudWatch Agentを使えば1秒粒度のデータポイントも取得でき、ほとんどの帯域幅ピークを捉えられるようになります。

さらに踏み込むなら、ENAのRX/TXキューでのトラフィック量と、報告されているシェーピング量を突き合わせる方法もあります。

もっとも、マイクロバーストの大半のシナリオでは、シェーピング量はそもそも気にするほど大きくなく、シェーピングの大半はキューイングに留まり、TCPベースのアプリケーションであればわずかなロスから容易に回復できます。

CloudWatchネットワークメトリクスの読み方

もう一つよくある誤解が、CloudWatchネットワークメトリクスの読み違いです。AWSのネットワーク制限はすべてビット毎秒で表現されている一方、CloudWatchのネットワークメトリクスは一定期間内のバイト量で表されます。このため、NetworkInNetworkOutを眺めただけでは、自分が帯域幅上限のどのあたりにいるのかが非常に分かりにくくなっています。

例として、私のc5.24xlargeインスタンスでNetworkInを開くと、次のように表示されます。

これを見ると、09:20にこのインスタンスのインバウンドトラフィックが50Gbps超のピークに達した、と勘違いしてしまいがちですが、これは誤りです。

実際のネットワークトラフィックをbpsで把握するには、統計をSumに切り替え、その値を期間(秒)で割ります(デフォルトでは5分)。これでその間隔における1秒あたりの平均トラフィック量が得られます。

このケースでは、データポイントの合計バイト数(299800135974)を300秒(5分)で割って、999333786.58バイト/秒となります。

次にバイトをビットに変換します。簡単に済ませたい場合は、0.000008を掛けて直接Mbpsに変換できます(1バイト/秒は0.000008 Mbpsに相当します)。

変換すると、このメトリクスが実際に示しているのは、その5分間のインバウンドトラフィック平均7994 Mbpsであることがわかります。最初に受けた50 Gbpsという印象とはかけ離れた値です。

その期間の総ネットワークトラフィックを把握したいときは、NetworkOutも同様に変換し、両者を合算する必要があります。

コネクショントラッキングのスロットリング

帯域幅制限の話から一歩進めると、AWSは追跡される接続数にも上限を設けており、これに達した時点で新規接続が拒否され始めます。

これはかなり厄介な問題です。一度この上限に到達すると、接続数が許容値を下回るまで、AWSはそのEC2インスタンスへの新規接続をすべて拒否し続けます。

ごく最近までAWSはこれについて何も公表しておらず、ドキュメントにもこの制限への言及はありませんでした。幸い、AWSは最近になってEC2インスタンスタイプごとの接続追跡上限を公開し始めましたが、対象はNitroベースの新しい世代のインスタンスに限られます。

非Nitroインスタンスにも同様の制限は存在するものの、その値は公表されておらず、自分のインスタンスでどの程度の接続数から新規接続が拒否されるかをテストして見つけ出すしかありません。

Nitroインスタンスで追跡可能な接続の最大数は、次のコマンドで確認できます。

[root@ip-172-31-92-221 ~]# ethtool -S ens5|grep conntrack_allowance_available
     conntrack_allowance_available: 136813
[root@ip-172-31-92-221 ~]#

そもそもこの制限が存在する理由は、セキュリティグループにあります。セキュリティグループはステートフルで、conntrackを使って接続を追跡することにより、アウトバウンドのセキュリティグループルールに関わらずインバウンドトラフィックの応答が出ていけるようにしています(逆方向も同様です)。

つまり、セキュリティグループを使わないという形であれば、インスタンスサイズを大きくせずにこの制限を回避できるということです。

セキュリティグループにすべてのトラフィックを許可するインバウンド・アウトバウンドのルールが設定されている場合、それらのフローはNOTRACKとしてマークされ、AWS側で追跡されないため、conntrackのアロワンスを消費しません [7]。

あるいは、ステートレスなネットワークACLを使うか、iptablesルールを直接利用する方法もあります。iptablesはステートレスにもステートフルにも構成でき、ステートフルにする場合はインスタンス側からLinuxのconntrackを制御できるため、必要に応じて上限を引き上げられます。

この回避策の唯一の例外は、以下に挙げる特定のAWSサービス向けの接続です。これらは対称ルーティングを保証するため、セキュリティグループの設定にかかわらず常に自動で追跡されます。この場合に取れる対処はインスタンスサイズの拡大のみです [7]。

  • Egress-only internet gateways
  • Gateway Load Balancers
  • Global Accelerator accelerators
  • NAT gateways
  • Network Firewall firewall endpoints
  • Network Load Balancers
  • AWS PrivateLink (interface VPC endpoints)
  • Transit gateway attachments
  • AWS Lambda (Hyperplane elastic network interfaces)

ローカルプロキシサービスへのスロットリング

AWSはEC2内向けにいくつかのローカルプロキシサービスを提供しています。具体的には、AWS DNSリゾルバ(VPCサブネットの2番目のIP、またはどのEC2インスタンスからでも利用できる169.254.169.253)、AWS提供のNTPサーバー(169.254.169.123)、そしてInstance Metadata Service(169.254.169.254)です。

これらのサービスは、ENIインターフェースごとに1024 pps(packets per second)のハードリミットを共有しています。これを超えると、linklocal_allowance_exceededによってインターフェースがスロットリングされます。

このケースでのスロットリングは、Instance Metadata Serviceの過剰利用が原因であることが多いです。たとえば、頻繁に呼ばれる再帰関数の中でIMDSへの問い合わせを行っていると、簡単にこの上限に達してしまいます。注意すべき点として、上限はパケット毎秒であり、HTTPによるIMDSリクエストは完了までに複数のネットワークパケットを使うため、この上限が「1024クエリ毎秒」と等価になるわけではありません。

この上限はインスタンスサイズに関係なく変更不可能なハードリミットなので、IMDSの利用を意識的に絞り、可能な範囲で結果をキャッシュすることが基本的な対処になります。

もう一つよくあるスロットリングのケースは、DNSクエリが大量に発生している場合で、その対策はローカルDNSキャッシュの実装です。

linklocal_allowance_exceededのENAカウンタが増えている場合は、これらのサービスIP宛のトラフィックをパケットキャプチャし、DNS、HTTP、NTPのいずれであるかを切り分けることで、原因となっているサービスを特定できます。

パケットスロットリングのトラブルシューティング

AWSにおけるもう一つのスロットリング形態が、パケット毎秒の数によるものです。これらの制限についてはドキュメントが極めて限られており、話が一気に複雑になります。

EC2インスタンスが帯域幅の上限に達していなくても、そのインスタンスにおけるパケット毎秒の最大値に到達すると、ネットワークトラフィックがスロットリングされる可能性があります。ここでの上限はlinklocal_allowance_exceededのようなENI単位ではなく、インスタンス単位です。

しかしAWSは、NDAを結ばない限り、EC2インスタンスタイプごとのパケット毎秒の最大許容値を公開していません。さらにこの値は固定でもなく、トラフィックを構成するパケットの種類によって変動します。

EC2インスタンスのPPS制限は、次の要素によって変わります [8]。

  • トラフィックがTCPかUDPか
  • フロー数
  • パケットサイズ
  • 新規接続か既存接続か(TCP SYNの制限)
  • 適用されているセキュリティグループのルール

このため、徹底的なテストを行ったとしても、確かなPPS上限値を一意に特定するのはほぼ不可能です。実際の制限はトラフィックの実態のパターン次第で変わるからです。

たとえば、新規接続を多数生成するアプリケーションはTCP SYNの制限に当たりやすく、既存接続を中心に利用するアプリケーションよりもはるかに早くPPS上限に達する傾向があります。

パケットを使ってインスタンスへストレステストを行い、PPS上限の概算値を求める方法もあります。AWSもこの記事でその手順を解説しています [8]。ただし、この方法はiperfで帯域幅上限を見つける場合に比べて信頼性が大きく劣ります。

より望ましいのは、実際にホストしているアプリケーション自体でストレステストを行い、PPSスロットリングのENAメトリクスを監視するアプローチです。これならアプリケーション本来のネットワークパターンが結果に反映されます。

幸い、PPS制限はそれほど厳しくないことが多く、たいていは帯域幅上限の方が先に到達します。とはいえ、望ましいトラフィックパターンとしては、TCPトラフィック中心で既存接続を多く再利用し、パケットサイズが大きく、フロー数が多く、対象ポートでインバウンド・アウトバウンドのすべてを許可するセキュリティグループを設定して接続追跡を回避する、という構成が理想です。

スロットリングが発生した場合は、上記のパターンに近づくようトラフィック構成を調整するか、それが難しいならインスタンスサイズを引き上げる、という対処になります。

参考資料