すべてのプロダクト
Search
ドキュメントセンター

Elastic Compute Service:MySQL (Linux) のアプリケーション整合性スナップショットを作成するためのベストプラクティス

最終更新日:Apr 02, 2026

アプリケーション整合性スナップショットは、ディスクの状態をキャプチャする前にデータベースの書き込み操作を一時的に停止し、復元するデータがスナップショット作成時のデータと完全に一致することを保証します。このガイドでは、CentOS 7.9 を実行している MySQL 8.0 の Elastic Compute Service (ECS) インスタンス向けにアプリケーション整合性スナップショットを作成し、復元されたデータが期待される状態と一致することを確認する手順を説明します。

スナップショットの整合性レベル

すべてのスナップショットが実行中のデータベースのデータ整合性を保証するわけではありません。違いを理解することで、適切なバックアップ方法を選択できます。

タイプキャプチャされる内容データベースの安全性
クラッシュ整合性ある時点でのディスクの状態メモリ内のデータまたは保留中の I/O 操作が失われる可能性があります
アプリケーション整合性メモリ内データをフラッシュし、書き込みを一時停止した後のディスクの状態データはクリーンで回復可能な状態であり、アプリケーションはエラーなしで再起動します

MySQL やその他のトランザクションデータベースの場合、アプリケーション整合性スナップショットが適切な選択肢です。

前提条件

開始する前に、以下を確認してください。

アプリケーション整合性スナップショットを作成する際、クラウドアシスタントはインスタンス上でコマンドを実行してプリスクリプトとポストスクリプトを実行します。RAM ロールはクラウドアシスタントに必要な権限を付与します。

RAM ロールにアタッチされたカスタムポリシーには、次の権限を含める必要があります。

{
    "Version": "1",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:DescribeSnapshot*",
                "ecs:CreateSnapshot*",
                "ecs:TagResources",
                "ecs:DescribeDisks"
            ],
            "Resource": [
                "*"
            ],
            "Condition": {}
        }
    ]
}

仕組み

image

ワークフローは 5 つのステップで構成されます。

  1. プリスクリプトとポストスクリプトの作成 — プリスクリプトは、スナップショット作成前に MySQL テーブルをフラッシュし、グローバル読み取りロックを取得します。ポストスクリプトは、スナップショット完了後に書き込み操作を再開するために、ロックを保持しているプロセスを強制終了します。

  2. 検証環境の準備 — 継続的な書き込みをシミュレートするデータベーステーブルとストアドプロシージャを作成します。これにより、復元後に確認するための既知のデータタイムラインが得られます。

  3. アプリケーション整合性スナップショットの作成 — ECS コンソールで、スナップショット作成を設定してスクリプトを実行し、ファイルシステム I/O を一時的に停止します。

  4. スナップショット作成の検証 — クラウドアシスタントがスクリプトを正常に実行したことを確認し、書き込みが一時停止および再開された正確なタイムスタンプを特定します。

  5. データ復元の検証 — スナップショットを使用してディスクをロールバックし、データベースをクエリして、最後に書き込まれたレコードが一時停止期間より前であることを確認します。

操作手順

ステップ 1: プリスクリプトとポストスクリプトの作成

重要

このガイドのスクリプトは、リファレンス実装として提供されています。ご利用のアプリケーションの要件に合わせて適応させてください。一般的なガイダンスについては、「アプリケーション整合性スナップショットの作成」をご参照ください。

両方のスクリプトは root が所有し、chmod 700 の権限(root のみが読み取り、書き込み、および実行可能)を設定する必要があります。権限が正しく設定されていない場合、スクリプトは実行されません。

/tmp/prescript.sh の作成

  1. root ユーザーとして ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。

  2. プリスクリプトファイルを作成して開きます。

    vim /tmp/prescript.sh
  3. 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 パスワード
  4. Esc」を押して、:wq と入力し、Enter を押してファイルを保存します。

  5. root のみがファイルを読み取り、書き込み、実行できるように権限を設定します。

    重要

    chmod 700 が必要です。より広い権限を設定すると、権限チェックが失敗し、スクリプトは実行されません。

    chmod 700 /tmp/prescript.sh

/tmp/postscript.sh の作成

  1. ポストスクリプトファイルを作成して開きます。

    vim /tmp/postscript.sh
  2. I を押して挿入モードに入り、次のスクリプトを貼り付けます。$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 パスワード
  3. Esc キーを押し、:wq と入力して Enter キーを押すと、ファイルが保存されます。

  4. 権限を設定します。

    chmod 700 /tmp/postscript.sh

スクリプト権限の検証

/tmp ディレクトリに移動し、両方のファイルが 700 権限を持っていることを確認します。

cd /tmp
ls -l

出力は次のようになります。

image

ステップ 2: データベース検証環境の準備

