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

Elastic Compute Service:MySQLがデプロイされているLinuxインスタンスのアプリケーション一貫性のあるスナップショットを作成するためのベストプラクティス

最終更新日:Sep 11, 2024

アプリケーション一貫性のあるスナップショットを作成するために、システムは書き込み要求を中断して、スナップショットでキャプチャされたデータの整合性と一貫性を確保します。 アプリケーションの一貫性のあるスナップショットを使用することで、データの破損や損失なしにディスクをロールバックできます。これにより、MySQLなどのアプリケーションが一貫した状態で起動できます。 このトピックでは、MySQLがデプロイされているLinux Elastic Compute Service (ECS) インスタンスのアプリケーション一貫性のあるスナップショットを作成し、そのスナップショットを使用してデータを期待どおりに復元できるかどうかを確認する方法について説明します。

前提条件

  • CentOS 7.6以降、Ubuntu 18.04以降、またはAlibaba Cloud Linux 2のいずれかのオペレーティングシステムを実行するECSインスタンスが作成されました。

  • ECSインスタンスにアタッチされているディスクは、マルチアタッチが無効になっているエンタープライズSSD (ESSD) です。

  • Cloud Assistant AgentがECSインスタンスにインストールされています。 Cloud Assistant Agentのインストール方法については、「Cloud Assistant Agentのインストール」をご参照ください。

    説明

    デフォルトでは、Cloud Assistant Agentは2017年12月1日以降にパブリックイメージから作成されたインスタンスにプリインストールされます。

  • MySQLがECSインスタンスにインストールされています。 MySQLのユーザー名とパスワードが取得されます。 詳細については、「LinuxインスタンスへのMySQLのデプロイ」をご参照ください。

手順

次の例では、CentOS 7.9を実行し、MySQL 8.0がインストールされているECSインスタンスが使用されています。 動作は、実際のシナリオに基づいて異なり得る。

手順1: データベース検証環境の準備

データベーステーブルやストアドプロシージャの作成など、データベース検証環境を準備します。これは、アプリケーションが期待どおりにデータベースと対話するかどうかを確認するために使用されます。

  1. ルートユーザーとしてECSインスタンスに接続します。

    詳細については、「パスワードまたはキーを使用したLinuxインスタンスへの接続」をご参照ください。

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

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

      vim /root/test.sql
    2. Iキーを押して挿入モードに入ります。

    3. スクリプトファイルをコンパイルします。

      このスクリプトには、PointInTimeという名前のデータベーステーブルを作成するために使用されるSQL文と、TestPITという名前のストアドプロシージャを作成するために使用されるSQL文が含まれます。 スクリプト例:

      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 ;
    4. Escキー、入力: wq、Enterキーを押してスクリプトファイルを保存して闭じます。

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

    次のコマンドを入力し、Enterキーを押して、指示に従ってMySQLパスワードを入力します。

    mysql -u <mysqlUserName> -p

    <mysqlUserName> を実際のMySQLユーザー名に置き換えます。

  4. AdventureWorksという名前のデータベースを作成します。

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

    source /root/test.sql
  6. MySQLを終了します。

    exit

ステップ2: prescript.shおよびpostscript.shスクリプトファイルを作成する

このセクションでは、MySQL用のprescript.shおよびpostscript.shスクリプトファイルを作成する方法について説明します。 スクリプトファイルは、アプリケーションの一貫性のあるスナップショットを作成するために使用されます。

重要

