内容
EC2からAmazon SQSを経由してRDSにデータを保存する方法をまとめます。
RDSのダウンタイム中にRDSに保存処理をしようとするとエラーになり、そのデータが失われます。
そのため、ダウンタイム中はSQSにメッセージをためておいて、RDSが起動したタイミングでデータを保存することにします。
前回作成したものを使用します。
Amazon SQSでキューを作成する
Amazon SQSのダッシュボードから「キューの作成」をクリックします。
今回は「標準」を選択します。
FIFOとの違いは、FIFOがメッセージの順番を約束してくれるのに対し、標準は保証されません。
以上です。
SQSにメッセージを送信する
AWS SDK for PHPのインストール
前回作成したindex.phpからAmazon SQSにメッセージを送信する処理を追加します。
今回はAWS SDK for PHPを使用します。
EC2にsshし、/var/www/html/
で↓を叩きます。
[ec2-user@ip-10-0-0-102 html]$ sudo composer require aws/aws-sdk-php
[ec2-user@ip-10-0-0-102 html]$ composer show -i
→aws/aws-sdk-phpがあればOK
これでAWS SDK for PHPが使用可能になりました。
/var/www/html/index.php
に↓を追記します。
<?php
require_once 'vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;
// AWSの認証情報
$credentials = new Aws\Credentials\Credentials([アクセスキーID], [アクセスキー]);
$sqsClient = new SqsClient([
'version' => 'latest',
'region' => '[リージョンのコード]',
'credentials' => $credentials,
]);
$queueUrl = [キューのURL];
...
if ($post_message) {
// メッセージを送信する処理
$result = $sqsClient->sendMessage([
'QueueUrl' => $queueUrl,
'MessageBody' => $post_message,
]);
$query = "INSERT INTO post (post) VALUES ('" . $post_message . "')";
$stmt = $dbh->query($query);
}
...
アクセスキーIDとアクセスキーをベタ打ちしていますが、本当にセキュリティ上やばいのでやめましょう。
今回だけです。
アクセスキーIDとアクセスキーを取得するには、
AWSのダッシュボード→セキュリティ認証情報→アクセスキーを作成
です。
ではブラウザからアクセスしてメッセージを送信してみましょう
↓
前回と同様に、送信したメッセージがDBに保存されました。
「利用可能なメッセージ」が1件あるのがわかります。
無事送信したメッセージがSQSに保存されていることがわかります。
SQSからメッセージを受信する
/var/www/html/にrecieve.php
を作成します。
<?php
require 'vendor/autoload.php';
use Aws\Sqs\SqsClient;
$dsn = "mysql:host=[エンドポイント];dbname=[データベース名]";
$username = "ユーザー名";
$password = "DBのパスワード";
$dbh = new PDO($dsn, $username, $password);
// AWS認証情報の設定
$credentials = new Aws\Credentials\Credentials('アクセスキーID', 'アクセスキー');
// SQSクライアントの作成
$sqsClient = new SqsClient([
'version' => 'latest',
'region' => '[リージョンコード]',
'credentials' => $credentials,
]);
// メッセージを受信
$queueUrl = 'amazon SQSのURL';
if ($_POST['fetch']) {
$result = $sqsClient->receiveMessage([
'QueueUrl' => $queueUrl,
]);
}
// 受信したメッセージを処理
if (!empty($result['Messages'])) {
foreach ($result['Messages'] as $message) {
$messageBody = $message['Body'];
echo $messageBody . "を受信しました" . PHP_EOL;
$query = "INSERT INTO post (post) VALUES ('" . $messageBody . "')";
$stmt = $dbh->query($query);
// メッセージを削除
$sqsClient->deleteMessage([
'QueueUrl' => $queueUrl,
'ReceiptHandle' => $message['ReceiptHandle'],
]);
}
} else {
echo '受信したメッセージはありません。';
}
?>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sqs</title>
</head>
<body>
<form action="" method="post">
<button name="fetch" value="1">メッセージを受信</button>
</form>
</body>
</html>
何度も言いますが、アクセスキーなどをベタ打ちするのはやめましょう。
ではブラウザで実行してみましょう。
↓
先ほど送信した「HELLO」というメッセージが取得できました。
ここでもDBに保存処理をしているので、index.phpを表示させると「HELLO」が2件保存されていることがわかります。
RDSのダウンタイム中に実行する
RDSのダウンタイムを想定してこの処理を実行してみます。
RDSのダウンタイム中はDBの接続情報をコメントアウトしておきましょう。
ブラウザで表示させると
(ダウンタイム中なのでDBのデータが取得できていません)
ではこの状態でメッセージを送信してみましょう。
「Good Morning」と入力して送信ボタンを押すと...
ダウンタイム中ですし、DBへの接続を切っているのでうんともすんともなりません...
「私のあいさつがこの世から消えてしまったのか...?」
そんな心配はご無用です。
SQSをのぞいてみると、きちんとメッセージが保存されています。
ここでRDSのダウンタイムが終わり、再起動しました。
DBへの接続情報のコメントアウトを外します。
recieve.phpからメッセージを受信してみましょう。
失ったと思われていた「Good Morning」が取得できました。
index.phpを確認すると、きちんとDBにも保存されていることがわかります。
という感じで、RDSのダウンタイム中の処理を止めない方法を作ってみました。
とはいえSELECTができないので、完璧ではないですね。
また何か方法があるか探ってみます。