SQSのバッチアクションAPI (boto3) の効果を確認してみた
Amazon SQS と SNSでは、最大10個のメッセージの同時発信をサポートするAPIが提供されています。
今回、Python用のAWS SDK、Boto3を利用して、SQSのメッセージ送信をバッチ処理するAPI、SendMessageBatch の 効果を確認する機会がありましたので、紹介させていただきます。
検証環境
- Amazon Linux 2023 (ARM) のAMI、「c7g.large」の EC2インスタンスを起動しました。
$ uname -a Linux ip-172-31-2-138.us-west-2.compute.internal 6.1.52-71.125.amzn2023.aarch64 #1 SMP Tue Sep 12 21:41:10 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux $ pip list|grep boto3 boto3 1.28.57 $ python --version Python 3.9.16
- Python3.9、pip、boto3 のインストールを実施、Boto3の実行環境として利用しました。
sudo dnf install python pip -y pip3 install boto3
デミーデータ作成
- OpenSSLコマンドを利用、1行約25KB、1000件のレコードを用意しました。
- 10レコードのサイズは約250KB。 SQSのバッチAPIの上限、256KBに収まる容量としました。
for ((i=0; i<1000; i++)) do openssl rand -hex 13000 >> 1.tmp done
Pythonスクリプト
3種類のPythonスクリプトを用意。 1000メッセージの送信所要時間より、毎秒送信可能なスループットを求めました。
KeepAlive無効
ループ中に都度SQSのコネクションを再接続する、KeepAlive無効なSQSクライアント(プロデューサー)を再現したコードを用意しました。
import boto3 queue_url="https://sqs.us-west-2.amazonaws.com/00000000/test-sqs" f = open('1.tmp', 'r') for a in f: sqs = boto3.client('sqs', region_name='us-west-2') response = sqs.send_message( QueueUrl=queue_url, MessageBody=(a) ) sqs.close() f.close()
通常処理
SQSのコネクションを再利用、1000回 send_message を実行するコードを用意しました。
import boto3 sqs = boto3.client('sqs', region_name='us-west-2') queue_url="https://sqs.us-west-2.amazonaws.com/00000000/test-sqs" f = open('1.tmp', 'r') for a in f: response = sqs.send_message( QueueUrl=queue_url, MessageBody=(a) ) f.close()
バッチAPI
バッチAPI (send_message_batch) を利用。 10件のメッセージを一括して送信する処理のコードを用意しました。
import boto3 sqs = boto3.client('sqs', region_name='us-west-2') queue_url="https://sqs.us-west-2.amazonaws.com/00000000/test-sqs" f = open('1.tmp', 'r') i=0 c=[] for a in f: i+=1 b = {'Id': str(i), 'MessageBody': a} c.append(b) if len(c) >= 10: response = sqs.send_message_batch( QueueUrl = queue_url, Entries = c ) c=[] f.close()
結果
- バッチAPI、10件のメッセージを一括送信する事で、1.76倍のスループット向上が確認できました。
- SQSのコネクションが再利用出来ない場合には、大きくスループットが低下する事が確認できました。
API | スループット(rps) |
---|---|
send_message (都度接続) | 15.71 |
send_message | 71.57 |
send_message_batch | 126.47 |
まとめ
SQS、SNS のメッセージ 送信(プロデューサー)、大量、かつ高いスループットで処理する必要がある場合、 まずバッチAPIの活用をご検討ください。
また、頻繁すぎるSDKの初期化、コネクション設定での利用は、スループットに悪影響を及ぼす場合があります。 特に実行環境として Lambda を利用する場合、初期化コストの高い初期化などの処理は、なるべくハンドラー外で設定いただくことをおすすめします。
CLI
AWS CLIでも、SQSのバッチAPIが効果的である事が確認できました。
send-message
for ((i=0; i<1000; i++)) do openssl rand -hex 13000 >> 1.tmp done time cat 1.tmp | while read a do aws sqs send-message --queue-url ${QueueUrl} --message-body ${a} > /dev/null 2>&1 done real 16m42.909s user 12m51.354s sys 3m3.881s
send-message-batch
TMP1=$(echo '{}' | jq ".QueueUrl|=\"${QueueUrl}\"" | jq ".Entries |= []") TMP2=${TMP1} for ((i=0; i<1000; i++)) do TMP2=$(echo ${TMP2} | jq ".Entries |= .+[{\"Id\": \"${i}\", \"MessageBody\": \"`openssl rand -hex 13000`\" }]" ) if [ `echo ${TMP2} | jq '.Entries| length' ` -eq 10 ] ; then echo ${TMP2} | jq . -c > ${i}.json TMP2=${TMP1} fi done time ls -1 *.json | xargs -P 1 -I{} aws sqs send-message-batch --cli-input-json file://./{} > /dev/null 2>&1 real 0m50.116s user 0m38.918s sys 0m6.713s time ls -1 *.json | xargs -P 2 -I{} aws sqs send-message-batch --cli-input-json file://./{} > /dev/null 2>&1 real 0m25.689s user 0m39.448s sys 0m7.124s