[アップデート] Amazon SQS でマルチテナントのノイジーネイバー発生を抑制できる「フェアキュー」という機能が使えるようになりました。
いわさです。
Amazon SQS にとてもおもしろいアップデートが来ましたね。フェアキューという機能が使えるようになりました。
マルチテナントのプールモデルでシステムを構築すると複数のテナントでリソースを共有して使う形になりますが、その際にノイジーネイバー問題が生じます。
ノイジーネイバーというのはある使用量の大きなテナントが、他の使用量の少ないテナントに影響を及ぼす事象のことです。
特にマルチテナント SaaS などではこのノイジーネイバー問題を考慮した設計をしないと、運用後に問題が出ることが多いです。
これまで SaaS on AWS ではプールモデルの場合はキューメッセージの消費スピードを上げるか、ティアリングなどと組み合わせて複数のキューに分離させる方法などを取ることが多かったです。
いずれの場合でも一定の効果はありますが、アーキテクチャやアプリケーション実装が少し複雑になりがちでした。
今回のアップデートで、単一のキューの中でメッセージごとにテナントを自動で識別し、負荷の高いテナントをノイジーと判断してメッセージ消費の優先度をコントロールしてくれるようです。
公式ドキュメントの内容がイメージしやすいと思うのですが、ノイジーネイバーが発生していると、消費時にはそれ以外のテナントのメッセージが優先的に返されます。これによって特に難しいことをせずに他テナントへの影響を抑えることが出来ます。
Amazon SQS fair queues - Amazon Simple Queue Service より、ノイジネイバーが発生している様子(従来)
Amazon SQS fair queues - Amazon Simple Queue Service より、ノイジネイバーが抑制された様子(フェアキュー)
今回完全にうまくは動作しなかったのですが、検証の様子を紹介します。
使い方
標準キューと FIFO キューに加えてフェアキューというキュータイプが登場したわけではありません。
また、有効化なども特にキューの設定として用意されていないです。アップデートのバナーは出ていました。
使用方法ですが、標準キューにメッセージを送信する際にメッセージグループ ID を指定します。このメッセージグループ ID にテナント識別子を指定することでテナントごとのメッセージとして判定してくれるようです。
従来は FIFO キューのみで使うことが出来ていたメッセージグループ ID を標準キューでも指定できるようになりました。
検証してみた
標準キューを作成し、テナント ID をメッセージグループ ID として指定するスクリプトを作成して実行してみました。
スクリプトの内容は省略しますが、次のようにテナント1で大量にメッセージを送信し、テナント2とテナント3では少量のメッセージを送信するようなスクリプトです。
% python message_sender.py
=== ノイジーネイバー問題再現テスト ===
キューURL: https://sqs.ap-northeast-1.amazonaws.com/123456789012/hoge0723fairqueue2
テナント1: 1000件(ノイジーネイバー)
テナント2: 1件
テナント3: 1件
📤 ステップ1: テナント1(ノイジーネイバー)のメッセージ送信開始
[05:32:06] tenant-1: 1000件のメッセージ送信開始
[05:32:11] tenant-1: 100/1000 送信完了
[05:32:16] tenant-1: 200/1000 送信完了
[05:32:22] tenant-1: 300/1000 送信完了
[05:32:27] tenant-1: 400/1000 送信完了
[05:32:33] tenant-1: 500/1000 送信完了
[05:32:38] tenant-1: 600/1000 送信完了
[05:32:43] tenant-1: 700/1000 送信完了
[05:32:49] tenant-1: 800/1000 送信完了
[05:32:54] tenant-1: 900/1000 送信完了
[05:32:59] tenant-1: 1000/1000 送信完了
[05:32:59] tenant-1: 送信完了 (1000/1000)
✅ テナント1送信完了: 1000件
⏳ 2秒待機後、テナント2、3のメッセージを送信...
📤 ステップ2: テナント2、3のメッセージ送信開始
[05:33:01] tenant-2: 1件のメッセージ送信開始
[05:33:01] tenant-3: 1件のメッセージ送信開始
[05:33:01] tenant-2: 送信完了 (1/1)
[05:33:01] tenant-3: 送信完了 (1/1)
🎉 全メッセージ送信完了: 55.60秒
- テナント1: 1000件(先行送信)
- テナント2: 1件(後続送信)
- テナント3: 1件(後続送信)
そして、今回のアップデートで CloudWatch に いくつか新しい SQS メトリクスが追加されています。
まず上記機能を使ってノイジーネイバーだと判断されたテナントが発生すると、ApproximateNumberOfNoisyGroups
としてカウントされます。閾値や条件は公式ドキュメントに明記されていないのですが、よくわからんがノイジーなテナントがひとつ発生していると認識してくれたみたいです。
そして、従来ApproximateNumberOfMessagesVisible
などでキューメッセージの数を見てコンシューマ側をスケーリングさせたりすることがあったと思うのですが、これらのメトリクスにあらたにInQuietGroups
というサフィックスが付与されたメトリクスが追加されています。
InQuietGroups
系のメトリクスはノイジーネイバーテナントを除外した値を得ることが出来ます。
ノイジーネイバーの恐れのあるテナントではスロットリングを適用したいことがあるので、ノイジーネイバー発生時に全体を見てスケーリングさせるとインフラコストが増大してしまう可能性があります。ノイジーなテナントに多すぎる使用量に応じた制限をかけつつ、他のテナントに影響のないようにシステムモニタリングを行いたい用途で使えるメトリクスというところでしょうか。
ただ、私が試した際にはうまく除外してくれず、ノイジーなテナントのメッセージも含めてInQuietGroups
メトリクスに表示されてしまいました。ノイジーネイバーが発生してから少し時間を置くとか何か条件が必要だったのだろうか。
以下はツールでメッセージ消費タイミングを可視化したものです。
標準キューなのでそもそも保証されていませんが、メッセージの送信順序としてはテナント1が完了した後にテナント2とテナント3を送信しています。
これを見ると、どうなんでしょう。一応テナント2が早めに取り出しされているようにも見えますが、微妙ですね。ちょっと検証方法が悪かったかもしれないです。
さいごに
本日は Amazon SQS でマルチテナントのノイジーネイバー発生を抑制できる「フェアキュー」という機能が使えるようになりました。
マルチテナントワークロードに SQS を組み込む際に、ノイジーネイバーを抑える新しい選択肢が登場しましたね。
今回検証がうまく行かなかったですが、意図どおり動作する場合は簡単に使えるうえにかなり効果の高い機能だと思います。
もう少し検証頑張ってみようかな。