kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

SQS にポイズンピルメッセージがあると ApproximateAgeOfOldestMessage の値が正しくなくなる可能性がある

ApproximateAgeOfOldestMessage とは?

SQS には ApproximateAgeOfOldestMessage というメトリクスがあり,CloudWatch でモニタリングをすることができる.なお,SQS の歴史を考えると比較的最近に追加されたメトリクスで,2016年8月にリリースされている.

ApproximateAgeOfOldestMessage の意味を公式ドキュメントから引用すると,以下の通りとなる.ようするに,SQS に登録されているメッセージの中で「最も古い」メッセージの「登録されてからの経過時間(秒)」と言えるため,例えば SQS をポーリングするようなアプリケーションが障害で停止しているような場合は ApproximateAgeOfOldestMessage の値が増えるため,異常を検知することができる.

キューで最も古い削除されていないメッセージのおおよその経過期間。

docs.aws.amazon.com

逆に,夜間帯にポーリングしないという仕様のアプリケーションだった場合は,夜間帯に ApproximateAgeOfOldestMessage の値が増えて(期待値),翌朝にポーリングをすると ApproximateAgeOfOldestMessage の値が 0 に戻る(期待値).実際にこのようなアプリケーションを運用していて,以下のようなグラフになっている.

f:id:kakku22:20180106235238p:plain

(夜間帯にポーリングを止めている状態)

最近起きた事象

最近,特定のメッセージがアプリケーションでエラーになり,可視性タイムアウト (Visibility Timeout) が終了したら SQS にメッセージが戻されて,リトライを繰り返す状況が起きていた.アプリケーションのバグは想定していたため,このような状況を ApproximateAgeOfOldestMessage の値で検知するはずだったけど,なぜか ApproximateAgeOfOldestMessage の値が定期的に下がってしまうという事象が起きた.なお,参考のために SQS の設定を一部抜粋する.

  • 可視性タイムアウト : 30分
  • DLQ (Dead-Letter Queue) : 設定なし
  • ApproximateAgeOfOldestMessage の CloudWatch アラーム : 設定あり

以下のグラフを見るとわかる通り,なぜか「90分間隔(可視性タイムアウトとも関連性がない)」ApproximateAgeOfOldestMessage の値が下がってしまっていた.また,アプリケーション側のリトライによってメッセージの受信数も増えていて,SQS に登録されてからの経過時間は ApproximateAgeOfOldestMessage の値よりもずっと長かったため,ずっと線形に値が増えていくことを想定していた.

もう1度 ApproximateAgeOfOldestMessage の定義を振り返ると「キューで最も古い削除されていないメッセージのおおよその経過期間」なので,勝手に下がってしまうというのは変だなと感じて,AWS サポートに問い合わせた.

f:id:kakku22:20180106235247p:plain

(定期的に ApproximateAgeOfOldestMessage の値が下がってしまった状態)

ポイズンピルメッセージがあると ApproximateAgeOfOldestMessage の値が正しくなくなる可能性がある

AWS サポートに問い合わせてわかった結論としては,ポイズンピルメッセージ(アプリケーションでエラーになって SQS に戻ったメッセージのこと)があると ApproximateAgeOfOldestMessage の値が「正しくなくなる可能性がある」という仕様だった.メトリクスのドキュメントには載っていなかったけど,以下の「全般的な推奨事項」には確かに載っていた.これって結構知られている仕様?

キューにポイズンピルメッセージを含めると、ポイズンピルメッセージの誤った経過期間を指定することで、ApproximateAgeOfOldestMessage CloudWatch メトリクスが正しくなくなる可能性があります。デッドレターキューを設定すると、このメトリクスを使用する場合の誤ったアラームの回避に役立ちます。

docs.aws.amazon.com

ドキュメントを見ると,今回の件は「DLQ を活用して回避する」と載っているけど,例えば DLQ を活用するとしても最大受信数を設定して DLQ に飛ばすため,DLQ を活用したからと言ってポイズンピルメッセージを撲滅できるわけではないと理解している.そういう意味で,今回の件を通して感じたのは ApproximateAgeOfOldestMessage のモニタリングに頼りすぎるのは危険だと思った.あくまで ApproximateAgeOfOldestMessage は参考値として考えて,DLQ の ApproximateNumberOfMessagesVisible などのメトリクスをモニタリングした方が良さそう.

まとめ

  • SQS のメトリクス ApproximateAgeOfOldestMessage の値は,ポイズンピルメッセージがあると「正しくなくなる」可能性がある
    • ドキュメントに載っている「正しくなくなる」は,今回の事象では「定期的に値が下がる」だった
    • メトリクスのドキュメントにはその仕様が載っていないため注意する
  • モニタリングをする場合は ApproximateAgeOfOldestMessage の値ではなく,DLQ を用意して ApproximateNumberOfMessagesVisible などを活用する
  • 今まで知らなかった SQS の仕様を勉強できて良かった👍