アプリケーション整合性スナップショットは、ディスクの状態をキャプチャする前にデータベースの書き込み操作を一時的に停止し、復元するデータがスナップショット作成時のデータと完全に一致することを保証します。このガイドでは、CentOS 7.9 を実行している MySQL 8.0 の Elastic Compute Service (ECS) インスタンス向けにアプリケーション整合性スナップショットを作成し、復元されたデータが期待される状態と一致することを確認する手順を説明します。
スナップショットの整合性レベル
すべてのスナップショットが実行中のデータベースのデータ整合性を保証するわけではありません。違いを理解することで、適切なバックアップ方法を選択できます。
| タイプ | キャプチャされる内容 | データベースの安全性 |
|---|---|---|
| クラッシュ整合性 | ある時点でのディスクの状態 | メモリ内のデータまたは保留中の I/O 操作が失われる可能性があります |
| アプリケーション整合性 | メモリ内データをフラッシュし、書き込みを一時停止した後のディスクの状態 | データはクリーンで回復可能な状態であり、アプリケーションはエラーなしで再起動します |
MySQL やその他のトランザクションデータベースの場合、アプリケーション整合性スナップショットが適切な選択肢です。
前提条件
開始する前に、以下を確認してください。
マルチアタッチが無効化された、ESSD (エンタープライズ SSD) である ECS ディスク
実行中 の状態の ECS インスタンスと、正常 の状態の クラウドアシスタント。詳細については、「Cloud Assistant のステータスの確認と異常の処理」をご参照ください。
インスタンスに MySQL がインストールされており、MySQL のユーザー名とパスワードが利用可能です。詳細については、「Linux インスタンスへの MySQL のインストール」をご参照ください。
アプリケーション整合性スナップショットの権限を付与するカスタムポリシーがアタッチされた Resource Access Management (RAM) ロールが ECS インスタンスにアタッチされていること。詳細については、「RAM ロールの作成と ECS インスタンスへのアタッチ」をご参照ください。
アプリケーション整合性スナップショットを作成する際、クラウドアシスタントはインスタンス上でコマンドを実行してプリスクリプトとポストスクリプトを実行します。RAM ロールはクラウドアシスタントに必要な権限を付与します。
RAM ロールにアタッチされたカスタムポリシーには、次の権限を含める必要があります。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecs:DescribeSnapshot*",
"ecs:CreateSnapshot*",
"ecs:TagResources",
"ecs:DescribeDisks"
],
"Resource": [
"*"
],
"Condition": {}
}
]
}仕組み
ワークフローは 5 つのステップで構成されます。
プリスクリプトとポストスクリプトの作成 — プリスクリプトは、スナップショット作成前に MySQL テーブルをフラッシュし、グローバル読み取りロックを取得します。ポストスクリプトは、スナップショット完了後に書き込み操作を再開するために、ロックを保持しているプロセスを強制終了します。
検証環境の準備 — 継続的な書き込みをシミュレートするデータベーステーブルとストアドプロシージャを作成します。これにより、復元後に確認するための既知のデータタイムラインが得られます。
アプリケーション整合性スナップショットの作成 — ECS コンソールで、スナップショット作成を設定してスクリプトを実行し、ファイルシステム I/O を一時的に停止します。
スナップショット作成の検証 — クラウドアシスタントがスクリプトを正常に実行したことを確認し、書き込みが一時停止および再開された正確なタイムスタンプを特定します。
データ復元の検証 — スナップショットを使用してディスクをロールバックし、データベースをクエリして、最後に書き込まれたレコードが一時停止期間より前であることを確認します。
操作手順
ステップ 1: プリスクリプトとポストスクリプトの作成
このガイドのスクリプトは、リファレンス実装として提供されています。ご利用のアプリケーションの要件に合わせて適応させてください。一般的なガイダンスについては、「アプリケーション整合性スナップショットの作成」をご参照ください。
両方のスクリプトは root が所有し、chmod 700 の権限(root のみが読み取り、書き込み、および実行可能)を設定する必要があります。権限が正しく設定されていない場合、スクリプトは実行されません。
/tmp/prescript.sh の作成
root ユーザーとして ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。
プリスクリプトファイルを作成して開きます。
vim /tmp/prescript.sh「
I」を押して挿入モードに入り、次のスクリプトを貼り付けます。$MYSQL_USERをご自分の MySQL ユーザー名に置き換え、$MYSQL_PASSWORDをご自分の MySQL パスワードに置き換えます。prescript.sh の内容を表示
TIMESTAMP=`date +%s` MYSQL_TEMP_FILE_NAME="/tmp/mysqlfreeze${TIMESTAMP}.tmp" LOG_FILE_NAME="/tmp/mysqlfreeze${TIMESTAMP}.log" # Enter your MySQL username. export MYSQL_USER="$MYSQL_USER" # Enter your MySQL password. export MYSQL_PWD="$MYSQL_PASSWORD" function Log() { echo "$1" echo "$1" >> ${LOG_FILE_NAME} } function ExitWithResult() { Log "[INFO]:mysql freeze result is $1." exit $1 } function Main() { Log "*********************************************************************" Log "[INFO]:Begin to freeze mysql." which mysql if [ $? -ne 0 ] then Log "[INFO]:mysql is not installed." ExitWithResult 0 fi systemctl status mysqld.service | grep "inactive (dead)" if [ $? -ne 1 ] then Log "[ERROR]:mysql is not running." ExitWithResult 0 fi mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "show processlist;" > "${MYSQL_TEMP_FILE_NAME}" 2>&1 if [ $? -ne 0 ] then cat ${MYSQL_TEMP_FILE_NAME} >>"${LOG_FILE_NAME}" [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:Show process list failed." ExitWithResult 1 fi process_id=`cat ${MYSQL_TEMP_FILE_NAME} | grep "select 1 and sleep(25)" | awk -F " " '{print $1}'` if [ "$process_id" != "" ] then cat ${MYSQL_TEMP_FILE_NAME} >>"${LOG_FILE_NAME}" [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:MySQL already been freezed " ExitWithResult 1 fi cat ${MYSQL_TEMP_FILE_NAME} Log "[INFO]:Try to execute flush tables command" echo "flush tables with read lock;select 1 and sleep(25);" | nohup mysql -u$MYSQL_USER >> "${LOG_FILE_NAME}" 2>&1 & if [ $? -ne 0 ] then Log "[ERROR]:Freeze mysql failed." ExitWithResult 1 fi Log "[INFO]:Flush tables command execute success" checkTime=0 while [ 1 ] do mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "show processlist;" > "${MYSQL_TEMP_FILE_NAME}" 2>&1 if [ $? -ne 0 ] then cat ${MYSQL_TEMP_FILE_NAME} >>"${LOG_FILE_NAME}" [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:Show process list failed." ExitWithResult 1 fi cat ${MYSQL_TEMP_FILE_NAME} process_id=`cat ${MYSQL_TEMP_FILE_NAME} | grep "select 1 and sleep(25)" | awk -F " " '{print $1}'` if [ "$process_id" = "" ] then checkTime=`expr $checkTime + 1` Log "[INFO]:Mysql is not freeze. checkTime is ${checkTime}" sleep 1 else Log "[INFO]:Found sleep command in processlist,freeze success" break fi if [ $checkTime -eq 10 ] then cat "${MYSQL_TEMP_FILE_NAME}" >>"${LOG_FILE_NAME}" 2>&1 freeze_id=`cat ${MYSQL_TEMP_FILE_NAME} | grep "flush tables with read lock" | awk -F " " '{print $1}'` mysql -u$MYSQL_USER -e "kill $freeze_id;" >> "${LOG_FILE_NAME}" 2>&1 if [ $? -ne 0 ] then Log "[ERROR]:Thaw mysql failed." fi [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:Mysql is not freeze. Will return error" ExitWithResult 1 fi done [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[INFO]:Finish freeze mysql." ExitWithResult 0 } Main更新するパラメーター:
パラメーター 説明 $MYSQL_USERご利用の MySQL ユーザー名 $MYSQL_PASSWORDご利用の MySQL パスワード 「
Esc」を押して、:wqと入力し、Enter を押してファイルを保存します。root のみがファイルを読み取り、書き込み、実行できるように権限を設定します。
重要chmod 700が必要です。より広い権限を設定すると、権限チェックが失敗し、スクリプトは実行されません。chmod 700 /tmp/prescript.sh
/tmp/postscript.sh の作成
ポストスクリプトファイルを作成して開きます。
vim /tmp/postscript.shIを押して挿入モードに入り、次のスクリプトを貼り付けます。$MYSQL_USERをお使いの MySQL ユーザー名に、$MYSQL_PASSWORDをお使いの MySQL パスワードに置き換えます。postscript.sh の内容を表示
TIMESTAMP=`date +%s` MYSQL_TEMP_FILE_NAME="/tmp/mysqlthaw${TIMESTAMP}.tmp" LOG_FILE_NAME="/tmp/mysqlthaw${TIMESTAMP}.log" # Enter your MySQL username. export MYSQL_USER="$MYSQL_USER" # Enter your MySQL password. export MYSQL_PWD="$MYSQL_PASSWORD" function Log() { echo "$1" echo "$1" >> ${LOG_FILE_NAME} } function ExitWithResult() { Log "[INFO]:mysql unfreeze result is $1." exit $1 } function Main() { Log "*********************************************************************" Log "[INFO]:Begin to thaw mysql." which mysql if [ $? -ne 0 ] then Log "[INFO]:mysql is not installed." ExitWithResult 0 fi systemctl status mysqld.service | grep "inactive (dead)" if [ $? -ne 1 ] then Log "[ERROR]:mysql is not running." ExitWithResult 0 fi mysql -u$MYSQL_USER -e "show processlist;" > "${MYSQL_TEMP_FILE_NAME}" 2>&1 if [ $? -ne 0 ] then cat ${MYSQL_TEMP_FILE_NAME} >>"${LOG_FILE_NAME}" [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:show process list failed." ExitWithResult 1 fi Log "[INFO]:show process list success." cat ${MYSQL_TEMP_FILE_NAME} process_ids=`cat ${MYSQL_TEMP_FILE_NAME} | grep "select 1 and sleep(25)" | awk -F " " '{print $1}'` if [ "$process_ids" = "" ] then [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:Get freeze process_id failed." ExitWithResult 1 fi cat ${MYSQL_TEMP_FILE_NAME} | grep "select 1 and sleep(25)" | awk -F " " '{print $1}'| while read pid do Log "[INFO]:Try to stop sql process ${pid}." mysql -u$MYSQL_USER -e "kill $pid;" >> "${LOG_FILE_NAME}" 2>&1 if [ $? -ne 0 ] then [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[ERROR]:Thaw mysql failed.PIDs is ${process_ids}" ExitWithResult 1 fi Log "[INFO]:Stop sql process ${pid} success." done [ -f ${MYSQL_TEMP_FILE_NAME} ] && rm -rf ${MYSQL_TEMP_FILE_NAME} Log "[INFO]:Finish thaw mysql." ExitWithResult 0 } Main更新するパラメーター:
パラメーター 説明 $MYSQL_USERご利用の MySQL ユーザー名 $MYSQL_PASSWORDご利用の MySQL パスワード Escキーを押し、:wqと入力して Enter キーを押すと、ファイルが保存されます。権限を設定します。
chmod 700 /tmp/postscript.sh
スクリプト権限の検証
/tmp ディレクトリに移動し、両方のファイルが 700 権限を持っていることを確認します。
cd /tmp
ls -l出力は次のようになります。