このトピックで使用されているprescript.shおよびpostscript.shスクリプトファイルは参照用です。 アプリケーションのアプリケーション一貫性のあるスナップショットを作成する場合、アプリケーションとビジネスシナリオに基づいて、prescript.shおよびpostscript.shスクリプトファイルをコンパイルできます。

  1. ルートユーザーとしてECSインスタンスに接続します。

    詳細については、「パスワードまたはキーを使用したLinuxインスタンスへの接続」をご参照ください。

  2. /tmp/prescript.shでスクリプトファイルにデータを書き込みます。

    1. ルートアカウントを使用して、/tmp/prescript.shスクリプトファイル。

      vim /tmp/prescript.sh
    2. Iキーを押して挿入モードに入ります。

    3. アプリケーションに基づいてスクリプトファイルを作成します。

      スクリプト例:

      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) に対する読み取り、書き込み、および実行権限がrootアカウントにのみ付与されていることを確認してください。 それ以外の場合、権限設定は無効になり、スクリプトは実行できません。

      chmod 700 /tmp/prescript.sh
  3. /tmp/postscript.shスクリプトファイルにデータを書き込みます。

    1. ルートアカウントを使用して、/tmp/postscript.shスクリプトファイル。

      vim /tmp/postscript.sh
    2. を押してください。Iキーを押して挿入モードに入ります。

    3. アプリケーションに基づいてスクリプトファイルを作成します。

      スクリプト例:

      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パスワードに設定します。

    4. Escキー、入力: wq、Enterキーを押してスクリプトファイルを保存して闭じます。

    5. スクリプトファイルの読み取り、書き込み、および実行権限をrootアカウントのみに付与します。

      重要

      セキュリティ上の理由から、スクリプトファイル (chmod 700) に対する読み取り、書き込み、および実行権限がrootアカウントにのみ付与されていることを確認してください。 それ以外の場合、権限設定は無効になり、スクリプトは実行できません。

      chmod 700 /tmp/postscript.sh
  4. /tmpディレクトリに移動し、スクリプトファイルの権限を確認します。

    cd /tmp
    ls -l

    次のコマンド出力が返されます。これは、スクリプトファイルに対する権限が正しく構成されていることを示します。

    image

手順3: LinuxインスタンスへのRAMロールのアタッチ

ECSインスタンスのアプリケーション一貫性のあるスナップショット機能を有効にする前に、スナップショットの詳細を照会してスナップショットを作成する権限など、必要な権限を持つResource Access Management (RAM) ロールをインスタンスにアタッチする必要があります。

  1. RAMコンソールAlibaba Cloudアカウントを使用します。

  2. アプリケーション一貫性のあるスナップショット機能のRAMロールを作成します。 詳細については、「信頼できるAlibaba CloudサービスのRAMロールの作成」をご参照ください。

    次の図は、AppSnapshotRoleNameという名前のRAMロールを作成する方法を示しています。应用一致性ram角色

  3. アプリケーション一貫性のあるスナップショット機能の権限ポリシーを作成します。 詳細については、「カスタムポリシーの作成」をご参照ください。

    快照权限

    AppSnapshotPolicyポリシーを作成して、スナップショットの詳細の照会、スナップショットの作成、タグの設定、およびディスクの詳細の照会の権限を付与します。 次のポリシーコンテンツを使用できます。

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ecs:DescribeSnapshot*",
                    "ecs:CreateSnapshot*",
                    "ecs:TagResources",
                    "ecs:DescribeDisks"
                ],
                "Resource": [
                    "*"
                ],
                "Condition": {}
            }
        ]
    }
  4. AppSnapshotPolicyポリシーをAppSnapshotRoleName RAMロールにアタッチします。 詳細については、「RAMロールへの権限の付与」をご参照ください。

    授权

  5. AppSnapshotRoleName RAMロールをECSインスタンスにアタッチします。 詳細については、「インスタンスRAMロールを使用してリソースへのアクセスを制御する」をご参照ください。

ステップ4: データベースでTestPITストアドプロシージャを呼び出す

