おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

Services_Amazon_SQSを触ってみた

Amazon SQS (Amazon Simple Queue Service) は、Amazonが提供するジョブキューイング用なメッセージ格納のキューです。
ここでは詳しい説明は、省略します。これ単体で使うというよりは、EC2で処理させて、スケーラブルに処理を捌くというのが用途かと思います。

で、これを扱うためのPEARライブラリとして、Services_Amazon_SQSがあります。

2010年1月現在、バージョン0.3がベータ版として提供されています。
また、このPEARパッケージは、いわゆるPEARライブラリのほかに、コマンドラインから実行してSQSを操作できるコマンドラインツールが同梱されています。

ちなみに、AmazonでもPHP用のサンプルコードを提供しています。

まずインストール

PEARコマンドでさっくりインストール。

sudo pear install Services_Amazon_SQS-0.3.0
Password:
Failed to download pear/Crypt_HMAC2 within preferred state "stable", latest release is version 0.2.1, stability "beta", use "channel://pear.php.net/Crypt_HMAC2-0.2.1" to install
Failed to download pear/Net_URL2 within preferred state "stable", latest release is version 0.3.0, stability "beta", use "channel://pear.php.net/Net_URL2-0.3.0" to install
Failed to download pear/HTTP_Request2 within preferred state "stable", latest release is version 0.5.1, stability "alpha", use "channel://pear.php.net/HTTP_Request2-0.5.1" to install
pear/Services_Amazon_SQS requires package "pear/Crypt_HMAC2" (version >= 0.2.1)
pear/Services_Amazon_SQS requires package "pear/Net_URL2" (version >= 0.2.0)
pear/Services_Amazon_SQS requires package "pear/HTTP_Request2" (version >= 0.1.0)
downloading Console_CommandLine-1.1.1.tgz ...
Starting to download Console_CommandLine-1.1.1.tgz (38,054 bytes)
..........done: 38,054 bytes
install ok: channel://pear.php.net/Console_CommandLine-1.1.1

ということで、依存関係のあるパッケージがベータで拾えずに失敗しているので、個別にインストール。

pear install Crypt_HMAC2-beta Net_URL2-beta HTTP_Request2-alpha Services_Amazon_SQS-0.3.0

Amazon SQSの利用登録

SQSは、有償サービスであり、登録が必要です。

から、"Sign Up for Amazon SQS" をクリックして、登録を完了してください。

ちなみに、利用料は、以下となっています。ちょっと試す程度であれば数ドル程度です。

  • リクエスト課金
    • 10000リクエストあたり、0.01ドル
  • 転送料 (IN)
    • 2010年6月30日まで無料
    • 以降は、1GBあたり0.1ドル
  • 転送料 (OUT)
    • 最初の10TBまで 1Gあたり 0.17ドル
    • 10TB〜50TB 1Gあたり 0.13ドル
    • 50TB〜150TB 1Gあたり 0.11ドル
    • 150TB以上 1Gあたり 0.1ドル

コマンドラインツールの実行

コマンドラインツールは、sqsという名前です。コマンドラインツールは、PEARのbin_dirにインストールされますので、以下でパスを調べることができます。

$ pear config-get bin_dir
/path/to/php/bin
設定ファイルの準備

設定ファイルに、Amazonのアクセスキーの設定が必要です。設定してない状態で起動すると、設定ファイルのパスが表示されます。

$ sqs
Access key id is missing from configuration file. Please set your Amazon Web Services 
access key id in the "access_key" field in the file "/path/to/sqs.ini".

ファイルの内容はこのようになっています。

; This file contains the access keys for your Amazon Web Services (AWS) account
; to be used by the PEAR Services_Amazon_SQS package. The Services_Amazon_SQS
; package is fully useable without entering this information but the provided
; 'sqs' command-line application requires this configuration file to be
; completed.
;
; See http://pear.php.net/packages/Services_Amazon_SQS for details.
;
; You can get your AWS access keys by going to http://aws.amazon.com/account/
; and clicking on the 'Access Identifiers' link. To use the SQS, you must
; have signed up for the service at http://aws.amazon.com/sqs/.

; Your AWS Access Key ID. Your Access Key ID identifies you as the party
; responsible for the request.
;access_key = "YOUR-AWS-ACCESS-KEY-HERE"