ステップ 2: データベース検証環境の準備
このステップでは、1 秒あたり 1 レコードを 3 分間挿入するテーブルとストアドプロシージャを作成します。スナップショットを作成する前にこのプロシージャを実行すると、ロールバック後に検証するためのリファレンスとなるタイムラインが得られます。
TestPIT ストアドプロシージャの実行中にアプリケーション整合性スナップショットを作成してください。プロシージャは 3 分間実行されます。この時間内にステップ 3 を完了する必要があります。
/root/test.sqlにテストスクリプトを作成します。vim /root/test.sqlIを押して、次の内容を貼り付け、次にEscを押してから:wqと入力して保存します。USE AdventureWorks; CREATE TABLE PointInTime(id int, t datetime); DELIMITER $$ CREATE PROCEDURE `TestPIT`() BEGIN DECLARE i int; SET i=1; WHILE i < 180 DO INSERT INTO PointInTime VALUES(i, now()); SELECT SLEEP(1); SET i=i+1; END WHILE; END $$ DELIMITER ;MySQL にログインします。
mysql -u <mysqlUserName> -p<mysqlUserName>をご利用の MySQL ユーザー名に置き換え、プロンプトが表示されたらパスワードを入力します。AdventureWorksデータベースを作成します。CREATE DATABASE AdventureWorks;テストスクリプトを実行します。
source /root/test.sqlストアドプロシージャを呼び出してレコードの書き込みを開始します。
CALL TestPIT;TestPITの実行中に、直ちにステップ 3 に進んでください。
ステップ 3: アプリケーション整合性スナップショットの作成
ECS コンソール - スナップショット整合性グループに移動します。
トップナビゲーションバーで、ご利用のインスタンスのリージョンとリソースグループを選択します。

