[AWS] SQS自分用まとめ

# SQSとは

- ほぼ無制限のスケーラビリティを備えたフルマネージドな分散メッセージキュー

| トピック | 内容 |
| :---: | :---: |
| セキィリティ | 利用するユーザーのアクセス制御やメッセージの暗号化が可能 |
| 耐久性 | 複数のサーバ/データセンターに全メッセージを重複して保持（分散キュー） |
| 可用性 | 分散キューモデルを採用することでメッセージの送信/受信の可用性を向上 |
| スケーラビリティ | ほぼ無制限のTPS（Transactions Per Second）をサポート |
| フルマネージド | サーバ管理不要で運用負荷軽減 |
| 初期投資不要 | 毎月の無料利用枠 + 使った分だけの従量課金（API実行回数 + データ転送量） |

# SQSの構成要素

| 要素 | 内容 |
| :---: | :---: |
| プロディーサー | 「キュー」に「メッセージ」を送信するアプリケーション |
| コンシューマー | 「キュー」の「メッセージ」を取得するアプリケーション |
| メッセージ | プロデューサーが生成するデータ（最大256KB） |
| キュー | メッセージをキューイングする分散キューでメッセージを最大14日間保持可能 |

# SQSのユースケース

## バッファリングとバッチ化（一時的なリクエスト増の均一化）

- 大量リクエストが発生する場合にキューで受け止める
    - 急激なスパイクにも対応
- その後キューにたまったメッセージを取得してバックエンド処理を実行する
    - バックエンド負荷を一定に保てる

```shell
↓　↓　↓　↓　↓
------------
    EC2   
------------

↓SQS導入↓

↓　↓　↓　↓　↓
------------
    SQS   
------------
     ↓
------------
    EC2   
------------
```

## ワークキュー（プロデューサーとコンシューマーの処理の依存関係を低減）

- アプリケーション感の依存関係を弱める
- プロデューサーはSQSへメッセージをためて完了
- コンシューマーはSQSのメッセージを処理して完了
- どちらかがサービス停止してもお互いがSQSにのみ依存しているので影響を受けずに済む

```shell
プロデューサー -> コンシューマー

↓SQS導入↓

プロデューサー -> SQS -> コンシューマー
```

## リクエストのオフロード

- 重い処理が含まれていてもすばやく応答を返したい
    - 非同期処理とか（メール送信処理）

## ターゲットのファンアウト

- 複数の処理を並列実行したい
- SNSと組み合わせて1つのメッセージ送信で並列処理が可能
- Pull型でより疎結合な構成

```shell
              プロデューサー
                   ↓
             ------------
                  SNS   
             ------------
　　　↓             ↓            ↓
------------ ------------ ------------
    SQS           SQS          SQS
------------ ------------ ------------
　　　↓             ↓            ↓
------------ ------------ ------------
 コンシューマ   コンシューマ   コンシューマ
------------ ------------ ------------
```

# SQSキューの特徴

> FIFOキューは2018年11月東京リージョン利用可能に

| 項目 | スタンダードキュー | FIFOキュー |
| :---: | :---: | :---: |
| スループット | ほぼ無制限のスループット | 1秒あたり最大300件のメッセージをサポート（最大300件の受信、送信、削除オペレーション） |
| 配信方式 | 少なくとも1回の配信（2回以上の配信もあり得る） | 1回のみの配信 |
| 配信順序 | ベストエフォード（順序が変わる） | 順序を保つ |
| 利用料金 | 100万件ごとに $0.4 | 100万件ごとに $0.5 |

- [スタンダードキュー](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)
- [FIFOキュー](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html)

## 2回以上配信がある場合の設計

- 冪等性を確保できるアプリケーションを設計する
    - 同じメッセージを何回処理しても同じ結果になる結果が変わらないアプリケーション
- DynamoDBなどを使用して重複実行しない設計

# メッセージ取得方法

| 項目 | ショートポーリング | ロングポーリング |
| :---: | :---: | :---: |
| 応答方式 | 即応答でメッセージが無い場合は「空」を返す | 最大20秒メッセージの受領を待ちメッセージが無い場合はタイムアウトし「空」を返す |
| 取得メッセージ | 分散されたサーバの中からサンプリングされたサーバのメッセージを応答する。全サーバではないので取得できないことがある | 全てのサーバをクエリしてメッセージを応答 |
| 利用料金 | 繰り返しショートポーリングを実施するとAPI料金が増加する可能性 | 受領時間が長いためAPI実行回数を抑制でき安価になる可能性 |
| 利用シーン | 複数のキューを1つのスレッドでポーリングするようなケース | 多くのケースのポーリング方式。複数のキューをポーリングする必要がないケース |

