
はじめに
Amazon Simple Notification Service(SNS)は、AWSが提供するフルマネージドなメッセージング・通知サービスです。アプリケーション間の連携やユーザーへの通知配信において、高い信頼性とスケーラビリティを実現します。
この記事では、SNSの基本概念から実用的な活用方法まで、実際の設定例と共に詳しく解説します。
Amazon SNSとは
Amazon SNSは、**Pub/Sub(パブリッシュ/サブスクライブ)**モデルを基盤としたメッセージングサービスです。メッセージの送信者(パブリッシャー)が特定の受信者を意識することなく、複数の受信者(サブスクライバー)に同時にメッセージを配信できます。
主な特徴
- フルマネージド: インフラストラクチャの管理が不要
- 高可用性: マルチAZ構成による自動冗長化
- スケーラビリティ: 秒間数百万メッセージの処理が可能
- 多様な配信先: SMS、Email、HTTP/HTTPS、AWS Lambda、SQSなど
- メッセージフィルタリング: 条件に基づく配信制御
- 暗号化対応: データの保護とセキュリティ確保
SNSの基本構成要素
トピック(Topic)
トピックは、メッセージを受け取る論理的なエンドポイントです。メッセージの集約点として機能し、複数のサブスクライバーに同じメッセージを配信できます。
- Standard Topic: 一般的な用途、高いスループット
- FIFO Topic: 順序保証とメッセージ重複排除
サブスクリプション(Subscription)
サブスクリプションは、トピックからメッセージを受信するための設定です。各サブスクリプションは特定のプロトコルとエンドポイントを持ちます。
サポートされるプロトコル
- HTTP/HTTPS: WebAPIへの配信
- Email/Email-JSON: メール通知
- SMS: SMS配信
- SQS: Amazon SQSキューへの配信
- Lambda: AWS Lambda関数の実行
- Application: モバイルアプリへのプッシュ通知
- Firehose: Amazon Data Firehoseへのストリーム配信
SNSの実装例
1. 基本的なトピック作成とサブスクリプション
まず、AWS CLIを使ってトピックを作成し、サブスクリプションを設定してみましょう。
# トピックの作成
aws sns create-topic --name user-notifications
# サブスクリプションの作成(Email)
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:user-notifications \
--protocol email \
--notification-endpoint user@example.com
# サブスクリプションの作成(SQS)
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:user-notifications \
--protocol sqs \
--notification-endpoint arn:aws:sqs:ap-northeast-1:123456789012:notification-queue
2. CloudFormationテンプレート例
Infrastructure as Codeでの実装例:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'SNS Topic with multiple subscriptions'
Resources:
UserNotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: user-notifications
DisplayName: ユーザー通知
KmsMasterKeyId: !Ref SNSEncryptionKey
# Email サブスクリプション
EmailSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref UserNotificationTopic
Protocol: email
Endpoint: admin@example.com
# SQS サブスクリプション
SQSSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref UserNotificationTopic
Protocol: sqs
Endpoint: !GetAtt NotificationQueue.Arn
FilterPolicy:
event_type: ["order", "payment"]
# Lambda サブスクリプション
LambdaSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref UserNotificationTopic
Protocol: lambda
Endpoint: !GetAtt ProcessingFunction.Arn
# 通知処理用キュー
NotificationQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: notification-queue
VisibilityTimeoutSeconds: 300
# 暗号化キー
SNSEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: SNS Topic encryption key
KeyPolicy:
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
Outputs:
TopicArn:
Description: SNS Topic ARN
Value: !Ref UserNotificationTopic
Export:
Name: !Sub '${AWS::StackName}-TopicArn'
3. メッセージフィルタリングの活用
特定の条件でメッセージを配信したい場合、フィルターポリシーを設定できます:
{
"event_type": ["order_completed", "payment_failed"],
"priority": ["high", "critical"],
"region": ["ap-northeast-1"],
"price": [{"numeric": [">", 10000]}]
}
高度な活用例
1. マイクロサービス間の非同期通信
import boto3
import json
def publish_order_event(order_data):
sns = boto3.client('sns')
message = {
"event_type": "order_completed",
"order_id": order_data["id"],
"customer_id": order_data["customer_id"],
"amount": order_data["total_amount"],
"timestamp": order_data["created_at"]
}
# メッセージ属性を設定
message_attributes = {
'event_type': {
'DataType': 'String',
'StringValue': 'order_completed'
},
'priority': {
'DataType': 'String',
'StringValue': 'high' if order_data["total_amount"] > 10000 else 'normal'
}
}
response = sns.publish(
TopicArn='arn:aws:sns:ap-northeast-1:123456789012:order-events',
Message=json.dumps(message),
MessageAttributes=message_attributes,
Subject='新規注文完了'
)
return response['MessageId']
2. ファンアウトパターンの実装
一つのメッセージを複数のサービスで異なる処理を行う場合:
# CloudFormation例
OrderProcessingTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: order-processing
# 在庫管理システム
InventorySubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref OrderProcessingTopic
Protocol: sqs
Endpoint: !GetAtt InventoryQueue.Arn
FilterPolicy:
event_type: ["order_created", "order_cancelled"]
# 配送システム
ShippingSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref OrderProcessingTopic
Protocol: lambda
Endpoint: !GetAtt ShippingFunction.Arn
FilterPolicy:
event_type: ["order_confirmed"]
# 請求システム
BillingSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref OrderProcessingTopic
Protocol: sqs
Endpoint: !GetAtt BillingQueue.Arn
FilterPolicy:
event_type: ["order_completed", "order_cancelled"]
3. モバイルプッシュ通知
import boto3
def setup_mobile_push():
sns = boto3.client('sns')
# プラットフォームアプリケーションの作成
platform_app = sns.create_platform_application(
Name='MyMobileApp',
Platform='GCM', # Android用、iOS用の場合は'APNS'
Attributes={
'PlatformCredential': 'YOUR_FIREBASE_SERVER_KEY'
}
)
# エンドポイントの作成(ユーザーのデバイストークン)
endpoint = sns.create_platform_endpoint(
PlatformApplicationArn=platform_app['PlatformApplicationArn'],
Token='DEVICE_TOKEN'
)
# プッシュ通知の送信
message = {
"GCM": json.dumps({
"data": {
"title": "新しいメッセージ",
"body": "お客様宛に新しいメッセージが届きました",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
}
})
}
sns.publish(
TargetArn=endpoint['EndpointArn'],
Message=json.dumps(message),
MessageStructure='json'
)
Amazon SNS vs Amazon SQS
SNSとSQSの使い分けを理解することは、適切なアーキテクチャ設計に重要です。
配信モデルの違い
特徴 | Amazon SNS | Amazon SQS |
---|---|---|
配信モデル | Push(プッシュ) | Pull(プル) |
配信先数 | 1対多(ファンアウト) | 1対1 |
メッセージ保持 | 配信時のみ | 最大14日間 |
順序保証 | FIFO Topicで対応 | FIFO Queueで対応 |
用途 | 即座の通知・イベント配信 | 非同期処理・ワークキュー |
組み合わせパターン
SNSとSQSを組み合わせることで、より柔軟なアーキテクチャを構築できます:
# SNS + SQS の組み合わせ例
EventTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: user-events
# 即座に処理が必要なタスク用キュー
HighPriorityQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: high-priority-tasks
VisibilityTimeoutSeconds: 30
HighPrioritySubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref EventTopic
Protocol: sqs
Endpoint: !GetAtt HighPriorityQueue.Arn
FilterPolicy:
priority: ["high", "critical"]
# バッチ処理用キュー
BatchProcessingQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: batch-processing
VisibilityTimeoutSeconds: 900
MessageRetentionPeriod: 1209600 # 14日
BatchSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref EventTopic
Protocol: sqs
Endpoint: !GetAtt BatchProcessingQueue.Arn
FilterPolicy:
processing_type: ["batch"]
セキュリティベストプラクティス
1. アクセス制御
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublishFromSpecificRoles",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:role/OrderProcessingRole",
"arn:aws:iam::123456789012:role/NotificationRole"
]
},
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-northeast-1:123456789012:user-notifications"
},
{
"Sid": "DenyUnencryptedPublish",
"Effect": "Deny",
"Principal": "*",
"Action": "sns:Publish",
"Resource": "*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
2. 暗号化設定
EncryptedTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: encrypted-notifications
KmsMasterKeyId: !Ref SNSKMSKey
SNSKMSKey:
Type: AWS::KMS::Key
Properties:
Description: SNS encryption key
KeyPolicy:
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
- Effect: Allow
Principal:
Service: sns.amazonaws.com
Action:
- kms:Decrypt
- kms:GenerateDataKey
Resource: '*'
3. メッセージの署名検証
HTTP/HTTPSエンドポイントでメッセージを受信する際の検証例:
import json
import base64
import urllib.request
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key
def verify_sns_message(message_data):
# 署名URLから証明書を取得
cert_response = urllib.request.urlopen(message_data['SigningCertURL'])
cert = cert_response.read().decode('utf-8')
# 公開鍵を抽出
public_key = load_pem_public_key(cert.encode('utf-8'))
# 署名文字列を構築
string_to_sign = construct_string_to_sign(message_data)
# 署名を検証
try:
public_key.verify(
base64.b64decode(message_data['Signature']),
string_to_sign.encode('utf-8'),
padding.PKCS1v15(),
hashes.SHA1()
)
return True
except Exception:
return False
監視とログ記録
1. CloudWatchメトリクス
重要な監視メトリクス:
NumberOfMessagesPublished
: 発行されたメッセージ数NumberOfNotificationsDelivered
: 配信されたメッセージ数NumberOfNotificationsFailed
: 配信に失敗したメッセージ数PublishSize
: メッセージサイズ
2. アラーム設定例
FailedDeliveryAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: SNS-Failed-Deliveries
AlarmDescription: SNS配信失敗の監視
MetricName: NumberOfNotificationsFailed
Namespace: AWS/SNS
Statistic: Sum
Period: 300
EvaluationPeriods: 2
Threshold: 5
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: TopicName
Value: !GetAtt UserNotificationTopic.TopicName
AlarmActions:
- !Ref AlertTopic
3. Dead Letter Queue(DLQ)の設定
NotificationQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: notification-queue
RedrivePolicy:
deadLetterTargetArn: !GetAtt NotificationDLQ.Arn
maxReceiveCount: 3
NotificationDLQ:
Type: AWS::SQS::Queue
Properties:
QueueName: notification-dlq
MessageRetentionPeriod: 1209600 # 14日間
料金最適化
東京リージョン(ap-northeast-1)の料金
-
リクエスト料金:
- 最初の100万リクエスト: $0.50/100万リクエスト
- 100万~10億リクエスト: $0.50/100万リクエスト
- 10億リクエスト以降: $0.30/100万リクエスト
-
配信料金:
- HTTP/HTTPS: $0.60/100万配信
- Email/Email-JSON: $2.00/100万配信
- SMS: 国内$0.0945/メッセージ(キャリア料金別途)
- モバイルプッシュ通知: $0.50/100万配信
コスト最適化のコツ
-
メッセージフィルタリングの活用
# 必要なサブスクライバーのみに配信 sns.publish( TopicArn=topic_arn, Message=message, MessageAttributes={ 'customer_tier': { 'DataType': 'String', 'StringValue': 'premium' } } )
-
バッチ処理の検討
# 複数のメッセージをまとめて送信 def batch_notifications(notifications): sns = boto3.client('sns') batch_messages = [] for notification in notifications: batch_messages.append({ 'Id': notification['id'], 'Message': json.dumps(notification['data']) }) # 10件ごとにバッチ送信 if len(batch_messages) == 10: sns.publish_batch( TopicArn=topic_arn, PublishRequestEntries=batch_messages ) batch_messages = []
-
不要なサブスクリプションの削除
# 使用されていないサブスクリプションを特定 aws sns list-subscriptions-by-topic \ --topic-arn arn:aws:sns:ap-northeast-1:123456789012:topic-name \ --query 'Subscriptions[?SubscriptionArn==`PendingConfirmation`]'
トラブルシューティング
よくある問題と解決方法
-
メッセージが配信されない
- サブスクリプションの確認状態をチェック
- フィルターポリシーの設定を確認
- IAMロールの権限を確認
-
配信の遅延
- エンドポイントの応答時間を確認
- リトライポリシーの設定を調整
- DLQの設定を確認
-
高い料金
- 不要なサブスクリプションを削除
- メッセージサイズを最適化
- フィルタリング条件を見直し
まとめ
Amazon SNSは、現代のクラウドアプリケーションにおいて欠かせないメッセージングサービスです。Pub/Subモデルによる柔軟な配信、豊富な配信先プロトコル、強力なフィルタリング機能により、複雑な通知要件にも対応できます。
SQSとの適切な使い分けや組み合わせにより、信頼性の高いイベント駆動アーキテクチャを構築できます。セキュリティ設定や監視体制を整えて、スケーラブルで効率的なシステムを実現しましょう。
次回はAmazon SQSについて詳しく解説予定です。SNSとSQSを組み合わせたより高度なメッセージングパターンもご紹介しますので、ぜひご期待ください。