backend
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
SNSメッセージフィルタリング — サブスクリプションフィルターポリシーの設計
SNSサブスクリプションフィルターポリシーの構文、属性ベースフィルタリング、数値条件、プレフィックスマッチ、MessageAttributesとMessageBodyフィルタリングの違いを解説。
一言結論
SNSフィルターポリシーをサブスクリプションに設定することで各コンシューマーは自分に関係するメッセージだけを受信でき、SNS側でのフィルタリングによりSQSへの配信メッセージ数を削減してコストと処理負荷の両方を下げられる。
SNSフィルタリングの仕組み
SNSはデフォルトでトピックに送られたメッセージを全サブスクライバーに配信する。フィルターポリシーを設定することで、条件に合うメッセージだけを特定サブスクライバーに届けられる。
フィルタリングなし:
SNSトピック → 全サブスクライバーに配信
→ 各SQS/Lambdaがメッセージを取捨選択する必要がある
フィルタリングあり:
SNSトピック → フィルターポリシーで評価
→ 条件A に合うメッセージ → サブスクライバー1(SQS-order)
→ 条件B に合うメッセージ → サブスクライバー2(SQS-payment)
→ 条件C に合うメッセージ → サブスクライバー3(Lambda-alert)
MessageAttributes を使ったフィルタリング
メッセージ送信時にMessageAttributesを付与し、サブスクリプションのフィルターで評価する。
import boto3
import json
sns = boto3.client('sns')
# メッセージ送信時にAttributesを付与
sns.publish(
TopicArn='arn:aws:sns:ap-northeast-1:123456789012:orders-topic',
Message=json.dumps({
'orderId': 'ORDER-123',
'amount': 50000,
'region': 'JP'
}),
MessageAttributes={
'eventType': {
'DataType': 'String',
'StringValue': 'OrderCreated'
},
'region': {
'DataType': 'String',
'StringValue': 'JP'
},
'amount': {
'DataType': 'Number',
'StringValue': '50000'
}
}
)
フィルターポリシーの構文
// 日本の大口注文(10万円以上)のみを受信するフィルター
{
"eventType": ["OrderCreated"],
"region": ["JP"],
"amount": [{"numeric": [">=", 100000]}]
}
# サブスクリプションにフィルターポリシーを設定
aws sns set-subscription-attributes \
--subscription-arn arn:aws:sns:ap-northeast-1:123456789012:orders-topic:xxx \
--attribute-name FilterPolicy \
--attribute-value '{
"eventType": ["OrderCreated"],
"region": ["JP"],
"amount": [{"numeric": [">=", 100000]}]
}'
フィルターポリシーの条件タイプ
文字列マッチ:
{"status": ["active", "pending"]}
→ "active" または "pending" に一致
プレフィックスマッチ:
{"prefix": [{"prefix": "Order"}]}
→ "Order"で始まる値に一致
数値条件:
{"amount": [{"numeric": [">=", 100]}]}
{"amount": [{"numeric": [">", 0, "<=", 1000]}]}(範囲指定)
否定(anything-but):
{"status": [{"anything-but": ["cancelled", "deleted"]}]}
→ "cancelled"と"deleted"以外に一致
存在チェック(exists):
{"couponCode": [{"exists": true}]}
→ couponCode属性が存在する場合のみ
{"couponCode": [{"exists": false}]}
→ couponCode属性が存在しない場合のみ
null チェック:
{"value": [null]}
→ 値がnullの場合
MessageBody フィルタリング(FilterPolicyScope)
従来のMessageAttributesに加え、メッセージ本文(JSON)でフィルタリングできる。
# MessageBody でフィルタリングを設定(FilterPolicyScope: MessageBody)
aws sns set-subscription-attributes \
--subscription-arn arn:aws:sns:... \
--attribute-name FilterPolicyScope \
--attribute-value MessageBody
aws sns set-subscription-attributes \
--subscription-arn arn:aws:sns:... \
--attribute-name FilterPolicy \
--attribute-value '{
"detail": {
"eventType": ["OrderCreated"],
"amount": [{"numeric": [">=", 10000]}]
}
}'
MessageAttributes フィルタリング:
→ メッセージヘッダー的な属性で評価
→ 属性は10個まで、値は256バイトまで
MessageBody フィルタリング:
→ JSONメッセージ本文のフィールドで評価
→ 入れ子構造も対応(detail.eventType等)
→ EventBridgeに近い使い方
SNS + SQS ファンアウトパターン
SNSトピック(受注イベント)
│
├─ [フィルター: eventType=OrderCreated] → SQS(在庫チェックキュー)
│
├─ [フィルター: amount>=100000] → SQS(大口注文アラートキュー)
│
├─ [フィルター: eventType=OrderCancelled] → Lambda(キャンセル処理)
│
└─ [フィルター: region=US] → SQS(海外配送キュー)
メリット:
→ 各コンシューマーは自分に関係あるメッセージだけを受信
→ 不要なメッセージ処理コストの削減
→ SNS側でフィルタリングするため、SQSへのメッセージ量を削減
コスト最適化
フィルタリングなし(全配信):
SNS → 全10 SQSキューに配信
→ 10メッセージ分の料金
フィルタリングあり:
SNS → 条件に合う2 SQSキューのみ配信
→ 2メッセージ分の料金(80%削減)
SQS料金: 0.00000040 USD / リクエスト(最初の100万件無料)
→ 大量メッセージ処理では効果大
試験頻出ポイント
| シナリオ | 回答 |
|---|---|
| 特定カテゴリのメッセージのみSQSに送りたい | SNSフィルターポリシー |
| JSON本文の内容でフィルタリング | FilterPolicyScope: MessageBody |
| ”active”と”pending”以外を受信 | anything-but条件 |
| メッセージ属性の存在チェック | exists条件 |
| EventBridgeとSNSフィルタリングの違い | EventBridgeはAWSサービスイベントや複雑なパターンに優れる |
まとめ
SNSフィルターポリシーはMessageAttributesまたはMessageBody(JSON)を使って特定の条件に合うメッセージのみをサブスクライバーに届ける機能だ。ファンアウトパターンと組み合わせることで、各コンシューマーに必要なメッセージだけを効率的に配信できる。