Amazon SQSの標準キューの順序を検証

# はじめに

Amazon SQSの標準キューの順序について、公式の説明では以下のように記載されています。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html#standard-queues-message-order

> スタンダードキューでは、できる限りメッセージの順序を保持しますが、複数のメッセージのコピーが順不同で配信される場合があります。

この”できる限り”が気になってみたので動きを見てみました。

# 得られた知見

- 最初は、順序の初めのほうがとられやすい傾向がある
- 何度も（今回は３度）取得されると、しばらく取得されなくなり、別のメッセージが取得されるようになる
    - しばらくたつと、また取得されるようになる

# やったこと

## 検証設定と予想

- 設定
    - 標準キュー
        - 可視性タイムアウトは３秒
    - １秒ずつ、１つのメッセージを取得
- 予想
    - 標準キューの順序の保持が強ければ強いほど、最初のメッセージばかり取得される
        - 仮に最も強く順序が保持されるならば、（可視性タイムアウトが３秒なので）最初の３つのメッセージのみ取得される、はず

## 検証準備

### SQS作成

標準キューの可視性タイムアウトが３秒であれば、あとは簡易な構成で作成しました。何度も再取得するので、デッドレターキューは設定しないです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c1fc803a-5cf9-12c8-cf45-93b76c7a1195.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/fc6f4faa-395d-8fdf-7df2-525f59cf0eba.png)

### メッセージ登録

0から99までの数値をメッセージとして登録します。以下のコマンドはCloudShellの`python3`で実行しました。(0.5秒のスリープは気持ちの問題です)

```python:メッセージ登録
import boto3
import time

sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='test20230130-standard')

for num in range(100):
  print(num)
  queue.send_message( MessageBody=str(num) )
  time.sleep(0.5)
```

### メッセージ取得

１秒ごとにメッセージを1つ取得するのを1000回繰り返し、ファイルに出力しています。実行中がわかるように標準出力にも出しています。

```python:メッセージ取得
import boto3
import time

sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='test20230130-standard')

with open('outs.txt', 'w') as f:
  for num in range(1000):
    for eachMsg in queue.receive_messages(MaxNumberOfMessages=1):
      print(eachMsg.body)
      f.write("%s\n"%(eachMsg.body) )
    print("-----")
    time.sleep(1)
```
なんとなく、先頭のほうがとられている傾向があるかも、と感じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/784f4879-d304-8717-b241-596cd25e9588.png)


### QuickSightに取り込み

グラフ化するためファイルを少し加工して、QuickSightのデータセットとしました。

- １列目に、何回目のメッセージ取得だったか、を付与
    - 1から1000
- ３列目に、カウント用の列を付与。
    - すべて１にすることで、合計値 = 取得できた回数 になる
- ファイルの先頭に、「０回目の取得」として、「0-99の数値で、カウント列が0」の行を追加
    - グラフにした際、X軸にすべての値を出しておきたかったため
- 「何回目のメッセージ取得だったか」について、10刻み、50刻み、100刻みの列を追加

以下のようなデータになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/955fea04-3b35-7255-dc8c-8dfe989bdd9d.png)


### グラフにて可視化

#### 全体

まずは全体を見てみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/02b795e8-16d6-c9e3-56fa-01ab49998573.png)
全体的にそこそこ取られています。この時点で予想は外れました。

3の倍数の取得が多いようなので、試しに件数でソートしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/e4a02eb8-97a1-a761-d58b-617b9e4780e6.png)
かなりきれいな階段状になっています。

#### 0からN（Nを10刻みで50まで）
0-10
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/652be1b3-0539-1a1c-ace8-ffed0f1410fb.png)
0-20
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c84944d0-e626-46ff-8bc1-6558112b6164.png)
0-30
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/1905c320-21d1-747d-b828-2be6ef547b1a.png)
0-40
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/d68b992a-25fa-157c-53ef-6d060e843f1a.png)
0-50
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/ad33cec1-d04d-ad1f-7ff1-34aab0b4eb6d.png)

早々に3回取得されたメッセージはそれ以上取得されず、他のメッセージが取得され始めたことが見て取れます。

#### 0からN（Nを100刻みで500まで）
0-100
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/ddfa780d-9080-b9bf-16cd-8be9831a80f9.png)
0-200
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/a189d497-12ea-4cab-8815-8dd89f3e5b78.png)
0-300
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/caee18ef-40d7-788b-3ef3-5d91c04ca495.png)
0-400
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/103f4645-6e7d-da0c-f11c-2e6e9ae527b7.png)
0-500
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0be03689-9c43-273e-ce75-db5ef54ef81b.png)

100刻みでみると、さらに顕著に見えてきました。

#### Small Multiplesで可視化

少し前に追加されたSmall Multiplesという機能で、10ずつ,50ずつ,100ずつで、どのようになっているか見てみました。

Small Multiplesについては、以下で紹介されています。

https://dev.classmethod.jp/articles/11-amazon-quicksight-small-multiples-line-bar-pie-charts/


##### 10ずつ
最初の200回を、10ずつに見ていくと、徐々に取得されるメッセージが後ろのほうにずれていっているのがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0d56ac76-5021-b956-71e0-bec4a068088c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0fccd85a-962c-0b39-cac2-286a7499abba.png)

##### 50ずつ
50ずつで見ると、「最初のほうで3回取得されたものはしばらく取得されなくなり、また取得され始める」というのが見えてきた気がします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/463f9e8d-0bfb-6850-a83e-0b8a264196f0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/85e5aeb2-7647-5630-4f79-174abfd6d792.png)

##### 100ずつ
100回ずつでみると、「どの100回においても、3回以上は取得されていない」ということが見えてきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/be9bb692-74f1-56c6-3f5b-02d5ab837faf.png)


# おわりに

一文が気になったことを切欠に見ていったら、興味深い傾向が見えました。
若干の優先度が見て取れますし、再取得時も１回程度であれば優先度がそのままのようでしたので、「多数の並列処理で、高めの優先度のメッセージから処理してほしい」などのケースには使えるかな、と思います。

今回の設定でたびたび見えてきた「3の上限」が、「可視性タイムアウトが３秒」と関係があるかは不明です。なので、追跡して調査される方大歓迎です。