; Your AWS Secret Access Key ID. Your Secret Access Key ID is used to sign
; requests for web services that require authenticated requests.
;secret_access_key = "YOUR-AWS-SECRET-ACCESS-KEY-HERE"

access_key と secret_access_key の行の先頭のコメント ( ; ) を外して、自身のアクセスキーを入力してください。

起動

起動に成功するとこんな感じで使い方のヘルプができます。

$ sqs
A command-line interface to Amazon's Simple Queue Service (SQS).

Usage:
  /path/to/sqs [options]
  /path/to/sqs [options] <command>
  [options] [args]

Options:
  -c config, --config=config  Find configuration in "config".

Commands:
  create   Creates a new queue with the specified name. The queue may take
           up to 60 seconds to become available.
  delete   Deletes an existing queue by the specified URI. The queue may
           take up to 60 seconds to become unavailable.
  help     Displays an overview of available options and commands, or
           detailed help for a specific command.
  list     Lists available queues. If a prefix is specified, only queues
           beginning with the specified prefix are listed.
  send     Sends input from STDIN to the specified queue. The resulting
           message identifier is displayed on STDOUT.
  receive  Receives a message from the specified queue. The message body is
           displayed on STDOUT. If no message is received, nothing is
           displayed on STDOUT.
  version  Displays version information and exits.

ざっくり訳すと、

$ sqs
Amazon Simple Queue Service (SQS)のコマンドラインインターフェイス

使用法:
  /path/to/sqs [オプション]
  /path/to/sqs [オプション] <コマンド>
  [オプション] [引数]

オプション:
  -c config, --config=config  "config"で指定した設定項目の値を表示

Commands:
  create   指定した名称で新しいキューを作成する。キューが利用可能になる
           まで60秒ほど時間がかかる。
  delete   指定したURIの既存のキューを削除する。キューが利用不能になる
           まで60秒ほど時間がかかる。
  help     利用可能なオプションとコマンドの概要を表示する、もしくは
           指定したコマンドのヘルプを表示する
  list     利用可能なキューの一覧を表示する。prefixを指定した場合、その
           prefixから始まるキューのみを一覧に表示する。
  send     指定したキューへ、標準入力(STDIN)からの入力を送信する。
           結果のメッセージ識別子は、標準出力(STDOUT)に表示される。
  receive  指定したキューからメッセージを受信する。メッセージ本文は、
           標準出力に表示される。もし、メッセージが受信されない場合、
           標準出力には何も表示されない。
  version  バージョン情報を表示する。
キューの作成 (create)

sqs create [キュー名] で作成。

$ sqs create test-queue
Queue "http://queue.amazonaws.com/508403871985/test-queue" has been added. 
It may take up to 60 seconds for the new queue to appear in the list of queues.
キューの作成 (delete)

sqs delete [キューのURI] で削除。

sqs delete "http://queue.amazonaws.com/508403871985/test-queue"
Queue has been deleted. It may take up to 60 seconds for 
the queue list to reflect this change.
キューの一覧表示 (list)

sqs list。要素数と、可視タイムアウト(visibility timeout)が表示される。(visibility timeoutはキューの作成時に、指定できる)

$ sqs list
                                                       ITEMS     VIS.  
QUEUE NAME                                             (APPROX.) TIMEOUT
http://queue.amazonaws.com/508403871985/test-queue          4       30 

visibility timeoutは、キューからデータを取得したときに、そのデータをロックする時間。例えば、クライアントAが、キューからデータ1を取得したタイミングで、visibility timeoutの秒数の間、データ1はロックされ、他のクライアントから取得されたりしない。この間に、クライアントAはデータ処理を行って、データ1を削除する。もし、クライアントAで問題が起きて、visibility timeoutの間に、削除できなかった場合、キューにデータ1は復活する。

キューへの要素の追加 (send)

sqs send [キューのURI] で標準入力で渡したデータをキューに追加。

$ echo 1 | sqs send "http://queue.amazonaws.com/508403871985/test-queue"
2ee91df9-2292-45f2-8c92-76ad2c6b8046
$ echo 2 | sqs send "http://queue.amazonaws.com/508403871985/test-queue"
1e6e135a-b287-41c3-af05-9d9298585ef1

