Amazon SQS

##■検討すること##

|× |〇 |
|---|---|
|**ストリーミング方式**<br>続的にデータを送る方式。データ間に順序性等の意味があり、まとめて処理する方式|**メッセージング方式**<br>メッセージ間に連続性等の意味をもたせず単体で処理をする方式|
|**同期方式**<br>リクエスタがプロバイダの処理完了までの応答を待つ方式 |**非同期方式**<br>リクエスタが処理完了の応答を待たずに後続の処理を実施する方式 |
|**Push方式**<br>プロデューサがメッセージを送信するとコンシューマに届く方式 |**Pull方式**<br> コンシューマがメッセージを要求することで受領する方式|
|**Publish Subscribe方式**<br>1つのメッセージを複数のコンシューマが受信する方式 |**P2P**<br>プロデューサとコンシューマが1対1で連携する方式|

※なお、ストリーミング方式の場合はAmazon kinesisを検討する。


##■Amazon SQSとは##
処理の間にQueueを噛ませることで、非同期処理にすることができる。
例えば全ての処理を同期処理してしまうと時間がかかってしまうので、Queueだけ登録してレスポンスを返してしまう。
![スクリーンショット 2019-03-23 18.29.18.png](https://qiita-image-store.s3.amazonaws.com/0/280929/46112362-f4c6-4334-d0e8-cbffb9f3ba36.png)


##■機能##

###1.ショートポーリングとロングポーリング###

通常はロングポーリングを利用する。

|ショートポーリング|ロングポーリング|
|-----|-----|
|即応答。メッセージがない場合は「空」を応答。 |最大20秒待つ。メッセージがない場合はタイムアウト。|
|分散されたサーバの中からサンプリングされたサーバのメッセージを応答。全サーバではないため取得できないこともある。 |全てのサーバをクエリしメッセージを応答。 |
|繰り返し実施する場合、APIコール数が増え利用料金が増加する傾向有。 |APIコール数が抑制できるため、利用料金が安価になる可能性有。 |

###2.可視性タイムアウト###

一定期（デフォルト30秒）、同じメッセージを他のコンシューマから見えないようにする。
SQSからのメッセージを受信するシステムが複数ある場合、あるシステムでメッセージを受信した後に、明示的に削除しない限りキューに残る。
これにより、他のシステムが二重に受け取らないようにする。

###3.遅延キュー###

メッセージをキューに送信してから一定時間経過後に利用可能になる機能。（可視性タイムアウトは受信後であるところが違います。）

###4.デッドレターキュ###

いつまでも残るメッセージを削除するのではなく、別のキューに移動する。　


##■制限##

- キューに格納できる１メッセージあたりのサイズは最大256KB。ただし、拡張クライアントライブラリを利用することで最大２GBまで。
- メッセージの送受信は、１APIリクエストあたり最大１０件。
- キューには、デフォルトで４日間メッセージが保存される。設定により６０秒から１４日間までの保存期間が可能。


##■スタンダードキューとFIFOキュー##

|スタンダードキュー|FIFOキュー|
|----------|-----------|
|少なくとも1回の配信|1回のみ配信| 
|順序は保証されない。なんだかのタイミングで同じメッセージを複数回受信する場合がある。|順序を保つ|
 　
![スクリーンショット 2019-03-23 18.44.18.png](https://qiita-image-store.s3.amazonaws.com/0/280929/4490ed14-d31b-3f85-bfe8-f0918f4414c8.png)

##高スループットモード（FIFOキュー）##

[Amazon SQS が FIFO キューの高スループットモードをサポート開始 (プレビュー版)](https://aws.amazon.com/jp/about-aws/whats-new/2020/12/amazon-sqs-supports-high-throughput-fifo-queues-preview/)

- FIFO キューの高スループットモードで、API アクションごとに 1 秒あたり最大 3000 件のメッセージを処理できるようになりました。これは、現在の SQS FIFO キュースループットクォータと比較して、10 倍増加しています。
- キューごとではなく、メッセージグループIDごとに重複排除が行われる。（メッセージグループごとにすることでスループットをあげているので、高スループットを利用する場合は必須である。）
- 設定は 次のように高スループット FIFO オプションを有効にするだけです。

![スクリーンショット 2020-12-30 17.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/550e1f98-730a-2bcb-07d8-691fcac2972d.png)

##■ユースケース##

- 一時的なリクエスト増の均一化 
- アプリケーションの依存関係を弱めたい場合
- 重い処理の切りだしによる応答性の改善
- SNSとの組み合わせによる処理の並列化


##■リンク##
[SQSのメッセージをトリガーにLambdaを起動する](https://qiita.com/leomaro7/items/28d646bb34f9a244c24f)
[SQS - FIFOキューの重複排除ID](https://qiita.com/leomaro7/items/47fcb468932438fab469)


##1.キューを作成する##
[キュー名]だけ入力し、パラメータはデフォルトで作成する。
（標準キーで作成する）
![スクリーンショット 2019-03-23 18.45.59.png](https://qiita-image-store.s3.amazonaws.com/0/280929/1227e426-0054-e84e-1435-40a4bb9f80e7.png)


##2.マネージメントコンソールからメッセージを送受信する##

[キュー操作]から[メッセージの送信]
![スクリーンショット 2019-03-23 18.47.46.png](https://qiita-image-store.s3.amazonaws.com/0/280929/53ae546e-4cab-f406-33f3-d0ab83d11c08.png)

2つメッセージを作成してみます。

　メッセージ本文:test

　メッセージ本文：test2
　メッセージ属性：名前(key), タイプ(String),値（value）

![スクリーンショット 2019-03-23 18.49.36.png](https://qiita-image-store.s3.amazonaws.com/0/280929/01767f23-b9a2-7c95-282f-24cd9a175df3.png)

キューに2つあることがわかります。
![スクリーンショット 2019-03-23 18.54.26.png](https://qiita-image-store.s3.amazonaws.com/0/280929/e031ac98-f202-be1b-7a3f-0b765de3554b.png)

[キュー操作]から[メッセージの表示/削除]
![スクリーンショット 2019-03-23 18.55.57.png](https://qiita-image-store.s3.amazonaws.com/0/280929/d3c9b283-6c30-d635-3ac8-bdf397c2fb4b.png)

[メッセージのボーリングを開始]を押すと先ほど作成した2
つのメッセージが受信されていることがわかる。
![スクリーンショット 2019-03-23 18.57.24.png](https://qiita-image-store.s3.amazonaws.com/0/280929/2b75ff09-4af0-b855-38e4-70b2aa0506f4.png)

ただし、マネージメントコンソールからの操作はキューを詰め込むことはあっても受信するという操作はあまりない。


##3.SDK for PHP でメッセージを送受信する##

```php:SendQueue.php
SendQueue.php 
<?php
require '../vendor/autoload.php';

use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;

date_default_timezone_set('Asia/Tokyo');

$client = new SqsClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-11-05'
]);

$params = [
    'MessageAttributes' => [
        "Sender" => [
            'DataType' => "String",
            'StringValue' => "ketancho"
        ]
    ],
    'MessageBody' => date('YmdHis'),
    //TODO: Queue の URL を記載する
    'QueueUrl' => '***'
];

try {
    $result = $client->sendMessage($params);
    var_dump($result);
} catch (AwsException $e) {
    error_log($e->getMessage());
}
```

php SendQueue.php を実行してみる。

```
vim php SendQueue.php 
object(Aws\Result)#142 (2) {
  ["data":"Aws\Result":private]=>
  array(4) {
    ["MD5OfMessageBody"]=>
    string(32) "88fcc276b82edad126cc8d8a71adb831"
    ["MD5OfMessageAttributes"]=>
    string(32) "cb369c99da64119aab2384a948af506c"
    ["MessageId"]=>
    string(36) "6a4a6716-a2ea-4cb2-8b4a-2aa4340a72e0"
    ["@metadata"]=>
    array(4) {
      ["statusCode"]=>
      int(200)
      ["effectiveUri"]=>
      string(62) "https://sqs.ap-northeast-1.amazonaws.com/268546037544/demo-sqs"
      ["headers"]=>
      array(4) {
        ["x-amzn-requestid"]=>
        string(36) "d6f69a23-fad5-5bb6-82af-cf33f262a6f6"
        ["date"]=>
        string(29) "Sat, 23 Mar 2019 10:12:07 GMT"
        ["content-type"]=>
        string(8) "text/xml"
        ["content-length"]=>
        string(3) "459"
      }
      ["transferStats"]=>
      array(1) {
        ["http"]=>
        array(1) {
          [0]=>
          array(0) {
          }
        }
      }
    }
  }
  ["monitoringEvents":"Aws\Result":private]=>
  array(0) {
  }
}
```

```php:ReceiveQueue.php 
vim ReceiveQueue.php 
<?php
require '../vendor/autoload.php';

use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;

//TODO: Queue の URL を記載する
$queueUrl = "***";

$client = new SqsClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-11-05'
]);

try {
    $result = $client->receiveMessage(array(
        'AttributeNames' => ['SentTimestamp'],
        'MaxNumberOfMessages' => 1,
        'MessageAttributeNames' => ['All'],
        'QueueUrl' => $queueUrl, // REQUIRED
        'WaitTimeSeconds' => 0,
    ));
    if (count($result->get('Messages')) > 0) {
        var_dump($result->get('Messages')[0]);
        $result = $client->deleteMessage([
            'QueueUrl' => $queueUrl, // REQUIRED
            'ReceiptHandle' => $result->get('Messages')[0]['ReceiptHandle'] // REQUIRED
        ]);
    } else {
        echo "No messages in queue. \n";
    }
} catch (AwsException $e) {
    // output error message if fails
    error_log($e->getMessage());
}
```

php ReceiveQueue.php を実行する

```
php ReceiveQueue.php 
array(7) {
  ["MessageId"]=>
  string(36) "6a4a6716-a2ea-4cb2-8b4a-2aa4340a72e0"
  ["ReceiptHandle"]=>
  string(412) "AQEBWpLLVfMBwxeVBxkn+I4rTIIqCuLXR+G1rYoWqCrmyiIY1lI3kWwsPd7F1Ai12IYUInDomtw09Z+EQFVE+nsogXOooadkdN8NDQ8B2wHjLZ/X8DaBDCuKGCsUQ9TwZ5/Kjq2rM9vfrboq8KBgkdV+I+ZXVAvmPOoLk+YSMhohw07vZjnwMmB1beenTV8O+/yXXGIaCwwc0lRmcM8eRCmaYz1++jTn2SIEbIL9L9tkAqBtU07UOkBSTUUyeHd+/Nap/QlA4+dnLEhW+ygUS9aN6ppPnK5Gk53vVrQyRs386oDR7gJ6Xa8DKALKPpReq5jED6yL3x0WJc5ljgeVvgyyN9ILWkXvZikF1JWIvD8ne1rWRWEAeurxnOYrMP0fKQSkM21vOLZ2P7VUWHUrLoKncQ=="
  ["MD5OfBody"]=>
  string(32) "88fcc276b82edad126cc8d8a71adb831"
  ["Body"]=>
  string(14) "20190323191207"
  ["Attributes"]=>
  array(1) {
    ["SentTimestamp"]=>
    string(13) "1553335927345"
  }
  ["MD5OfMessageAttributes"]=>
  string(32) "cb369c99da64119aab2384a948af506c"
  ["MessageAttributes"]=>
  array(1) {
    ["Sender"]=>
    array(2) {
      ["StringValue"]=>
      string(8) "ketancho"
      ["DataType"]=>
      string(6) "String"
    }
  }
}
```


##4.AWS CLI での操作##


###4-1キューの作成###

```
[ec2-user@ip-10-0-0-235 ~]$ aws sqs create-queue --queue-name test
{
    "QueueUrl": "https://ap-northeast-1.queue.amazonaws.com/268546037544/test"
}
```

キューの作成：作成されたことを確認

```
[ec2-user@ip-10-0-0-235 ~]$ aws sqs list-queues
{
    "QueueUrls": [
        "https://ap-northeast-1.queue.amazonaws.com/268546037544/test"
    ]
}
```

###4-2メッセージの送信###

```
[ec2-user@ip-10-0-0-235 ~]$ aws sqs send-message --queue-url https://ap-northeast-1.queue.amazonaws.com/268546037544/test --message-body 'Hello world'
{
    "MD5OfMessageBody": "3e25960a79dbc69b674cd4ec67a72c62",
    "MessageId": "bf564b0e-4aa8-4d05-adc5-ba3442f0f845"
}
```

###4-3メッセージの受信###

```
[ec2-user@ip-10-0-0-235 ~]$ aws sqs receive-message --queue-url https://ap-northeast-1.queue.amazonaws.com/268546037544/test
{
    "Messages": [
        {
            "Body": "Hello world",
            "ReceiptHandle": "AQEBRbqzo4iFfW19gUVFgsA2pEOQFfnxQBS+40Cl86OY3q34vyyjob99wsKy9FQWOXitze6ZCMr7jZJGAcjyFmSvQO2ey9HGjiCSy3nP4FOZI2g0o9QqJtlUGokOWHzk5N8rZvviXwylk+S+OeyfLfxlVmtpl7xBKrWeKfO7EJ9pDL4mYkVTtLuDMOl/pl9rkXnIRRgvLrCQZfK+WX9cOZtceBdjPsT330b/HG1tLg/j+EHeJ/m8kMvkC2m6jbzKmqwiAYgNZa1YyucCzcUeMBKXFtoyI7sFzpf4domYCxV9zDI2Bqm82MfqoODFRT7yPt9TyW6ZO1Czrp9RhwSvNP1cs4RNBxqRED8q8qf9pUQ41ClqdZtZRPiHAL+MOBATum1FhT0TN4gsG3bdwKG9x8dMDw==",
            "MD5OfBody": "3e25960a79dbc69b674cd4ec67a72c62",
            "MessageId": "bf564b0e-4aa8-4d05-adc5-ba3442f0f845"
        }
    ]
}
```

###4-4メッセージの削除###

```
[ec2-user@ip-10-0-0-235 ~]$ aws sqs delete-message --queue-url https://ap-northeast-1.queue.amazonaws.com/268546037544/test --receipt-handle "AQEBRbqzo4iFfW19gUVFgsA2pEOQFfnxQBS+40Cl86OY3q34vyyjob99wsKy9FQWOXitze6ZCMr7jZJGAcjyFmSvQO2ey9HGjiCSy3nP4FOZI2g0o9QqJtlUGokOWHzk5N8rZvviXwylk+S+OeyfLfxlVmtpl7xBKrWeKfO7EJ9pDL4mYkVTtLuDMOl/pl9rkXnIRRgvLrCQZfK+WX9cOZtceBdjPsT330b/HG1tLg/j+EHeJ/m8kMvkC2m6jbzKmqwiAYgNZa1YyucCzcUeMBKXFtoyI7sFzpf4domYCxV9zDI2Bqm82MfqoODFRT7yPt9TyW6ZO1Czrp9RhwSvNP1cs4RNBxqRED8q8qf9pUQ41ClqdZtZRPiHAL+MOBATum1FhT0TN4gsG3bdwKG9x8dMDw=="
```

##リンク##

https://dev.classmethod.jp/articles/sns-sqs-subscribe-access-policy/