PHP中的SQS
导言
由于以前没有使用过SQS,我尝试从PHP进行集成来使用它。
环境
亚马逊 Linux 2
PHP 7.2.27 (如果是7.x版本即可)
AWS SDK 3.133 (如果是3.x版本即可)
在亚马逊Linux上,如果通过yum安装php,它会成为5系列。在这种情况下,尝试使用composer安装AWS SDK会成为2.8版本。然后,在使用基于AWS SDK的PHP程序时,会出现一些关于credential的错误,导致完全无法工作,所以我升级到了PHP 7才解决了这个问题,但在升级过程中遇到了困难。
在汉语中,SQS是什么意思?
AWS的队列服务。
FIFO(先进先出)是在学习基本信息时经常出现的一种概念。
也就是说,可以按照先后顺序取出信息。
使用A系统将消息(数据)存储到队列中。
使用B系统查看队列,如果有消息,则取出来。
这是使用的想象。
As per the pricing of Amazon SQS, how are the fees calculated?
每个月的前100万个请求是免费的。
超过免费配额后的每100万个请求的费用(按月计算)
标准队列 0.40美元(0.0000004美元/请求)
FIFO队列 0.50美元(0.0000005美元/请求)
如果每秒一次的请求,
1*60*60*24 = 86,400请求。
假设一个月有30天,
86400*30 = 2,592,000请求。
所以,我想如果每3秒钟左右只请求一次的话,应该不会超过免费配额。
可能实际上还会有发起请求的队列、获取请求的队列,以及删除已获取消息的请求等等,所以如果不加以处理,请求数量很容易激增。
即使在标准队列中超过100万个免费配额,也只需支付0.4美元,以100日元兑换1美元,相当于40日元,所以并不算什么大不了的事情。
顺便说一下,在价格表上有标准队列和FIFO队列的表示。
冷静一点,其实队列不都是FIFO的吗,但据说在SQS中,如果是标准队列,并不总是按照进入顺序被取出。(队列是个什么头痛的问题呢)
只需提供一个选项,用中文本地语言转述以下句子:
在大致浏览这些内容时,我觉得你可以大致了解有关SQS特有概念的一些信息。
在使用Amazon SQS之前,你需要了解一些基本事项。
顺便提一下关于确认消息是否已进入队列的一方面。
我认为最好设置长轮询以激活Amazon SQS消息队列。
基本上,收到要求確認訊息的一方不需要做任何操作,只要發送確認訊息的要求到 SQS,SQS 將執行以下操作:
– 如果有訊息,立即回應。
– 如果沒有訊息,最多等待20秒,等待訊息到達後再回應。
(當然,在等待期間如果有訊息進來,將立即回應)
這樣,SQS 會替我們執行相應的操作。
(在發送方,只需要設定要求自身的逾時設定就好…?)
如果您希望实时性,即使没有消息,每20秒也只会产生一个请求,这对您的钱包也很友好。
(如果你不是那么追求实时性,你可以延长接收方的请求周期,这是个好主意。)
环境搭建
我只能依赖模糊记忆查看历史,所以如果有错误,请谅解。
暂时不管
sudo su -
成为管理用户
安装 PHP 7.2
遇到困难,于是暂时尝试了各种看似相关的 PHP 模块(巨爆)
可能会有一些不必要的模块,但这里先列出了从历史记录中找到的模块。
yum install -y php72 php72-php php72-php-fpm php72-php-mbstring php72-php-devel php72-php-gd
由于需要安装AWS SDK,所以可以参考以下的方法安装composer。因为感觉有点麻烦,所以创建了一个工作目录,在那里进行操作。
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
安装 AWS SDK 版本 3 的 PHP
composer require aws/aws-sdk-php
当我陷入困境时,进行composer的更新可能会导致失败,让我非常恼火。尽管我已经采取了一些应对措施,但也许普通情况下不需要更新,或者如果不是micro实例类型,可能就不会出现这种情况。仅供参考,在这里贴出关于在EC2的micro实例上更新composer失败的备忘录。
通过PHP发送消息
使用AWS SDK或AWS CLI执行命令的人都很熟悉,但是在从PHP发起请求时,需要进行身份验证,所以必须事先在IAM中准备一个允许”程序访问”的用户。需要准备那个常见的访问密钥和秘密访问密钥。
参考这里的PHP源代码
我尝试使用 AWS SDK for PHP 中的 AWS SQS。
使用AWS SDK for PHP来使用Amazon SQS。
据说标准队列和FIFO队列有些许不同。
这次我们选择了FIFO队列来执行。
发送消息处理
<?php
require_once 'vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;
$queueUrl = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxx/yyyyyyyy.fifo";
try{
$client = new SqsClient([
'profile' => 'default',
'region' => 'ap-northeast-1',
'version' => 'latest',
]);
$fifo_params = [
'QueueUrl' => $queueUrl,
'MessageBody' => "xxxxxx", // ここにメッセージを設定
'MessageGroupId' => 'test', // よく分かってない
'MessageDeduplicationId' => time(), // よく分かってない
];
$client->sendMessage($fifo_params);
} catch(AwsException $e){
var_dump($e->getMessage());
}
执行此操作后,您可以在AWS控制台上确认SQS中是否有消息。
接收消息的处理
<?php
require_once 'vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;
$queueUrl = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxx/yyyyyyyy.fifo";
try{
$client = new SqsClient([
'profile' => 'default',
'region' => 'ap-northeast-1',
'version' => 'latest',
]);
// ここまではsendMessageと一緒
// 継続的にメッセージを受け取りに行く場合にはここでループの記述
// while(true){
// メッセージ受け取り
$result = $client->receiveMessage(array(
'QueueUrl' => $queueUrl,
'WaitTimeSeconds' => 5, // ロングポーリングする秒数(最大20秒)
'MaxNumberOfMessages' => 10, // 同時に取ってくるメッセージ数
));
// メッセージの受け取り処理をループにしていた場合はメッセージの中身が空ならここでcontinueさせる
// if(!$result->search('Messages[]'))continue;
// メッセージを1件づつ取得し、取得済みメッセージは都度削除リクエストを投げる
foreach ($result->search('Messages[]') as $message) {
$queueHandle = $message['ReceiptHandle'];
echo $message['Body'];
// 対象メッセージの削除
$client->deleteMessage([
'QueueUrl' => $queueUrl,
'ReceiptHandle' => $queueHandle,
]);
}
// メッセージの受け取りループをしていた場合はここまで
// }
} catch(AwsException $e){
var_dump($e->getMessage());
}
得出结论
在接收端进行了SQS的长轮询,同时执行了消息发送处理,结果在接收端不到1秒的时间内就收到了消息。
具有十分广泛的应用场景,给人以很大的信心。
赠品
关于可视性超时
创建一个名为“test”的SQS队列
向“test”队列发送消息”AAA”
当$client->receiveMessage的时候,会给”AAA”分配一个叫作ReceiptHandle的类似会话ID的东西。(ReceiptHandle是针对每条消息的,一对一的关系。)
而且,在ReceiptHandle的有效期内,”AAA”是不可见的,也就是说其他人看不到它,可以说是一种独占状态。
(可能,ReceiptHandle的有效期=可见性超时)
收到消息的进程可以使用ReceiptHandle对不可见消息执行操作(例如删除或更改可见性超时时间等)。
若干迷上了可视性超时设置为0秒,消息就无法消除了。
如果接收端处理中途中断,为了重新获取消息,再次发送请求并且如果仍然不可见,就会很麻烦,所以我决定大胆地将可视性超时设置为0秒,结果出现了上述的状态。
(因为ReceiptHandle已经过期,所以当然无效啦)
在重新请求时,若问题仍然处于不可见状态,只需使用 ReceiptHandle 将相关消息的有效期设为0秒,即可使其变为可见状态,通过此方法解决该问题。
在中文中的表达可以是:
可见超时为0秒,可能意味着只有当消息本身的有效期限到期时,消息才能一直保持可见状态,这是一种必需的设置。这样的设置存在吗?可以在最新新闻列表等地方使用吗?
使用PHP创建FIFO队列。
<?php
require 'vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;
try{
$client = new SqsClient([
'profile' => 'default',
'region' => 'ap-northeast-1',
'version' => 'latest',
]);
$client->createQueue([
'QueueName' => 'omake.fifo',
'Attributes' => ['FifoQueue' => 'true'],
]);
} catch(AwsException $e){
var_dump($e->getMessage());
}
使用AWS CLI ver2创建FIFO队列。
aws2 sqs create-queue --queue-name omake.fifo --attributes FifoQueue=true