メッセージは最大8KBまで格納できます。追加が成功すると、メッセージIDというのが表示されます。
なお、マルチバイト文字列を送ろうとするとエラーになります。ライブラリの仕様と、SQSの隠れ仕様で、この問題が起きてます。以下は、試しにdateコマンドの出力を流した場合。

date | sqs send "http://queue.amazonaws.com/508403871985/test-queue"
The request signature we calculated does not match the signature you provided. 
Check your AWS Secret Access Key and signing method. Consult the service 
documentation for details.
キューの要素の取得 (receive)

sqs receive [キューのURI] で、データを出力します。また、-d オプションで受信したデータを削除することができます。

$ sqs receive "http://queue.amazonaws.com/508403871985/test-queue"
1
$ sqs receive "http://queue.amazonaws.com/508403871985/test-queue"
2

ライブラリの利用

キューの作成などももちろんできますが、送信と受信処理についてだけ。

受信時の戻り値

receive()は、成功時、以下のような配列を返却します。データが取得できない場合は空配列を受け取ります。

array(1) {
  [0]=>
  array(3) {
    ["id"]=>
    string(36) "f6f79090-8a26-469f-89a3-2162c571f7e5"
    ["body"]=>
    string(2) "2
"
    ["handle"]=>
    string(172) "+eXJYhj5rDri2De+UILzboaz4QxJnnN7vk0KSUVNAbl0DJ3gVOmjI2Gh/oFnb0IeJqy5Zc8kH4JWc6Thp2AWPDaAPSeOkXQZMXPJOvFfdxLavSb3vNGeNOxBMZZJvVmtx3TOK4vrk/uogD2VS+quUjQ5YSB3Eu3zxQj1NeyAqDM="
  }
}
id (Message ID)
2009-02-01以前のAPIでは、メッセージを削除するときにこの値を指定していた。現在は、Receipt Handleの方を利用する。
body
メッセージ本文
handle (Receipt Handle)
メッセージの削除や、メッセージのvisibility timeoutの変更にこの値を利用する。
メッセージ投入側

キューにメッセージを詰める場合。実際に使う場合、投げる方も受け取る方もPHPであれば、配列でデータを作成して、serializeして投げる、受け取った側はunserializeして配列として処理する (マルチバイトを含む場合は、base64_encode/decodeも噛ませる) というのが、便利で汎用性も高いと思います。

<?php
require 'Services/Amazon/SQS/Queue.php';

define('AMAZON_ACCESS_KEY', your access key);
define('AMAZON_SECRET_ACCESSKEY', your secret access key);

define('QUEUE_URL', 'http://queue.amazonaws.com/508403871985/test-queue');

$sqs = new Services_Amazon_SQS_Queue(QUEUE_URL, AMAZON_ACCESS_KEY, AMAZON_SECRET_ACCESSKEY);

try {
    $sqs->send('this is new message!');
} catch (Services_Amazon_SQS_Exception $e) {
    // 失敗したらケアする
    trigger_error($e->getMessage());
}
メッセージ受信側

キューからメッセージを取得して、処理をするようなコマンドラインスクリプトの場合、こんな感じ。

<?php
require 'Services/Amazon/SQS/Queue.php';

define('AMAZON_ACCESS_KEY', your access key);
define('AMAZON_SECRET_ACCESSKEY', your secret access key);

// queueのURIを指定
define('QUEUE_URL', 'http://queue.amazonaws.com/508403871985/test-queue');

$sqs = new Services_Amazon_SQS_Queue(QUEUE_URL, AMAZON_ACCESS_KEY, AMAZON_SECRET_ACCESSKEY);

while(1) {
    // 1件だけ取得
    list($item) = $sqs->receive(1);

    // ジョブがなければ10秒待ってリトライ
    if (empty($item)) {
        echo 'queue is empty!', PHP_EOL;
        sleep(10);
        continue;
    }

    echo 'item body is ', $item['body'], PHP_EOL;

    // ここで時間のかかる作業をやる
    // 必要に応じて、visibility timeoutを延長したりする

    $sqs->delete($item['handle']);
    echo 'item delete.', PHP_EOL;
}