- [ロングポーリング](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html#sqs-long-polling) 

# SQSのワークフロー

1. ポーリング
2. メッセージ取得
3. 処理
4. メッセージ削除

# 可視性タイムアウトによる処理中メッセージのロック

- コンシューマが取得したメッセージに対して指定された期間（デフォルト30秒）他のコンシューマからの同一メッセージへのアクセスをブロックする機能

## 利用目的

- 複数のコンシューマが同じメッセージを処理するのを防ぐ
- 指定時間を越えるとアクセス可能となりアプリ障害発生時に再度他のコンシューマで処理が可能

## 考慮点

- 通常の処理の処理に必要な時間より大きな値を設定することで重複処理の発生を防止
- ただし長すぎると障害発生時などの再処理が遅延する
- スダンダードキューの場合は可視性タイムアウトはメッセージを「2回」受信しない保証にはならない
    - 可視性タイムアウト時間中であっても2回コンシューマが受信する可能性がある


- [可視性タイムアウト](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)

# 遅延キューとメッセージタイマー

- メッセージをキューに送信してから一定時間経過後にメッセージが利用可能になる機能（可視性タイムアウトは受信後）

## 利用目的

- メッセージの処理を一定時間遅延させて実施したい場合
    - 例えばリトライ処理などを一定時間後に利用したい場合など

## 考慮点

- 遅延キューはキュー全体の設定
- メッセージタイマーは特定のメッセージに対して遅延を設定するもの
- 両方設定した場合はメッセージタイマーが優先される
- メッセージタイマーは `FIFOキュー` 未サポート

- [メッセージタイマー](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-timers.html)
- [遅延キュー](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/
sqs-delay-queues.html)

# Dead Letter Queue（DLQ）を利用したメッセージの滞留回避

- 正しく処理できないメッセージがキュー内に滞留し続ける状態を回避するために分離先として利用されるキュー
- 分離後にメッセージを解析して原因分析が可能

## 利用目的

- 正常処理できないメッセージが残り続けることを早期（保存期間より前）に回避する
- DLQにメッセージを解析し原因の分析に活用
- DLQにアラームを設定することで検知可能

## 考慮点

- リージョン、アカウント、キュータイプは同一である必要がある
- データの保持期間は元のキューに追加された際のタイムスタンプに基づく
- FIFOキューで順序が変わることが許容できない場合は利用しない
- 無期限に繰り返したい場合は利用しない

- [DLQ](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)

# サーバサイド暗号化を利用したメッセージの暗号化

- AWS KMSで管理されているキーを使用してSQSキュー内のメッセージの内容を保護

## 利用目的

- キュー内に保存されたメッセージを暗号化
- キューへのアクセス権に加えてAWS KMSの鍵へのアクセス権を持つユーザのみがメッセージの送信・受信が可能になる

## 考慮点

- 暗号化対象はメッセージ本文のみで属性は対象外
- AWS利用料金が別途必要

- [サーバサイド暗号化](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html)

# キューのアクセス制御

- IAMポリシーとSQSポリシーのいずれか または両方でアクセス制御を実現

- [サクセス制御](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-overview-of-managing-access.html)

# メッセージ属性を利用したメタ情報の格納

- メッセージ本文とは別に最大10個メタデータ等を保持させることができる

## 利用目的

- メッセージ本文を解析することなく任意の属性を使用して処理の実施判断などが可能

## 考慮点

- メッセージサイズ上限256KBに含まれる
- サーバサイド暗号化の対象外

- [メッセージ属性](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html)

# キューのメトリクス

- スタンダードキューの場合は概算値であり、FIFOキューの場合は厳密な値である

- [使用可能な Amazon SQS の CloudWatch メトリクス](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html)

# 利用料金

- APIリクエスト数に基づく料金 + データ転送量
- APIは64KB単位で1APIリクエストと計算される

| 項目 | 料金 |
| :---: | :---: |
| 無料利用枠 | 毎月100万リクエストまで無料。超えた分から請求 |
| スタンダードキュー | 100万件を超えた場合100万件ごとに $0.40 |
| FIFOキュー | 100万件を超えた場合100万件ごとに $0.50 |
| データ転送量（受信：IN） | $0.00 / GB |
| データ転送量（送信：OUT） | $0.90 / GB |

> 1つのリージョン内のSQSとEC2間は無料

- [SQS料金](https://aws.amazon.com/jp/sqs/pricing/)

# 参考資料

- [AWS BlackBelt AmazonSQS](https://d1.awsstatic.com/webinars/jp/pdf/services/20190717_AWS-BlackBelt_AmazonSQS.pdf)

素晴らしいまとめ、とても参考になる