MySQLデータベースのアプリケーション一貫性のあるスナップショットを作成するために、システムはデータベースを一時停止します。 このセクションでは、データベースのアプリケーション一貫性のあるスナップショットを作成する前に、TestPITストアドプロシージャを呼び出してMySQLデータベースにデータを挿入する方法について説明します。 これにより、MySQLデータベースが中断されたかどうかを確認し、作成されたスナップショットを期待どおりに使用してデータを復元できます。

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

    次のコマンドを入力し、Enterキーを押して、指示に従ってMySQLパスワードを入力します。

    mysql -u <mysqlUserName> -p

    <mysqlUserName> を実際のMySQLユーザー名に置き換えます。

  2. AdventureWorksデータベースに切り替えます。

    USE AdventureWorks;
  3. TestPITストアドプロシージャを呼び出します。

    CALL TestPIT;
    重要

    TestPITストアドプロシージャを実行するために必要な3分間のウィンドウ内に、アプリケーションの一貫性のあるスナップショットを作成する必要があります。

手順5: ECSコンソールでのアプリケーションの一貫性のあるスナップショットの作成

このセクションでは、ECSコンソールでMySQLがデプロイされているLinuxインスタンスのアプリケーションに一貫性のあるスナップショットを作成する方法について説明します。

  1. ECSコンソールの [インスタンス] ページに移動します。

    1. ECSコンソール.

    2. 左側のナビゲーションウィンドウで、インスタンス&画像 > インスタンス.

    3. 上部のナビゲーションバーで、ECSインスタンスが存在するリージョンを選択します。image.png

  2. 管理するインスタンスを見つけて、[操作] 列の 更多 > ディスクとイメージ > [スナップショットの一貫性のあるグループの作成] を選択します。

  3. [スナップショット一貫性のあるグループの作成] ダイアログボックスで、パラメーターを設定します。

    1. スナップショットを作成するESSDを選択し、[スナップショットパラメータ] セクションでパラメータを設定します。

    2. アプリケーションに対応したスナップショットパラメーターを設定します。

      [Application-consistent Snapshotの有効化] を選択し、[Application Pre-freeze script path] フィールドにprescript.shスクリプトファイルが配置されているパスを入力し、[Application Post-thaw Script Path] フィールドにpostscript.shスクリプトファイルが配置されているパスを入力します。 入力するパスが, 手顺2で作成したスクリプトファイルのパスと同じであることを确认してください。 スクリプトファイルの詳細については、このトピックの「手順2: prescript.shおよびpostscript.shスクリプトファイルの作成」をご参照ください。

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

  5. スナップショット整合性グループが作成されると、次の図に示すように、Cloud AssistantコマンドIDとタスクIDを含むメッセージが表示されます。 タスクIDに基づいて、アプリケーションに整合性のあるスナップショットが作成されているかどうかを確認できます。命令执行id

手順6: アプリケーションの一貫性のあるスナップショットが作成されているかどうかを確認