[スナップショット整合性グループ] タブで、[スナップショット整合性グループの作成] をクリックします。
[スナップショットの作成] ダイアログボックスで:
[リソースタイプ] を [インスタンス] に設定したままにしてください。
インスタンスを、[インスタンスの選択] ドロップダウンリストから選択します。[クラウドディスクの選択] セクションで、スナップショットに含める ESSD を選択します。
[詳細設定] を展開します。
[アプリケーション整合性スナップショットの有効化] を選択します。
プリスクリプトとポストスクリプトのパスを、ステップ 1 で作成したファイル (
/tmp/prescript.shおよび/tmp/postscript.sh) に一致するように設定します。「ファイルシステム I/O の一時停止および再開」機能について、[有効化]を選択し、タイムアウト期間を設定します。
[OK] をクリックします。
スナップショット整合性グループが作成されると、クラウドアシスタントコマンド ID とタスク ID を示す確認メッセージが表示されます。次のステップでタスク ID を使用して結果を検証します。
ステップ 4: スナップショット作成の検証
ECS クラウドアシスタントページで、タスク ID をクリックしてコマンド実行結果を表示します。スクリプトが正常に実行された場合、ExitCode は
0であり、出力にはスナップショット ID とスナップショット整合性グループ ID がリストされます。ExitCode が0でない場合は、次の表を使用してトラブルシューティングを行ってください。完全なエラーコードリファレンスについては、「エラーコード」をご参照ください。ExitCode 考えられる原因 操作 1(プリスクリプト)MySQL はすでにフリーズしている、接続に失敗した、または 10 回のリトライ後にフリーズがタイムアウトした 特定の [ERROR]行について、/tmp/mysqlfreeze<timestamp>.logのプリスクリプトログを確認します。1(ポストスクリプト)フリーズプロセスが見つからない、または kill コマンドが失敗した /tmp/mysqlthaw<timestamp>.logのポストスクリプトログを確認します。systemctl status mysqld.service権限エラー スクリプト権限が 700ではない、またはスクリプトが root によって所有されていないchmod 700を再実行し、ls -l /tmp/prescript.sh
クラウドアシスタントの出力で、書き込みが一時停止および再開された時刻を特定します。
プリスクリプトは
2024-08-27 15:27:55に開始されました。この時点で書き込みが一時停止されました。
ポストスクリプトは
2024-08-27 15:27:57に完了しました。この時点で書き込みが再開されました。
スナップショットがアプリケーション整合性スナップショットとしてタグ付けされていることを確認します。[ECS コンソール - スナップショット整合性グループ] に移動します。[スナップショット整合性グループ] タブで、スナップショット整合性グループ ID をクリックします。[スナップショット情報] セクションで、各スナップショットの [タグ] 列を確認します。「
APPConsistent:True」とタグ付けされたスナップショットは、アプリケーション整合性スナップショットです。
MySQL に接続し、一時停止期間中に挿入が発生しなかったことを確認します。
ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。
MySQL にログインします。
mysql -u <mysqlUserName> -pPointInTimeテーブルをクエリします。USE AdventureWorks; SELECT * FROM PointInTime;結果で、
2024-08-27 15:27:55から2024-08-27 15:27:58の間にレコードがないことを確認します。このギャップは、スナップショット作成中にデータベースが一時停止されたことを確認します。
ステップ 5: データ復元の検証
スナップショット整合性グループを使用してディスクをロールバックします。詳細については、「スナップショット整合性グループを使用したディスクのロールバック」をご参照ください。
ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。
MySQL にログインします。
mysql -u <mysqlUserName> -pPointInTimeテーブルをクエリします。USE AdventureWorks; SELECT * FROM PointInTime;最後のレコードのタイムスタンプを確認します。結果を解釈します。例の出力では、最後のレコードは
2024-08-27 15:27:54であり、プリスクリプト開始時刻の2024-08-27 15:27:55より前です。アプリケーション整合性スナップショットは、MySQL データを正しくバックアップしました。最後のレコードのタイムスタンプ 意味 2024-08-27 15:27:55より前 (プリスクリプト開始時刻)一時停止中に書き込みは発生しませんでした。スナップショットはデータベースの状態を正しくキャプチャしました。復元は成功しました。 以降 2024-08-27 15:27:55一時停止期間中に書き込みが発生しました。スナップショットデータは、期待されるフリーズポイントと整合性がありません。 