1. はじめに
1.1 背景
クラウドアーキテクチャにおいて、スケーラブルなアプリケーションを構築することは重要な課題です。特に、マイクロサービス環境では、柔軟にリソースを増減できる仕組みが求められます。AWS の Elastic Container Service (ECS) と Simple Queue Service (SQS) を組み合わせることで、負荷に応じたスケール調整が可能になります。
本記事では、ECS とは何か、SQS とは何かを詳しく解説し、それらを組み合わせたスケーラブルなアーキテクチャの構築方法を詳細に説明します。また、ECS タスク内の並列処理を Java を用いて実装する方法についても深く掘り下げます。
1.2 ECS と SQS を組み合わせる理由
ECS はコンテナのスケーリングと管理を担い、SQS は非同期メッセージングを提供します。この 2 つを組み合わせることで、リアルタイム処理を求められるマイクロサービスアーキテクチャや、バッチ処理を効率化するワークフローシステムなどで特に有効に機能します。例えば、EC サイトにおける注文処理では、SQS を使って決済や在庫管理のリクエストをキューイングし、ECS のスケールアウト機能を活用して、ピーク時の負荷に適応できます。同様に、データ分析基盤では、大量のログやセンサーデータを SQS で処理キューに格納し、ECS を使って並列処理することで、処理の遅延を最小限に抑えることができます。この 2 つを組み合わせることで、以下のような利点があります。
- 負荷分散の最適化: SQS を使ってリクエストをキューイングし、ECS タスクが処理可能な範囲で順次処理。
- 高可用性の確保: ECS のスケールアウト/イン機能と SQS の耐障害性を活かし、システム全体の安定性を向上。
- コスト最適化: 必要な分だけリソースを使用し、不要になればスケールイン。
2. ECS とは?
2.1 ECS の概要
AWS Elastic Container Service (ECS) は、Docker コンテナを簡単にデプロイ・管理できるフルマネージドなコンテナオーケストレーションサービスです。
2.2 ECS の特徴
- マネージドサービス: Kubernetes のようなクラスタ管理が不要。
- Fargate 対応: インフラ管理なしでコンテナを実行可能。
- 自動スケーリング: 負荷に応じてコンテナ数を増減可能。
- IAM 権限管理: コンテナごとに異なる IAM ポリシーを適用可能。
2.3 ECS のコンポーネント
- クラスター: コンテナを実行する環境。
- タスク定義: コンテナの設定(CPU、メモリ、環境変数など)。
- サービス: タスクの管理(スケーリング、ヘルスチェック)。
- タスク: 実行中のコンテナ。
- ロードバランサー: コンテナの負荷分散を管理。
- オートスケール: 負荷に応じて ECS タスクを自動で増減。
3. SQS とは?
3.1 SQS の概要
AWS Simple Queue Service (SQS) は、メッセージを非同期で送受信できるフルマネージドなメッセージキューサービスです。ECS などの処理システムと組み合わせることで、システムの耐障害性を向上させることができます。
3.2 SQS の特徴
- 非同期処理: 処理をキューに蓄積し、適切なタイミングで処理可能。
- 自動スケーリング: メッセージ量に応じたスケーリングが可能。
- 高可用性: AWS によってフルマネージドされているため、障害耐性が高い。
- 高スループット: 大量のメッセージ処理に最適。
3.3 SQS の種類
- 標準キュー: 高スループット、メッセージの順序保証なし。
- FIFO キュー: メッセージの順序を保証、重複処理を防ぐ。
- デッドレターキュー (DLQ): 処理失敗メッセージを蓄積し、手動で再処理可能。
4. ECS タスク内の並列処理 (Java)
ECS タスク内の処理を効率化するために、Java の FixedThreadPool
を利用して並列処理を行う方法を紹介します。
4.1 Java による並列処理の実装
private final ExecutorService service = Executors.newFixedThreadPool(3);
4.2 並列タスクの処理
ECS タスク内でメッセージを並列に処理するために、FixedThreadPool
を使用して複数のスレッドを作成します。以下のコードは、SQS からメッセージを取得し、並列で処理する実装例です。
import java.util.concurrent.*;
import java.util.List;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
public class SqsMessageProcessor {
private final ExecutorService service = Executors.newFixedThreadPool(3);
private final SqsClient sqsClient;
private final String queueUrl;
public SqsMessageProcessor(SqsClient sqsClient, String queueUrl) {
this.sqsClient = sqsClient;
this.queueUrl = queueUrl;
}
public void processMessages() {
while (true) {
List<Message> messages = receiveMessages();
if (messages.isEmpty()) continue;
for (Message message : messages) {
service.submit(() -> handleMessage(message));
}
}
}
private List<Message> receiveMessages() {
ReceiveMessageRequest request = ReceiveMessageRequest.builder()
.queueUrl(queueUrl)
.maxNumberOfMessages(10)
.waitTimeSeconds(10)
.build();
return sqsClient.receiveMessage(request).messages();
}
private void handleMessage(Message message) {
try {
System.out.println("Processing message: " + message.body());
Thread.sleep(5000); // 模擬的な処理
deleteMessage(message);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void deleteMessage(Message message) {
DeleteMessageRequest deleteRequest = DeleteMessageRequest.builder()
.queueUrl(queueUrl)
.receiptHandle(message.receiptHandle())
.build();
sqsClient.deleteMessage(deleteRequest);
}
public void shutdown() {
service.shutdown();
try {
if (!service.awaitTermination(60, TimeUnit.SECONDS)) {
service.shutdownNow();
}
} catch (InterruptedException e) {
service.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
4.3 Graceful Shutdown の実装
ECS のタスクが停止される際に、安全にスレッドを終了させるための ShutdownHook
を追加します。
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down gracefully...");
service.shutdown();
try {
if (!service.awaitTermination(60, TimeUnit.SECONDS)) {
service.shutdownNow();
}
} catch (InterruptedException e) {
service.shutdownNow();
}
}));
このコードにより、ECS のタスクが SIGTERM
を受信した際に、並列処理中のタスクを適切に処理しつつ、安全にシャットダウンすることができます。
5. SQS のメッセージ処理最適化
SQS の設定を最適化することで、処理の効率化とリソースの適切な使用を実現できます。特に、可視性タイムアウト(Visibility Timeout)や最大受信メッセージ数(MaxNumberOfMessages)の設定は、システムのパフォーマンスに大きく影響を与えます。
可視性タイムアウトの最適な設定
可視性タイムアウトは、ECS タスクがメッセージを取得した後、他のコンシューマーが同じメッセージを取得できないようにする時間です。処理時間が短すぎると、まだ処理が完了していないメッセージが再取得され、重複処理が発生する可能性があります。
メッセージ処理時間 | 推奨可視性タイムアウト |
---|---|
5 秒未満 | 15 秒 |
10 秒 | 25 秒 |
30 秒 | 60 秒 |
60 秒以上 | 処理時間の 2 倍 |
適切な値を設定することで、メッセージの二重処理を防ぎつつ、ECS の処理負荷を最適化できます。
最大受信メッセージ数の設定
MaxNumberOfMessages
は、一度に取得するメッセージ数を指定します。ECS のスレッド数に応じて適切な値を設定すると、処理効率が向上します。
ECS のスレッド数 | 推奨 MaxNumberOfMessages
|
---|---|
1 | 1 |
2 | 2 ~ 5 |
3 | 3 ~ 7 |
4 | 4 ~ 8 |
5 以上 | 5 ~ 10 |
最大 10 件まで設定可能ですが、すべてのメッセージを処理し終える前にタイムアウトすると、未処理メッセージが残る可能性があるため注意が必要です。
メッセージ再試行とデッドレターキューの活用
処理に失敗したメッセージが無限にリトライされないように、デッドレターキュー(DLQ)を設定すると、エラーメッセージを安全に管理できます。通常、MaximumReceives
を 5 ~ 10 に設定し、特定回数以上失敗したメッセージを DLQ に移動させることで、システムの安定性を向上できます。
このように、SQS の設定を適切に調整することで、ECS のパフォーマンスを最大限に引き出し、安定したメッセージ処理システムを構築できます。
6. ECS のスケールイン・スケールアウトの仕組み
ECS のスケーリングに関する詳細な説明と、AWS Auto Scaling の設定方法を解説します。
6.1 オートスケーリングの設定例
ECS では Application Auto Scaling を使用して、タスク数を自動的に増減できます。オートスケーリングを設定するには、次のステップを実行します。
ステップ 1: スケーラブルターゲットの作成
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/my-cluster/my-service \
--min-capacity 1 \
--max-capacity 10
このコマンドは、ECS サービス my-service
のタスク数を 1~10 の範囲でスケール 可能にします。
ステップ 2: スケーリングポリシーの作成
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/my-cluster/my-service \
--policy-name ecs-scale-out-policy \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration file://scale-out.json
ここで scale-out.json
は、CPU 使用率や SQS のメトリクスを基準にスケールするための JSON 設定ファイルです。
scale-out.json の例 (CPU 使用率 70% でスケールアウト)
{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 300
}
6.2 監視すべきメトリクス
ECS のスケーリングには、以下のメトリクスを活用できます。
メトリクス | 説明 | 推奨トリガー |
---|---|---|
ECSServiceAverageCPUUtilization |
ECS タスクの平均 CPU 使用率 | 70% 以上でスケールアウト |
ECSServiceAverageMemoryUtilization |
ECS タスクの平均メモリ使用率 | 75% 以上でスケールアウト |
ApproximateNumberOfMessagesVisible |
SQS に残っている未処理メッセージ数 | 10 件以上でスケールアウト |
これらの設定を活用することで、負荷に応じた効率的なオートスケーリングを実現できます。
7. まとめ
本記事では、AWS ECS と SQS を活用したスケーラブルなアーキテクチャの構築方法を解説しました。
✅ ECS と SQS を組み合わせてスケールしやすいシステムを構築
✅ ECS の stopTimeout
を適切に設定し、Graceful Shutdown を確保
✅ ECS 内で Java を用いた並列処理を実装し、スループットを向上
これらのベストプラクティスを活用し、スケーラブルで高効率な AWS インフラを構築しましょう! 🚀