このセクションでは、データベースに対してアプリケーション整合性のあるスナップショットが作成され、挿入操作が一時停止されているかどうかを確認する方法について説明します。

  1. ECSクラウドアシスタントページで、コマンドの実行結果を表示します。

    1. ECSコンソール.

    2. 左側のナビゲーションウィンドウで、メンテナンス&モニタリング > クラウドアシスタン

    3. コマンド実行結果タブをクリックします。

    4. 前の手順で取得したタスクIDを検索し、IDをクリックして実行結果を表示します。

      image

      タスクでアプリケーション一貫性のあるスナップショットが作成されると、ExitCodeの戻り値が0され、作成されたアプリケーション一貫性のあるスナップショットとスナップショット一貫性のあるグループのIDがコマンド出力に表示されます。

      説明

      ExitCodeの戻り値が0でない場合はエラーが発生しました。 ExitCode列で返されたエラーコードに基づいてエラーをトラブルシューティングします。 詳細については、「アプリケーション一貫性のあるスナップショットの作成」トピックのエラーコードをご参照ください。

  2. 戻りデータでアプリケーションが中断された時刻を表示します。

    返されるデータで、prescript.shスクリプトが実行を開始した時刻とpostscript.shスクリプトが実行を停止した時刻を見つけます。

    • この例では、prescript.shスクリプトは2024-08-27 15:27:55で実行を開始しました。 image

    • この例では、postscript.shスクリプトは2024-08-27 15:27:57で実行を停止しました。

      image

  3. スナップショットページで、作成したスナップショット整合性グループとディスクスナップショットを表示します。

    1. 左側のナビゲーションウィンドウで、ストレージ&スナップショット > スナップショット.

    2. スナップショット整合性グループタブで、作成したスナップショット整合性グループを見つけ、スナップショット整合性グループのIDをクリックして、グループが作成されたスナップショットの詳細を表示します。

    3. スナップショット情報セクションでは、スナップショットに追加されたタグに基づいて、スナップショット一貫性グループで作成されたスナップショットがアプリケーション一貫性のあるスナップショットであるかどうかを確認します。

      作成されたスナップショットがアプリケーション整合性のあるスナップショットの場合、次の図に示すように、スナップショットに対応する [タグ] 列にAPPConsistent:Trueタグが表示されます。

      image

  4. MySQLデータベースに接続して、挿入操作が中断された時間を表示します。

    1. Linuxインスタンスに接続します。

      詳細については、「パスワードまたはキーを使用したLinuxインスタンスへの接続」をご参照ください。

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

      次のコマンドを入力し、Enterキーを押して、指示に従ってMySQLパスワードを入力します。

      mysql -u <mysqlUserName> -p

      <mysqlUserName> を実際のMySQLユーザー名に置き換えます。

    3. PointInTimeテーブルのコンテンツを照会します。

      USE AdventureWorks;
      SELECT * FROM PointInTime;

      次のクエリ結果が返されます。これは、prescript.shおよびpostscript.shスクリプトが2024-08-27 15:27:55から2024-08-27 15:27:57まで実行されている間に、データベースの挿入操作が中断されたことを示します。 この場合、アプリケーション整合性スナップショットは、スナップショットが作成された時点でのアプリケーションとデータベース間のデータ整合性を保証することができる。

      image

手順7: アプリケーションの一貫性のあるスナップショットを使用してデータを期待どおりに復元できるかどうかを確認します

アプリケーション一貫性のあるスナップショットを使用して、Linux ECSインスタンスのデータを復元します。 次に、MySQLデータの最後の書き込み時間とprescript.shスクリプトの実行が開始された時間を比較して、データがアプリケーションの一貫性のあるスナップショットで適切にバックアップされ、期待どおりにスナップショットから復元されたかどうかを判断します。

  1. ECSコンソールで、作成したスナップショット整合性グループを使用して、Linux ECSインスタンスのデータをロールバックします。

  2. MySQLにログインし、PointInTimeテーブルのコンテンツを照会します。

    1. Linux ECSインスタンスに接続します。

      詳細については、「パスワードまたはキーを使用したLinuxインスタンスへの接続」をご参照ください。

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

      次のコマンドを入力し、Enterキーを押して、指示に従ってMySQLパスワードを入力します。

      mysql -u <mysqlUserName> -p

      <mysqlUserName> を実際のMySQLユーザー名に置き換えます。

    3. PointInTimeテーブルのコンテンツを照会します。

      USE AdventureWorks;
      SELECT * FROM PointInTime;

      次のクエリ結果が返されます。

      image

      データベースが中断される前に、挿入操作が中断されました。 この例では、データを復元するために作成したスナップショット整合性グループのアプリケーション整合性スナップショットを使用した後、MySQLデータベースへの最終書き込み時間は2024-08-27 15:27:54です。 最後の書き込み時間は、ステップ6で取得した2024-08-27 15:27:55に先行します。これは、prescript.shスクリプトの実行が開始された時間です。 この場合、MySQLデータはアプリケーション一貫性のあるスナップショットで適切にバックアップされています。