AWS再入門ブログリレー SQS編

2019.07.31

こんにちは、コンサルティング部 もこ@札幌オフィス です!

当エントリは弊社コンサルティング部による『AWS再入門ブログリレー 2019』の22日目のエントリです。

前日は森田 桂介による「DynamoDB」でした。

このブログリレーの企画は、普段AWSサービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、 今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。

AWSをこれから学ぼう!という方にとっては文字通りの入門記事として、またすでにAWSを活用されている方にとってもAWSサービスの再発見や2019年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。

本日22日目のテーマは『Amazon Simple Queue Service』です。

目次

Amazon Simple Queue Service(SQS)とは?

Amazon Simple Queue Service(以下SQS)はフルマネージド型のメッセージキューサービスです。

「メッセージをSQSの送信」、「SQSからメッセージをポーリング」することができ、SQSを利用することによって

  • 軽い受付処理をした結果をSQSに登録し、別のサーバーからメッセージをポーリングし、重い処理を済ませる

  • SQS側で処理予定のタスクをバッファーでき、スパイク的なアクセスに耐えれる構成を作成できる

  • SQSに登録されているキューに基づいてSQSをポーリングし、処理を行うサーバーをスケールする事ができる

  • SQSをトリガーにLambdaをキックし、サーバーレスが捗る

などなどで、お店で例えて言うと

「注文はチーズバーガー→お会計130円です→チーズバーガーを作成→チーズバーガーを返す」

ような同期的なアプリケーションを

「レジ側: 注文はチーズバーガー→お会計130円です(SQSにキューを登録)」

「厨房側: SQSをポーリング、チーズバーガーを作成、チーズバーガーを返す」

のように、レジと厨房を非同期で処理できるため、レジでは注文と会計のみの仕事に集中もできますし、何よりチーズバーガーを作る作業は厨房に丸投げするため、お客様にも待たさずに次々と注文を受け付けられます。

また、キューの量をトリガーにスケールすることも可能です。

前提知識

メッセージをSQSに送信するアプリケーションのことを「プロデューサー」と呼び、

SQSからメッセージをポーリングするアプリケーションのことを「コンシューマー」と呼びます。

SQSに送信できる最大サイズは256KBで、SQS側での最長保持期間は14日です。

SQSのタイプ

SQSには2つの種類があり、「標準キュー」、「FIFOキュー」があります。

標準キュー

「順不同な可能性がある」、「複数回配信される可能背がある」、「ほぼ無制限に送信ができる」、標準的なキューです。

(1, 2, 3, 4)->SQS->(2, 4, 1, 3, 4)

のように順不同で配信される可能性があり、同じメッセージを複数回配信される可能性があります。

複数回同じメッセージを受け取っても悪影響が出ないよう、DynamoDBなどを利用して重複が無いようにする必要があります。

FIFOキュー

「順番配信」、「重複キューの削除」、「一回だけの配信」、「1秒に送信できるキューに制限がある」キューです。

つまり、

(1, 2, 3, 4)->SQS->(1, 2, 3, 4)

となり、DynamoDBなどを利用して重複処理を回避する必要もなくなります!

FIFOキューの制限

SendMessage、ReceiveMessage、DeleteMessageは 300 Message/s

SendMessageBatch、DeleteMessageBatch、ChangeMessageVisibilityBatchを利用すると最大 3000 Message/sとなります。

(SendMessageBatchなどのBatch系では最大10件のメッセージを一つのリクエストで送信することができます)

また、FIFOキューではLambda, SNSなどの連携をサポートしていないため、利用する場合は標準キューを利用する必要があります。

SQSのライフサイクル

SQSには主に「可視性タイムアウト」、「メッセージ保持期間」の設定があります。

可視性タイムアウトは、「コンシューマーがメッセージを受信してから可視性タイムアウトの間、他のコンシューマーなどにキューを配信しない」ものです。

メッセージ保持期間は「SQSにメッセージ保持する期間」で、SQSに登録されてから処理されずにSQSに溜まったメッセージが削除されるまでの期間です。

SQSを使ってアプリケーションを作ってみた

ここまでSQSについて紹介しましたが、実際に使ってみないとよくわからないと思います。

実際にSQSを利用し、「ハンバーガーの注文を受け、厨房で作成する」ものを作ってみたいと思います。

(レジ) ハンバーガーの注文を受け付ける

//@ts-check
const AWS = require("aws-sdk");
const SQS = new AWS.SQS({region: "ap-northeast-1"})

const QueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/queue";

function order(burger, amount) {
const MessageBody = JSON.stringify({burger, amount})
SQS.sendMessage({
MessageBody,
QueueUrl,
}, (err, data) => {
if(err) return console.error(err, err.stack);
console.log(data)
});

}

order("チーズバーガー", 10);

(厨房) ハンバーガーの注文を処理する

//@ts-check
const AWS = require("aws-sdk");
const sqs = new AWS.SQS({ region: "ap-northeast-1" });

const QueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/queue";

const receiveMessage = QueueUrl =>
new Promise((resolve, reject) => {
const params = {
QueueUrl,
MaxNumberOfMessages: 10,
WaitTimeSeconds: 10
};
sqs.receiveMessage(params, (err, data) => {
if (err || !data.Messages) return reject(err);
return resolve(data);
});
});

const deleteMessage = (ReceiptHandle, QueueUrl) => {
const params = {
QueueUrl,
ReceiptHandle
};
sqs.deleteMessage(params, (err, data) => {
if (err) return console.error(err);
console.log("delete queue");
console.log(data);
});
};

const createBurger = burger =>
new Promise(resolve => {
setTimeout(() => resolve("🍔"), 3000);
});

async function main() {
const messageids = [];

while (true) {
const data = await receiveMessage(QueueUrl).catch(console.error);
if (!data) continue;
for (const message of data.Messages) {
// すでに処理済みだったらスキップする
// DynamoDBなどを利用するといい感じにできます。
if (messageids.includes(message.MessageId)) return;

// ハンバーガーを作る
const order = JSON.parse(message.Body);

// 重い処理
console.log(order.burger)
const result = await createBurger(order.burger);
console.log(result)
messageids.push(message.MessageId);

deleteMessage(message.ReceiptHandle, QueueUrl);
}
}
}

main();

標準SQSを利用しているため、実際に利用する場合はDynamoDBを使うなどで受信側で重複を回避する必要があるので、注意が必要です。

まとめ

このように、SQSを利用すると簡単にサービスを分離することができ、AWS側にキューの処理などをまるまる任せられるので、とても便利です!

今回の「AWS再入門ブログリレー」もおかげさまで非常に皆様の高評価を戴いた企画となりました。ご支持戴き誠にありがとうございました!

本リレーを通してAWSのたくさんある様々なサービスに再入門できたなら幸いです!