
ALBの新機能 Target Optimizer による同時接続数の制御を試してみた
2025年11月20日、Application Load Balancer (ALB) の新機能、ターゲットオプティマイザー (Target Optimizer) がリリースされました。
これまではWAFやWebサーバ側で行っていた同時接続数の制御が、ALBとターゲット間の連携によってより効果的に行えるようになります。 今回、ALB配下のターゲットの同時接続数を一定以下に制御し、過剰な接続による性能劣化を回避できるか、試す機会がありましたので、紹介します。
環境構成
今回は ECS のサイドカー構成を模倣するため、EC2 上で Docker を利用し、--network host モードでエージェントとアプリケーションを同居させました。
- OS: Amazon Linux 2023 (al2023-ami-2023.9.20251117.1-kernel-6.1-x86_64)
- App: Node.js (クエリパラメータで遅延を制御)
- Agent: AWS Target Optimizer Agent
EC2 (Docker & アプリ)
1秒の遅延を意図的に発生させる Node.js アプリケーションと、ALB からのリクエストを中継・制御する Target Optimizer agent を起動しました。
#!/bin/bash# 1. システムパッケージを最新化yum update-y# 2. Dockerをインストールyuminstall-ydocker# 3. Dockerサービスを起動・有効化systemctl startdockersystemctlenabledocker# 4. Target Optimizer agentイメージをダウンロードdocker pull public.ecr.aws/aws-elb/target-optimizer/target-control-agent:latest# 5. Node.jsアプリケーションのディレクトリを作成mkdir-p /app# 6. 遅延可能なNode.jsアプリケーションを作成(クエリパラメータ ?delay=<ms> で遅延時間を指定)cat> /app/app.js<<'EOF'require('http').createServer(async (req, res) => { const delay = parseInt(new URL(req.url, 'http://localhost').searchParams.get('delay')) || 0; if (delay > 0) await new Promise(r => setTimeout(r, delay)); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(`OK (${delay}ms delay)\n`);}).listen(8080, () => console.log('Server running on port 8080'));EOF# 7. Dockerfileを作成cat> /app/Dockerfile<<'EOF'FROM node:alpineCOPY app.js .CMD ["node", "app.js"]EOF# 8. Dockerイメージをビルドcd /app&&docker build-t delay-app.# 9. Node.jsアプリケーションコンテナを起動docker run-d\--name delay-app\--restart unless-stopped\--networkhost\ delay-app# 10. Target Optimizer agentコンテナを起動docker run-d\--name target-optimizer-agent\--restart unless-stopped\--networkhost\-eTARGET_CONTROL_DATA_ADDRESS=0.0.0.0:80\-eTARGET_CONTROL_CONTROL_ADDRESS=0.0.0.0:3000\-eTARGET_CONTROL_DESTINATION_ADDRESS=127.0.0.1:8080\-eTARGET_CONTROL_MAX_CONCURRENCY=1\ public.ecr.aws/aws-elb/target-optimizer/target-control-agent:latestALB ターゲットグループ作成
検証用のALBを作成しました。
ターゲットグループ作成時、--target-control-port 設定を実施しました。
これにより、ALB は指定したポート(今回は3000)を通じてエージェントと通信し、混雑状況を把握します。
Target Optimizer有効のTarget Groupを作成(CLI)
aws elbv2 create-target-group\--name optimized-tg\--protocol HTTP\--port80\ --vpc-id<VPC-ID>\ --target-control-port3000\--region ap-northeast-1# --target-control-port でエージェントとの通信ポートを指定- マネージドルール(GUI)設定

今回 EC2のエージェントに合わせ、ターゲットコントロールポートは「3000」。 Target Optimizer agentコンテナのポート「80」を通信先としました。
動作検証
リクエスト毎に意図的に「1秒」の遅延を発生させ、同時接続数制限(今回は1)を超えた場合にどう挙動するかを確認しました。
テストスクリプト
#!/bin/bashDELAY=${1:-0}ALB_DNS=$(aws elbv2 describe-load-balancers--region ap-northeast-1--query'LoadBalancers[0].DNSName'--output text)URL="http://$ALB_DNS/?delay=$DELAY"run_requests(){localPARALLEL=$1localRESULT=$(seq1 $PARALLEL|xargs-P $PARALLEL-I{}curl-s--http1.1-o /dev/null-w"%{http_code}\n""$URL"2>/dev/null)localS=$(echo"$RESULT"|grep-c"200"||true)localF=$(echo"$RESULT"|grep-c"503"||true)echo"$S$F"sleep1}echo"=== テスト設定 ==="echo"遅延時間:${DELAY}ms"echo"URL:$URL"echo""echo"=== ウォームアップ中(2並列、10秒間)==="START_TIME=$(date +%s)WARMUP_SUCCESS=0WARMUP_FAILED=0while[$(($(date+%s)- START_TIME))-lt10];doread S F<<<$(run_requests2)WARMUP_SUCCESS=$((WARMUP_SUCCESS+ S))WARMUP_FAILED=$((WARMUP_FAILED+ F))doneecho"ウォームアップ完了: 成功=$WARMUP_SUCCESS, 失敗=$WARMUP_FAILED"echo""sleep2echo"=== Target Optimizer 並列負荷テスト (各30秒間) ==="echo"並列数 | 成功(200) | 失敗(503) | 成功率"echo"-------|-----------|-----------|-------"forPARALLELin124816;doSTART_TIME=$(date +%s)SUCCESS=0FAILED=0while[$(($(date+%s)- START_TIME))-lt30];doread S F<<<$(run_requests $PARALLEL)SUCCESS=$((SUCCESS+ S))FAILED=$((FAILED+ F))doneTOTAL=$((SUCCESS+ FAILED))if[$TOTAL-gt0];thenRATE=$(awk"BEGIN {printf\"%.1f%%\", ($SUCCESS*100.0/$TOTAL)}")elseRATE="0.0%"fiprintf"%6d | %9d | %9d | %s\n"$PARALLEL$SUCCESS$FAILED"$RATE"doneecho""echo"=== テスト完了 ==="検証結果
並列数を 1 から 16 まで増やして負荷をかけました。 EC2は2台構成、各エージェントの設定は MAX_CONCURRENCY=1 です。
| 並列数 | 成功(200) | 失敗(503) | 成功率 |
|---|---|---|---|
| 1 | 15 | 1 | 93.8% |
| 2 | 21 | 9 | 70.0% |
| 4 | 30 | 30 | 50.0% |
| 8 | 30 | 90 | 25.0% |
| 16 | 30 | 210 | 12.5% |
並列数を増やしても、成功数は「30」で頭打ちになり、超過分は期待通り 503 Service Unavailable となりました。
※ 成功数が30件である理由: アプリの処理時間(1秒) + スクリプトの待機時間(1秒) = 1サイクル約2秒。 30秒間のテストでおよそ15サイクル実行され、2台のEC2がそれぞれ1リクエストずつ処理したため(15回 × 2台 = 30回)と考えられます。
アクセスログの確認
ALBのアクセスログからも、Target Optimizerの動作が確認できました。
- 成功ログ(200)
処理時間(target_processing_time)が 1.004s となっており、アプリでの1秒遅延を経て正常に返されていました。
| 項目 | 値 |
|---|---|
| プロトコル | http |
| 時刻 | 2025-11-21T16:10:02.724784Z |
| ALB | app/alb-XXXXX/a7c2180283d10881 |
| クライアント | 203.xx.xx.xx:53426 |
| ターゲット | 172.31.24.14:80 |
| 処理時間 | request=0.000s / target=1.004s / response=0.000s |
| ELBステータス | 200 |
| ターゲットステータス | 200 |
| 受信バイト | 144 |
| 送信バイト | 163 |
| リクエスト | GET /?delay=1000 HTTP/1.1 |
| User-Agent | curl/8.11.1 |
http 2025-11-21T16:10:02.724784Z app/alb-XXXXX/a7c2180283d10881 203.xx.xx.xx:53426 172.31.24.14:80 0.0001.004 0.000 200 200 144 163 "GET http://my-alb-XXXXX.ap-northeast-1.elb.amazonaws.com:80/?delay=1000 HTTP/1.1" "curl/8.11.1" - - arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/optimized-tg/41e7338699cf44e9 "Root=1-69208ed9-4b1b24d81a741acd3b4a42dd" "-" "-" 0 2025-11-21T16:10:01.720000Z "forward" "-" "-" "172.31.24.14:80" "200" "-" "-" TID_7290691baf7245469508aa6a42bd733c "-" "-" "-"- 失敗ログ(503)
ターゲットに到達する前(target ipが -)に、ALBまたはエージェントの判断により 503 が返却されています。
Target Optimizerにより、バックエンドのアプリに負荷をかけない保護が実現できていることが確認できました。
| 項目 | 値 |
|---|---|
| プロトコル | http |
| 時刻 | 2025-11-21T16:10:01.738713Z |
| ALB | app/alb-XXXXX/a7c2180283d10881 |
| クライアント | 203.xx.xx.xx:53464 |
| ターゲット | - (到達せず) |
| 処理時間 | request=-1s / target=-1s / response=-1s |
| ELBステータス | 503 |
| ターゲットステータス | - |
| 受信バイト | 144 |
| 送信バイト | 162 |
| リクエスト | GET /?delay=1000 HTTP/1.1 |
| User-Agent | curl/8.11.1 |
※ALBアクセスログでは、リクエストがターゲットに到達しなかった場合、処理時間フィールドに -1 が記録されます。
http 2025-11-21T16:10:01.738713Z app/alb-XXXXX/a7c2180283d10881 203.xx.xx.xx:53464 - -1 -1 -1 503 - 144 162 "GET http://my-alb-XXXXX.ap-northeast-1.elb.amazonaws.com:80/?delay=1000 HTTP/1.1" "curl/8.11.1" - - arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/optimized-tg/41e7338699cf44e9 "Root=1-69208ed9-4a2f731a0e5fabfe6f9d184f" "-" "-" 0 2025-11-21T16:10:01.736000Z "forward" "-" "-" "-" "503" "-" "-" TID_3e941d6f5423694e9f3f8e512cc30b7c "-" "-" "-"まとめ
今回の検証により、Target Optimizer を利用することで、アプリケーションの限界を超えたリクエストを ターゲットに到達させる前に 遮断できることが確認できました。
ALBレベル(エージェント連携)で制御されるため、アプリケーションプロセスを守る「流量制限(バルクヘッド)」の手段として非常に有効です。
今回はEC2上のDockerで検証しましたが、特に Amazon ECS のサイドカーパターンで導入する場合、タスクごとの厳密な同時実行数の制御に利用できます。
特に、1リクエストの処理時間が長く、GPUリソースなどに物理的な並列限界がある「生成AI・LLMアプリケーション」などで、システム全体の安定稼働を守る手段としてご活用ください。







