fck-natの通信負荷の耐性について調べてみた
Posted On 2024-12-04
AWSのマネージドNATゲートウェイの高額なコストの対策として、NATインスタンスが最近注目されています。本記事では、低コストで効果的なfck-natの性能を帯域面から検証していきます。
目次
はじめに
- AWSのマネージドのNATゲートウェイは高い
- 東京リージョンで、1時間に0.062USDで、NATを通しただけで0.062 USD/GBのデータ処理料金が発生する。これはアウトバンドの転送量と別にかかり、固定の維持費は月額44.6ドルにもなる。
- マネージドのNATゲートウェイの可用性は高いが、そこまで可用性いらないケースにはfck-natが有効
- これはNATインスタンスで、デフォルトで
t4g.micro
のインスタンスを立てておくだけで良い。東京リージョンで毎事0.0108 USDで、データ処理量は必要ない。 - 月額7.8ドル+Elastic IPの費用でNATを維持できるという仕組み
- ただ、可用性を犠牲にするといってもどこまで犠牲にできるかわからななかったので、帯域や並列接続でどこまで行けるかテストしてみた
iPerf
アップロード・ダウンロードの帯域幅を指定してベンチマークできるライブラリ
https://github.com/esnet/iperf
Ubuntuなら以下のようにインストールできる
sudo apt update
sudo apt install iperf3 -y
基本的な使い方は以下の通りで、以下のコマンドで100MbpsでサーバーのIPアドレスに60秒間アップロードできる。
iperf3 -c <サーバーのIPアドレス> -u -b 100M -t 60
並列化もできて、これで同時接続をエミュレートできる。以下は10Mbpsで、10個並列にアップロードし、それを300秒継続するという意味。
iperf3 -c <サーバーのIPアドレス> -u -b 10M -P 10 -t 300
結果はリアルタイムとサマリーで可視化されて、以下のように出力される。
[ 5] 297.00-298.00 sec 119 MBytes 1.00 Gbits/sec 86326
[ 5] 298.00-299.00 sec 119 MBytes 1.00 Gbits/sec 86326
[ 5] 299.00-300.00 sec 119 MBytes 1000 Mbits/sec 86326
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-300.00 sec 34.9 GBytes 1000 Mbits/sec 0.000 ms 0/25897719 (0%) sender
[ 5] 0.00-300.00 sec 34.9 GBytes 999 Mbits/sec 0.001 ms 14136/25897719 (0.055%) receiver
これは1Gbpsで送った例。見るべきはreceiverの転送量や、Jitter、ロストの割合で、ロストの割合が大きくなるほど通信負荷が高くなっていることを示す。つまり、NATインスタンスに負荷をかけるほどJitterやロストが上がっていくというもの
テストの構成図
- EC2が3個登場する
- 2個VPCを用意し、片方(右側)にfck-nat(NATインスタンス)をパブリックサブネットにおく
- そのVPCのプライベートサブネットに、iPerfのクライアントをおき、fck-natを通じてインターネットに接続する
- クライアントには、ローカルからSession Managerで接続する
- 接続先として別のVPCのパブリックサブネットにiPerfのサーバーを用意し、このIPをiperfのコマンドの接続先とする
- fck-natのインスタンススペックを変えて負荷テストを行う
t4g.nano, t4g.micro, t4g.small
と変えて比較
- サーバーとクライアントはボトルネックとならないように十分高いスペックのEC2を使う。
- この例では、クライアントに
c7g.8xlarge
、サーバーにm7g.xlarge
を使用。本当はサーバーも通信にバーストリミットがない8xlargeのような大きめのインスタンスを使ったほうが厳密
- この例では、クライアントに
- 帯域を図るための単一接続(並列化しない)と、同時接続を見るための並列接続を比較する
- 要注意なのが、Session Manager(SSH)でリアルタイムに標準出力を出すかで、これをするとNATで輻輳を起こすのか測定結果が大幅に悪化する。詳細のシェルスクリプトは末尾に示すが、iperfのコマンドをパイプしてteeなどで標準出力とファイルの両方で記録としたほうがノイズの少ないスループットを計測できる。
単一接続の場合
- 縦軸がNATインスタンスのスペック、横軸がアップロードの帯域(bps)
- 上がJitterのmsで、下がロスのパーセント
- ロスが0.01%未満を緑、0.01%~10%を黄色、それ以上を赤で表記
- 単一接続なら、
t4g.nano
は2Gbpsは厳しい、デフォルトのt4g.micro
なら頑張れば2Gbpsは出せる。多少のロスは出るが気にしない
同時接続(並列処理)の場合
- 縦軸がNATインスタンスのスペックと、1個あたりの帯域。横軸が並列数
- 5M×50並列なら、合計で250Mbpsの帯域を使う
- NATインスタンスのスケールアップ効果が顕著に出ている
t4g.nano
の場合、5Mbpsの場合は同時接続20~50でも耐えられるが、10Mbpsを要求するととたんに厳しくなる- 10Mbpsで20並列の場合は途中でクラッシュしたのでデータなし
t4g.micro
(デフォルト)の場合、一定耐えられるが同時接続100などになると厳しいt4g.small
にするとどれでも耐えられておりややオーバースペックかもしれない。画像はt4g.smallのプロファイルで、どんなテストでもCPUクレジットが溜まっている- 2Gbps以上などI/Oのバーストが気にならない帯域なら、結局CPUのバーストクレジットが持つかどうかがポイントになるかもしれない
その他
- SSHでリアルタイムにログ(標準出力)吐いてるとそれがかなりのノイズになって結果が悪化するので注意
- fck-natのオプションで変えられるが、基本はオートスケーリンググループに紐づけられたEC2が1個NATインスタンスとしてあるだけなので、耐障害性とか可用性とか気にする場合は普通にNATゲートウェイ使ったほうが普通にいいと思う
テストコード
iPerfのクライアントで動かしたシェルスクリプトは以下の通り(ChatGPT製)
#!/bin/bash
# ユーザーからフォルダ名を入力として受け取る
read -p "結果を格納するフォルダ名を入力してください: " folder_name
# フォルダを作成(既に存在する場合はスキップ)
mkdir -p "$folder_name"
# 接続先のサーバーIPアドレス
SERVER_IP="<your-server-ip-address>"
# テストの持続時間(秒)
DURATION=300
# 並列化なしの帯域幅オプション
SINGLE_BANDWIDTHS=("100M" "500M" "1G" "2G")
# 並列接続数のオプション
PARALLELS=(10 20 50 100)
# ------------------------------
# 1. 並列化なしでのバンド幅検証
# ------------------------------
echo "========================================"
echo "並列化なしでのバンド幅検証を開始します。"
echo "========================================"
for b in "${SINGLE_BANDWIDTHS[@]}"; do
# 出力ファイル名を設定(並列化なし)
filename="${folder_name}/iperf3_b${b}_single.txt"
echo "実行中: iperf3 -b ${b} (並列化なし)"
echo "結果をファイル ${filename} に保存中..."
# iperf3コマンドを実行(並列化なし)
iperf3 -c "$SERVER_IP" -u -b "$b" -t "$DURATION" 2>&1 | tee "$filename"
# 各試行の間に1分(60秒)のクールダウンを挿入
echo "1分間待機します..."
sleep 60
echo "----------------------------------------"
done
echo "並列化なしでのバンド幅検証が完了しました。"
echo "----------------------------------------"
# ---------------------------------
# 2. 並列化ありでのバンド幅検証
# ---------------------------------
echo "========================================"
echo "並列化ありでのバンド幅検証を開始します。"
echo "========================================"
# 並列化ありの帯域幅オプション
PARALLEL_BANDWIDTHS=("5M" "10M")
for b in "${PARALLEL_BANDWIDTHS[@]}"; do
for P in "${PARALLELS[@]}"; do
# 出力ファイル名を設定(並列化あり)
filename="${folder_name}/iperf3_b${b}_P${P}.txt"
echo "実行中: iperf3 -b ${b} -P ${P}"
echo "結果をファイル ${filename} に保存中..."
# iperf3コマンドを実行(並列化あり)
iperf3 -c "$SERVER_IP" -u -b "$b" -P "$P" -t "$DURATION" 2>&1 | tee "$filename"
# 各試行の間に1分(60秒)のクールダウンを挿入
echo "1分間待機します..."
sleep 60
echo "----------------------------------------"
done
done
echo "並列化ありでのバンド幅検証が完了しました。"
echo "----------------------------------------"
echo "すべてのテストが完了しました。結果はフォルダ '$folder_name' に保存されています。"
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー