SJ blog
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)を使って特定の条件に合うメッセージのみをサブスクライバーに届ける機能だ。ファンアウトパターンと組み合わせることで、各コンシューマーに必要なメッセージだけを効率的に配信できる。