在建立應用一致性快照時,系統會暫停正在寫入的資料,確保快照捕獲到的資料的完整性和一致性。通過應用一致性快照復原雲端硬碟,資料不會損壞和丟失,可以確保應用(例如MySQL)處於一致性的啟動狀態。本文以在Linux執行個體部署MySQL資料庫為例,驗證應用一致性快照的資料備份效果。
前提條件
ECS執行個體的作業系統是CentOS 7.6及以上版本、Ubuntu 18.04及以上版本或Alibaba Cloud Linux 2。
ECS執行個體的雲端硬碟類型是ESSD雲端硬碟,且雲端硬碟未開啟多重掛載功能。
ECS執行個體已安裝雲助手Agent。具體操作,請參見安裝雲助手Agent。
您已安裝MySQL資料庫,並知悉資料庫的登入名稱及密碼。具體操作,請參見部署MySQL資料庫(Linux)。
操作步驟
本操作以CentOS 7.9作業系統安裝的MySQL 8.0來驗證應用一致性快照的資料備份效果為例,請您根據實際環境進行操作。
步驟一:準備資料庫驗證環境
準備資料庫驗證環境(資料庫表、預存程序等),用於後續驗證應用程式與資料庫的互動是否正常。
使用root使用者遠端連線ECS執行個體。
具體操作,請參見通過密碼或密鑰認證登入Linux執行個體。
建立測試指令碼(/root/test.sql)。
建立並開啟測試指令碼(/root/test.sql)。
vim /root/test.sql
輸入
i
,進入編輯模式。編寫驗證的SQL指令碼。
SQL指令碼中內容包含建立資料庫表(PointInTime)及驗證預存程序(TestPIT),具體內容如下所示。
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 ;
按
Esc
鍵,並輸入:wq
,然後按斷行符號鍵,退出並儲存內容。
登入MySQL資料庫。
輸入以下命令,按斷行符號鍵,並根據介面提示輸入MySQL密碼。
mysql -u <mysqlUserName> -p
其中
<mysqlUserName>
需替換為您的MySQL使用者名稱。建立新的資料庫AdventureWorks。
CREATE DATABASE AdventureWorks;
執行測試指令碼。
source /root/test.sql
退出資料庫。
exit
步驟二:建立prescript.sh和postscript.sh指令碼
此操作介紹如何為MySQL建立prescript.sh和postscript.sh指令碼,在建立應用一致性快照時需要使用這兩個指令碼。
本文中使用的prescript.sh和postscript.sh指令碼,指令碼內容僅為驗證樣本使用。如果您需要為自己的業務應用建立應用一致性快照,需要根據業務情境編寫對應的prescript.sh和postscript.sh指令碼。
使用root使用者遠端連線ECS執行個體。
具體操作,請參見通過密碼或密鑰認證登入Linux執行個體。
建立/tmp/prescript.sh指令碼並寫入指令碼內容。
使用root使用者建立/tmp/prescript.sh。
vim /tmp/prescript.sh
輸入
i
,進入編輯模式。在指令碼中根據應用自訂指令碼內容。
本文中使用以下指令碼內容:
TIMESTAMP=`date +%s` MYSQL_TEMP_FILE_NAME="/tmp/mysqlfreeze${TIMESTAMP}.tmp" LOG_FILE_NAME="/tmp/mysqlfreeze${TIMESTAMP}.log" # 設定您的MySQL使用者名稱 export MYSQL_USER="$MYSQL_USER" # 設定您的MySQL密碼 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
,然後按斷行符號鍵,退出並儲存內容。為指令碼設定僅root使用者讀、寫和執行許可權。
重要為了保證指令碼的執行安全,請確保指令碼僅root使用者具有讀、寫及執行許可權,即許可權為700,否則執行指令碼時會判斷失敗。
chmod 700 /tmp/prescript.sh
建立/tmp/postscript.sh指令碼並寫入指令碼內容。
使用root使用者建立/tmp/postscript.sh。
vim /tmp/postscript.sh
輸入
i
,進入編輯模式。在指令碼中根據應用自訂指令碼內容。
本文中使用以下指令碼內容:
TIMESTAMP=`date +%s` MYSQL_TEMP_FILE_NAME="/tmp/mysqlthaw${TIMESTAMP}.tmp" LOG_FILE_NAME="/tmp/mysqlthaw${TIMESTAMP}.log" # 設定您的MySQL使用者名稱 export MYSQL_USER="$MYSQL_USER" # 設定您的MySQL密碼 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
,然後按斷行符號鍵,退出並儲存內容。為指令碼設定僅root使用者的讀、寫和執行許可權。
重要為了保證指令碼的執行安全,請確保指令碼僅root使用者具有讀、寫及執行許可權,許可權為700,否則執行指令碼時會判斷失敗。
chmod 700 /tmp/postscript.sh
進入/tmp目錄查看指令碼許可權是否正確。
cd /tmp ls -l
結果如下所示,表示指令碼許可權正確。
步驟三:為ECS執行個體授予RAM角色
開啟應用一致性快照前,必須先為ECS執行個體配置相關的RAM角色,賦予ECS執行個體查詢快照、建立快照等相關許可權。
登入RAM控制台。
建立應用一致性快照相關的RAM角色、為RAM角色授權並授予ECS執行個體。具體操作,請參見建立ECS執行個體RAM角色並授予給ECS。其中:
RAM角色:樣本名稱為AppSnapshotRoleName
可信實體類型:阿里雲服務
自訂權限原則:樣本名稱為AppSnapshotPolicy,內容如下:
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "ecs:DescribeSnapshot*", "ecs:CreateSnapshot*", "ecs:TagResources", "ecs:DescribeDisks" ], "Resource": [ "*" ], "Condition": {} } ] }
該策略具有查詢快照相關資訊、建立快照、設定標籤和查詢雲端硬碟資訊等許可權。
步驟四:在資料庫中調用預存程序(TestPIT)
應用一致性快照能夠暫停資料庫狀態,在建立快照前調用資料庫預存程序用於類比資料插入操作,後續建立應用一致性快照時,方便查看資料庫的暫停效果和復原資料後的效果。
登入MySQL資料庫。
輸入以下命令,按斷行符號鍵,並根據介面提示輸入MySQL密碼。
mysql -u <mysqlUserName> -p
其中
<mysqlUserName>
需替換為您的MySQL使用者名稱。切換到AdventureWorks資料庫。
USE AdventureWorks;
調用預存程序(TestPIT)。
CALL TestPIT;
重要在驗證過程中,您需要在TestPIT運行(大概3分鐘左右)完成前建立應用一致性快照,否則不好驗證應用一致性快照的效果。
步驟五:通過控制台建立應用一致性快照
此操作介紹如何在控制台為MySQL資料庫所在的Linux執行個體建立應用一致性快照。
進入ECS執行個體列表頁面。
登入ECS管理主控台。
在左側導覽列,選擇 。
在頂部功能表列處,選擇目標ECS執行個體所在地區。
找到目標執行個體,在操作列選擇
。在建立快照一致性組對話方塊中,設定參數。
選擇需要建立快照一致性組的ESSD雲端硬碟並設定其他快照參數。
設定應用一致性快照。
選中啟用應用一致性快照,並設定prescript.sh指令碼和postscript.sh指令碼的路徑資訊。指令碼路徑資訊需要和前面步驟建立的指令碼路徑一致。具體指令碼資訊,請參見步驟二:建立prescript.sh和postscript.sh指令碼。
單擊確定。
建立後會返回雲助手命令ID和命令執行ID,您可以根據命令執行ID查看建立結果。
步驟六:驗證是否成功建立應用一致性快照
此操作介紹如何在ECS管理主控台查看應用一致性快照建立結果,並在資料庫中查看資料暫停提交的效果。
在雲助手頁面,查看命令執行結果。
在雲助手的返回資訊中,查看應用暫停時間。
在返回資訊中,找到prescript.sh指令碼開始時間和postscript.sh指令碼完成時間。
prescript.sh指令碼開始時間為
2024-08-27 15:27:55
。postscript.sh指令碼結束執行時間為
2024-08-27 15:27:57
。
在快照頁面查看快照一致性組和雲端硬碟快照資訊。
在左側導覽列,選擇 。
單擊快照一致性組頁簽,找到已建立的快照一致性組,單擊快照一致性組ID查看快照詳情。
在快照資訊地區,根據快照的標籤資訊,檢查是否成功建立應用一致性快照。
樣本中雲端硬碟快照的標籤顯示
APPConsistent:True
,表示建立的是應用一致性快照。
串連MySQL資料庫,查看資料暫停提交時間。
遠端連線ECS執行個體。
具體操作,請參見通過密碼或密鑰認證登入Linux執行個體。
登入MySQL資料庫。
輸入以下命令,按斷行符號鍵,並根據介面提示輸入MySQL密碼。
mysql -u <mysqlUserName> -p
其中
<mysqlUserName>
需替換為您的MySQL使用者名稱。查詢資料庫表PointInTime的內容。
USE AdventureWorks; SELECT * FROM PointInTime;
查詢結果如下所示,在prescript.sh指令碼和postscript.sh指令碼執行過程中(
2024-08-27 15:27:55
~2024-08-27 15:27:57
),資料庫寫入暫停提交。說明應用一致性快照可以確保在快照建立瞬間,應用程式與資料庫資料的一致性。
步驟七:驗證通過應用一致性快照恢複資料的效果
先通過應用一致性快照恢複資料,然後將MySQL資料最後寫入時間與prescript.sh指令碼執行的時間做對比,來判斷應用一致性快照的資料恢複是否正確。
在ECS管理主控台,通過上面建立的快照一致性組復原ECS執行個體。
具體操作,請參見通過快照一致性組復原雲端硬碟。
登入MySQL並查詢資料庫表PointInTime的內容。
遠端連線ECS執行個體。
具體操作,請參見通過密碼或密鑰認證登入Linux執行個體。
登入MySQL資料庫。
輸入以下命令,按斷行符號鍵,並根據介面提示輸入MySQL密碼。
mysql -u <mysqlUserName> -p
其中
<mysqlUserName>
需替換為您的MySQL使用者名稱。查詢資料庫表PointInTime的內容。
USE AdventureWorks; SELECT * FROM PointInTime;
查詢結果如下所示。
資料庫暫停成功之前會停止插入資料。使用應用一致性的快照一致性組恢複資料後,最後一條資料對應的時間為
2024-08-27 15:27:54
,早於步驟六中查詢的暫停時間點2024-08-27 15:27:55
。因此證明關於MySQL的應用一致性快照備份的結果是正確的。