このステップでは、1 秒あたり 1 レコードを 3 分間挿入するテーブルとストアドプロシージャを作成します。スナップショットを作成する前にこのプロシージャを実行すると、ロールバック後に検証するためのリファレンスとなるタイムラインが得られます。

重要

TestPIT ストアドプロシージャの実行中にアプリケーション整合性スナップショットを作成してください。プロシージャは 3 分間実行されます。この時間内にステップ 3 を完了する必要があります。

  1. /root/test.sql にテストスクリプトを作成します。

    vim /root/test.sql
  2. I を押して、次の内容を貼り付け、次に 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 ;
  3. MySQL にログインします。

    mysql -u <mysqlUserName> -p

    <mysqlUserName> をご利用の MySQL ユーザー名に置き換え、プロンプトが表示されたらパスワードを入力します。

  4. AdventureWorks データベースを作成します。

    CREATE DATABASE AdventureWorks;
  5. テストスクリプトを実行します。

    source /root/test.sql
  6. ストアドプロシージャを呼び出してレコードの書き込みを開始します。

    CALL TestPIT;

    TestPIT の実行中に、直ちにステップ 3 に進んでください。

ステップ 3: アプリケーション整合性スナップショットの作成

ECS コンソール - スナップショット整合性グループに移動します。

  1. トップナビゲーションバーで、ご利用のインスタンスのリージョンとリソースグループを選択します。

    Region

  2. [スナップショット整合性グループ] タブで、[スナップショット整合性グループの作成] をクリックします。

  3. [スナップショットの作成] ダイアログボックスで:

    1. [リソースタイプ][インスタンス] に設定したままにしてください。

    2. インスタンスを、[インスタンスの選択] ドロップダウンリストから選択します。[クラウドディスクの選択] セクションで、スナップショットに含める ESSD を選択します。

    3. [詳細設定] を展開します。

    4. [アプリケーション整合性スナップショットの有効化] を選択します。

    5. プリスクリプトとポストスクリプトのパスを、ステップ 1 で作成したファイル (/tmp/prescript.sh および /tmp/postscript.sh) に一致するように設定します。

    6. ファイルシステム I/O の一時停止および再開」機能について、[有効化]を選択し、タイムアウト期間を設定します。

  4. [OK] をクリックします。

スナップショット整合性グループが作成されると、クラウドアシスタントコマンド ID とタスク ID を示す確認メッセージが表示されます。次のステップでタスク ID を使用して結果を検証します。

ステップ 4: スナップショット作成の検証

  1. ECS クラウドアシスタントページで、タスク ID をクリックしてコマンド実行結果を表示します。スクリプトが正常に実行された場合、ExitCode0 であり、出力にはスナップショット ID とスナップショット整合性グループ ID がリストされます。ExitCode0 でない場合は、次の表を使用してトラブルシューティングを行ってください。完全なエラーコードリファレンスについては、「エラーコード」をご参照ください。

    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

    image

  2. クラウドアシスタントの出力で、書き込みが一時停止および再開された時刻を特定します。

    • プリスクリプトは 2024-08-27 15:27:55 に開始されました。この時点で書き込みが一時停止されました。image

    • ポストスクリプトは 2024-08-27 15:27:57 に完了しました。この時点で書き込みが再開されました。image

  3. スナップショットがアプリケーション整合性スナップショットとしてタグ付けされていることを確認します。[ECS コンソール - スナップショット整合性グループ] に移動します。[スナップショット整合性グループ] タブで、スナップショット整合性グループ ID をクリックします。[スナップショット情報] セクションで、各スナップショットの [タグ] 列を確認します。「APPConsistent:True」とタグ付けされたスナップショットは、アプリケーション整合性スナップショットです。

    image

  4. MySQL に接続し、一時停止期間中に挿入が発生しなかったことを確認します。

    1. ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。

    2. MySQL にログインします。

      mysql -u <mysqlUserName> -p
    3. PointInTime テーブルをクエリします。

      USE AdventureWorks;
      SELECT * FROM PointInTime;
    4. 結果で、2024-08-27 15:27:55 から 2024-08-27 15:27:58 の間にレコードがないことを確認します。このギャップは、スナップショット作成中にデータベースが一時停止されたことを確認します。image

ステップ 5: データ復元の検証

  1. スナップショット整合性グループを使用してディスクをロールバックします。詳細については、「スナップショット整合性グループを使用したディスクのロールバック」をご参照ください。

  2. ECS インスタンスに接続します。詳細については、「Linux インスタンスへの接続」をご参照ください。

  3. MySQL にログインします。

    mysql -u <mysqlUserName> -p
  4. PointInTime テーブルをクエリします。

    USE AdventureWorks;
    SELECT * FROM PointInTime;
  5. 最後のレコードのタイムスタンプを確認します。結果を解釈します。例の出力では、最後のレコードは 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一時停止期間中に書き込みが発生しました。スナップショットデータは、期待されるフリーズポイントと整合性がありません。

    image