SAP-C02-088 · セクション 10 / タスク 2.5
BufferingによるPerformance安定化
Amazon SQS / Buffer / Traffic Spike / Producer / Consumer / Backpressure
システムへ届く処理要求の量は、常に一定とは限りません。
例えば通常時は、
500件 / 秒しか届かない処理でも、キャンペーン開始や一斉通知によって短時間だけ、
5,000件 / 秒まで急増することがあります。
このとき、処理側を常にピーク時の5,000件/秒へ合わせておく必要があるとは限りません。
非同期処理できる要求であれば、
送信側
↓
バッファ
↓
処理側という境界を作り、
一時的な流入量
と
実際の処理速度を分離できます。
重要なのは、
バッファを入れる
=
処理自体が速くなるではないことです。
バッファは、
処理要求を失わず一時的に待たせる
+
処理側が扱える速度へ平準化するために使います。
ゴール
次の判断ができるようにします。
一時的なトラフィックスパイク
+
非同期処理可能
+
後段を急増負荷から保護したい
↓
Amazon SQSによるバッファリングさらに、
送信側の到着速度
処理側の処理速度
キューのバックログ
最古メッセージの待ち時間から、
一時的な急増なのか
処理能力が恒常的に不足しているのかを判断できるようにします。
1. バッファは処理速度の違いを吸収する
バッファ(Buffer)は、まだ処理されていない要求を一時的に保持する境界です。
送信側
↓
バッファ
↓
処理側例えば、
Web API
↓
Amazon SQS
↓
画像変換ワーカーという構成なら、Web APIと画像変換ワーカーが完全に同じ速度で動く必要はありません。
短時間だけ、
送信
2,000件 / 秒
処理
800件 / 秒になっても、
差分
1,200件 / 秒をキューへ蓄積できます。
2. 送信側と処理側の速度を見る
バッファリングでは、
送信側(Producer)と、
処理側(Consumer)の速度関係が重要です。
例えば、
送信側
1,000件 / 秒
処理側
1,000件 / 秒なら、理論上バックログは増えません。
一方、
送信側
2,000件 / 秒
処理側
1,200件 / 秒なら、
800件 / 秒ずつ未処理要求が増えます。
基本関係は、
送信側の到着速度
>
処理側の処理能力
↓
バックログ増加です。
言い換えると、
到着する量
>
処理できる量
↓
待っている仕事が増えるとなります。
3. 一時的な速度差ならバッファで吸収できる
送信側が処理側より速いこと自体が、すぐ問題になるわけではありません。
例えば、
通常
送信側 500件 / 秒
処理側 1,000件 / 秒で、キャンペーン開始直後の1分間だけ、
送信側 3,000件 / 秒
処理側 1,000件 / 秒になったとします。
この1分間はバックログが増えます。
しかし、その後送信側が500件/秒へ戻れば、
処理側 1,000件 / 秒
-
送信側 500件 / 秒
=
毎秒500件の速度でバックログを減らせます。
このような、
一時的なトラフィックスパイク
(Traffic Spike)を吸収することが、バッファの代表的な役割です。
4. 恒常的な処理能力不足はバッファだけでは解決できない
一方、
送信側
2,000件 / 秒
処理側
1,500件 / 秒という状態が何時間も続くなら、
500件 / 秒ずつバックログが増え続けます。
Amazon SQSを間に置いたとしても、
処理能力不足そのものは解消していません。
SQS
↓
バックログを保持できることと、
処理側
↓
十分な速度で処理できることは別です。
したがって、
一時的な速度差
→ バッファで吸収
恒常的な速度差
→ 処理側の増強
処理高速化
送信側の抑制
などが必要と判断します。
5. Amazon SQSを性能安定化のバッファとして使う
Amazon SQSは、完全マネージド型のメッセージキューサービスです。
性能設計では、
送信側
↓
Amazon SQS
↓
処理側という構成によって、送信側が処理側の処理完了を待たずに要求を受け渡せることを利用します。
例えば、
注文受付API
↓
Amazon SQS
↓
帳票生成ワーカーとします。
短時間に注文が急増しても、
注文受付
↓
SQSへ送信までを素早く完了させ、帳票生成は、
処理側が処理可能な速度で後から進められます。
Amazon SQSの配信保証、FIFO、可視性タイムアウト、再配信、デッドレターキューなどは、バッファによる性能平準化とは別の設計条件として扱います。
6. Amazon SQS標準キューは大規模な流入を受け止められる
Amazon SQS標準キューは、SendMessage、ReceiveMessage、DeleteMessageなどに対して非常に高い、ほぼ無制限のAPIコール数をサポートします。
そのため、
大量の送信側
↓
SQS
↓
処理側群という高スループットのバッファとして利用できます。
ただし、
SQSがスケールする
=
処理側も無限に処理できるではありません。
性能ボトルネックは、
処理側
データベース
外部APIなど、キューより後ろに残る可能性があります。
7. バッファはピーク負荷を平準化する
直接接続では、
トラフィックスパイク
↓
処理側へ
そのまま急増負荷となります。
バッファを入れると、
トラフィックスパイク
↓
Amazon SQS
↓
処理側が処理可能な速度にできます。
イメージすると、
流入量
▲
│ ████
│ ████
│ ████
│ ███████████
└────────────────→ 時間というピークを、
処理量
▲
│ ███████████████
│ ███████████████
└──────────────────────→ 時間のように時間方向へ広げます。
これが、
需要曲線を平準化するという考え方です。
8. バッファは総処理量を減らすわけではない
100万件の処理要求が来た場合、
SQSを入れるだけで、
100万件
↓
10万件になるわけではありません。
処理側は最終的に100万件を処理する必要があります。
変わるのは、
いつ
どの速度で
処理するかです。
したがってバッファは、
処理量削減ではなく、
処理タイミングの調整に利用します。
9. バックログを監視する
Amazon SQSでは、
ApproximateNumberOfMessagesVisibleによって、現在取得可能な未処理メッセージ数のおおよその値を確認できます。
これは、
現在どの程度
処理待ちがあるかを見る代表的な指標です。
例えば、
10
↓
500
↓
10,000
↓
50,000と継続的に増えているなら、
送信側の到着速度
>
処理側の処理能力となっている可能性があります。
逆にスパイク後、
50,000
↓
30,000
↓
10,000
↓
0と減っているなら、処理側がバックログを解消できています。
10. キューの深さだけでなく最古メッセージの待ち時間を見る
同じ10,000件のバックログでも、
1秒で処理できる10,000件と、
30分待たされている10,000件では性能状態が違います。
Amazon SQSでは、
ApproximateAgeOfOldestMessageによって、最も古いメッセージのおおよその経過時間を確認できます。
例えば性能目標が、
要求をキューへ入れてから
30秒以内に処理開始なら、
ApproximateAgeOfOldestMessageは件数だけを見るより直接的な判断材料になります。
11. 処理待ちと処理中を分けて考える
SQSには、
ApproximateNumberOfMessagesVisibleだけでなく、
ApproximateNumberOfMessagesNotVisibleもあります。
大まかには、
ApproximateNumberOfMessagesVisible
→ まだ処理側が取得可能な処理待ち
ApproximateNumberOfMessagesNotVisible
→ 処理側が受信して処理中のメッセージと考えます。
例えば、
処理待ちメッセージが急増
+
処理中メッセージはほぼ一定なら、
処理待ちだけが増えている可能性があります。
一方、
処理中メッセージも増加しているなら、処理側で多くのメッセージを並行処理している可能性があります。
ただし、SQSのこれらの値は分散システム上のおおよその値です。
12. 件数と待ち時間を組み合わせる
性能監視では、
ApproximateNumberOfMessagesVisibleだけを見て、
キューが多いから異常とは限りません。
例えば、
一時スパイク
↓
処理待ち 50,000件
↓
数十秒で急速に減少なら、設計どおりかもしれません。
一方、
処理待ち件数増加
+
ApproximateAgeOfOldestMessage増加が続くなら、
処理側が追いついていない可能性が高くなります。
したがって、
バックログ件数
+
バックログの待ち時間を組み合わせて判断します。
13. 処理側をバックログに合わせてスケールする
Amazon SQSをEC2ワーカー群で処理する場合、
CPU使用率だけを見ても適切にスケールできないことがあります。
例えば処理側が、
外部API待ち
データベースI/O待ちを多く含むなら、
CPU 30%でもキューが増え続ける可能性があります。
この場合は、
キューにどれだけ仕事が残っているかをスケーリング判断へ使います。
14. バックログ / インスタンスで考える
EC2 Auto Scalingでは、SQSのバックログをワーカー数で割った、
インスタンスあたりバックログを利用できます。
基本式は、
ApproximateNumberOfMessagesVisible
÷
InServiceのインスタンス数です。
例えば、
バックログ
4,000件
処理側
20台なら、
4,000
÷
20
=
200件 / インスタンスです。
単純なキュー全体件数より、
1台あたり
どの程度の仕事を抱えているかを見られます。
15. 許容バックログをレイテンシーから逆算する
さらに、
許容できる待ち時間
÷
1件の平均処理時間から、1台あたりの許容バックログを求められます。
例えば、
許容待ち時間
20秒
1件の平均処理時間
0.2秒なら、
20
÷
0.2
=
100件です。
つまり、
100件 / インスタンス程度を目標値としてスケーリングを設計できます。
現在、
200件 / インスタンスなら、
許容値100
を超えている
↓
処理側を増やすという判断ができます。
16. 処理側を増やせばよいとは限らない
キューが増えたとき、
処理側を最大まで増やすことが常に正解ではありません。
例えば、
Amazon SQS
↓
Lambda
↓
RDSで、RDSが安全に処理できる同時接続数が100なのに、
Lambda
1,000同時実行まで増やすと、
SQSのバックログは減る
しかし
RDSが過負荷になる可能性があります。
したがって処理側のスケーリングでは、
処理側自身の能力
+
下流システムの安全な処理能力の両方を確認します。
17. Lambda + SQSでは同時実行数を制御できる
Amazon SQSをLambdaのイベントソースとして利用する場合、Lambdaはメッセージ量に応じて処理をスケールできます。
一方、
下流DBは100並列まで
外部APIは50並列までのような制約があるなら、
最大同時実行数を使って、1つのSQSイベントソースから起動されるLambdaの同時実行数を制限できます。
この場合、
トラフィックスパイク
↓
SQSのバックログ増加
↓
処理側は安全な上限で処理とし、下流を急激な並列実行から保護できます。
18. バックプレッシャーとは何か
バックプレッシャー(Backpressure)は、
後段が処理できない速度で
前段から要求を流し続けないための考え方です。
例えば、
送信側
5,000件 / 秒
処理側
1,000件 / 秒が長時間続いているのに、
送信側
そのまま5,000件 / 秒で投入し続ければ、バックログは増え続けます。
この場合、
一時的にはSQSで吸収できても、最終的には、
処理側を増強
処理を高速化
送信側を抑制
新規要求の受付を制御などが必要になります。
19. バッファとバックプレッシャーは同じではない
バッファは、
一時的に待たせる場所です。
バックプレッシャーは、
処理能力を超えた要求が
無制限に流れ続けないようにする考え方です。
したがって、
バッファあり
=
バックプレッシャー不要ではありません。
例えば、
送信側
10,000件 / 秒
処理側
1,000件 / 秒
これが永続なら、巨大なバッファがあっても根本問題は残ります。
20. バッファリングとスロットリングを使い分ける
処理能力を超えた要求への代表的な対応には、
バッファリングと、
スロットリング(Throttling)があります。
バッファリングは、
要求を受け付ける
↓
後で処理する方式です。
一方、スロットリングでは、
今は受け付けられない
↓
後でもう一度試してもらうという制御を行います。
例えば、
非同期で後から処理してよい
+
要求を一度受け付けたい
↓
バッファが有力です。
一方、
送信元が再試行できる
+
後段へこれ以上流したくない
↓
スロットリングを評価できます。
21. バッファはレスポンス要件も変える
バッファを挟むと、
要求受付完了と、
実処理完了が別の時点になります。
例えば、
画像アップロード
↓
SQSへ受付
↓
「処理を受け付けました」
↓
後から画像変換なら適しています。
しかし、
決済処理が成功したか確認してから
注文成功を返すなど、結果を同期的に必要とする処理では、
SQSへ入れた時点
=
業務処理成功とはできません。
したがって、バッファリングを選ぶ前に、
非同期化できる処理かを確認します。
22. バックログが減る速度を計算する
スパイク終了後のバックログ解消時間も重要です。
例えば、
残バックログ
200,000件
送信側
500件 / 秒
処理側
1,500件 / 秒なら、処理側の処理能力すべてをバックログへ使えるわけではありません。
毎秒500件の新しい要求も到着するため、
1,500
-
500
=
1,000件 / 秒が実際にバックログを減らせる速度です。
したがって、
200,000
÷
1,000
=
200秒で解消できます。
23. 「キューがあるから大丈夫」ではない
Amazon SQSは大量のメッセージを保持できますが、バッファ設計では、
最大停止時間
+
復旧後に追いつく時間
+
許容処理遅延を考える必要があります。
例えば、
処理側停止
↓
大量のバックログ
↓
処理側復旧しても、
送信側と同じ速度でしか処理できなければ、
バックログは永遠に減らないことになります。
復旧後には、
送信側の到着速度
<
処理側の処理能力となる余力が必要です。
24. キャッシュとバッファを分ける
キャッシュは、
過去に取得 / 生成した結果
を再利用する仕組みです。
バッファは、
まだ処理していない要求
を待たせる仕組みです。
例えば、
同じ商品情報を
何度も読みたい
↓
キャッシュですが、
注文が一時的に急増
+
後段が一度に処理できない
↓
バッファです。
25. シナリオ1:短時間だけ10倍の要求が来る
要件:
通常
500件 / 秒
キャンペーン開始時
5,000件 / 秒
処理側
1,000件 / 秒
処理は非同期可能この場合、
送信側
↓
Amazon SQS
↓
処理側群を評価します。
SQSで一時的な差分を保持し、
スパイク終了後
処理側がバックログを処理できるようにします。
重要なのは、
スパイクが終わった後に
バックログを減らせる余力があることです。
26. シナリオ2:バックログが一日中増えている
要件:
送信側
2,000件 / 秒
処理側
1,500件 / 秒
24時間継続
処理待ち件数
増加
最古メッセージの待ち時間
増加この場合、
SQSを追加するだけでは解決しません。
処理側の増強
+
処理時間短縮
+
送信側の抑制などによって、
長期平均の処理能力
>=
長期平均の到着量へ戻す必要があります。
27. シナリオ3:CPUは低いのにキューが増える
要件:
EC2処理側群
CPU
30%
SQSバックログ
増加
最古メッセージの待ち時間
増加
処理の多くは外部I/O待ちこの場合、
CPU 30%
だから
スケールアウト不要とは判断できません。
SQSバックログ
÷
稼働中の処理側数のように、実際の未処理仕事量に比例する指標を使ってスケーリングを評価します。
28. シナリオ4:処理側を増やすとDBが落ちる
要件:
SQS
↓
Lambda
↓
RDS
RDS安全上限
100同時処理
トラフィックスパイク時
Lambdaが急速に増えるこの場合、
キューを最速で空にすることだけを目標にしません。
処理側の同時実行数を
下流が安全に処理できる範囲へ制限し、
余った要求
↓
SQSで一時的に待機させます。
これは、
バックログを許容することで
下流システムを守る設計です。
29. 混同ポイント
| 混同 | 正しい判断 |
|---|---|
| SQSを入れれば処理側が高速になる | SQSは処理速度そのものを上げるわけではない |
| キューに保持できるなら処理能力不足は解決済み | 恒常的に送信側 > 処理側ならバックログは増え続ける |
| トラフィックスパイクでは常に最大台数を常時起動する | 非同期処理ならバッファでピークを時間方向へ平準化できる |
| キューの件数だけ見ればよい | 最古メッセージの待ち時間も見る |
| CPUが低ければ処理能力は十分 | I/O中心の処理ではバックログ基準のスケーリングが適する場合がある |
| 処理側は増やせるだけ増やす | 下流DBや外部APIの安全な処理能力も確認する |
| バッファとバックプレッシャーは同じ | バッファは待機場所、バックプレッシャーは流入を制御する考え方 |
| バッファは永続的な処理能力不足も解決する | 長期平均で処理側が追いつけなければ別の対策が必要 |
| キャッシュとバッファは同じ | 再利用する結果と未処理要求では目的が異なる |
30. SAP-C02での判断フロー
性能問題
↓
要求量が一時的に急増している?
│
├─ いいえ
│ ↓
│ 恒常的な処理能力不足を評価
│
└─ はい
↓
処理を非同期化できる?
│
├─ いいえ
│ ↓
│ 同期経路のスケーリング等を評価
│
└─ はい
↓
Amazon SQS
↓
バッファリング
↓
送信側の到着速度
と
処理側の処理能力
を比較
↓
ApproximateNumberOfMessagesVisible
+
ApproximateAgeOfOldestMessage
を監視
↓
一時的なバックログ?
│
├─ はい
│ ↓
│ 処理側が後から解消可能か確認
│
└─ いいえ
↓
処理側の増強
処理高速化
送信側の抑制
バックプレッシャー
↓
処理側を増やしても
下流は安全?
│
├─ はい
│ ↓
│ キューバックログに応じてスケール
│
└─ いいえ
↓
処理側の同時実行数を制限
SQSで一時待機
↓
性能目標を満たすかまとめ
バッファリングで重要なのは、
Amazon SQSを使うことそのものではありません。
判断の中心は、
送信側
と
処理側
の処理速度差です。
一時的に、
送信側
>
処理側になるなら、
Amazon SQS
↓
バッファ
↓
後から処理によってトラフィックスパイクを平準化できます。
ただし、
送信側
>
処理側が永続するなら、
バッファだけでは解決しないことが重要です。
性能状態は、
ApproximateNumberOfMessagesVisible
+
ApproximateAgeOfOldestMessageなどで確認し、
処理側のスケーリング
+
下流システムの処理上限
+
バックプレッシャーまで設計します。
最終的には、
一時的なスパイク
→ バッファ
バックログ増加
→ 処理側の能力を確認
待ち時間増加
→ スケール / 高速化
下流が限界
→ 同時実行数を制御
恒常的に到着量が多い
→ 送信側の抑制も検討という判断ができることが目標です。
主要AWS公式資料
- AWS Certified Solutions Architect - Professional 試験ガイド
- Amazon SQS — 標準キュー
- Amazon SQS — CloudWatchメトリクス
- Amazon SQS — メッセージ処理に必要なリソース
- Amazon EC2 Auto Scaling — Amazon SQSに基づくスケーリングポリシー
- AWS Lambda — SQSイベントソースマッピングのスケーリング
- AWS Well-Architected Framework — バッファリングまたはスロットリングによる需要曲線の平準化
理解確認
このページの内容を9問で確認します。
理解確認9問へ →