

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 刪除堆疊後復原 DLT 資料
<a name="recover-data-after-stack-deletion"></a>

本節說明如何還原測試案例，並在刪除原始堆疊之後，在新的 DLT 堆疊中執行歷史記錄。當客戶的 S3 儲存貯體和 DynamoDB 資料表保留時 （預設行為），且客戶想要將其重新連線至新的部署時，就會套用此規則。

## 背景介紹
<a name="recovery-background"></a>

刪除 DLT 堆疊時，由於資料保護政策，下列資源會保留在客戶的 AWS 帳戶中：


| 資源 | Contains | 命名 | 
| --- | --- | --- | 
| 案例 S3 儲存貯體 | 測試指令碼 (JMeter/K6/Locust)、每個任務結果 XML 檔案、JMeter 架構資產 | 自動產生 （例如，`dltstack-scenariosbucket-abc123`) | 
| 日誌 S3 儲存貯體 | 所有 DLT 儲存貯體的 S3 存取日誌 | 自動產生 | 
| 主控台 S3 儲存貯體 | Web UI 靜態資產 | 自動產生 | 
| 案例 DynamoDB 資料表 | 測試定義、組態、排程規則 | 自動產生 （例如 `DLTStack-ScenariosTable-xyz789`) | 
| 歷史記錄 DynamoDB 資料表 | 測試執行結果、持續時間、成功率 | 自動產生 （例如 `DLTStack-HistoryTable-xyz789`) | 
| CloudWatch 日誌群組 | Lambda 和 ECS 執行日誌 (10 年保留期） | 依函數命名 | 

CloudFormation 會自動產生所有資源名稱。部署新堆疊時，它們無法預測，也無法指定為參數。

## 重要限制條件
<a name="recovery-important-constraints"></a>

1. DLT CloudFormation 範本不接受現有 DynamoDB 資料表或 S3 儲存貯體的參數。新部署一律會建立新的資源。

1. 直接修改堆疊外部的 CloudFormation 受管資源會導致堆疊偏離。所有資料遷移都必須發生在資料層級，而非基礎設施層級。

1. 每次新部署都會隨機產生解決方案 UUID。新堆疊的 UUID 將與原始堆疊不同。

1. DynamoDB 資料表預設會Point-in-Time復原 (PITR)，提供過去 35 天的連續備份。

## 復原程序
<a name="recovery-process"></a>

### 步驟 1：識別保留的資源
<a name="recovery-step-1-identify-retained-resources"></a>

部署新的堆疊之前，請從已刪除的堆疊找到保留的資源。

```
# List retained DynamoDB tables (look for DLT naming patterns)
aws dynamodb list-tables --query "TableNames[?contains(@, 'ScenariosTable') || contains(@, 'HistoryTable')]"

# List retained S3 buckets (look for DLT naming patterns)
aws s3api list-buckets --query "Buckets[?contains(Name, 'dlttestrunnerstoragedlts') || contains(Name, 'dltconsoleresourcesdltda')]"
```

如果您在刪除之前記下 CloudFormation 堆疊輸出，請使用這些確切名稱。相關輸出為：
+  `ScenariosBucket` — S3 儲存貯體名稱
+  `ScenariosTable` — DynamoDB 案例資料表名稱

對於未公開為堆疊輸出的資源 （例如歷史記錄表），請在刪除`list-stack-resources`前使用 來取得實體資源 IDs。此命令會列出堆疊中的每個資源，無論其是否具有對應的輸出。

### 步驟 2：部署新的 DLT 堆疊
<a name="recovery-step-2-deploy-new-stack"></a>

使用相同的 CloudFormation 範本版本 （或更新版本） 部署新的 DLT 堆疊。使用與原始部署相同的參數 (VPC 設定、管理員電子郵件等）。

```
aws cloudformation create-stack \
  --stack-name distributed-load-testing-new \
  --template-url https://s3.amazonaws.com/solutions-reference/distributed-load-testing-on-aws/latest/distributed-load-testing-on-aws.template \
  --parameters ParameterKey=AdminName,ParameterValue=<admin-name> \
               ParameterKey=AdminEmail,ParameterValue=<admin-email> \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND
```

等待堆疊達到`CREATE_COMPLETE`狀態。

### 步驟 3：識別新堆疊的資源
<a name="recovery-step-3-identify-new-stack-resources"></a>

從新堆疊的輸出擷取資源名稱。

```
aws cloudformation describe-stacks \
  --stack-name distributed-load-testing-new \
  --query "Stacks[0].Outputs"
```

請注意下列項目的值：
+  `ScenariosBucket` （新的儲存貯體名稱）
+  `ScenariosTable` （新的資料表名稱）

對於未公開為堆疊輸出的任何資源 （例如歷史記錄表），請使用 `list-stack-resources`依其邏輯 ID 來尋找它：

```
aws cloudformation list-stack-resources \
  --stack-name distributed-load-testing-new \
  --query "StackResourceSummaries[?contains(LogicalResourceId, 'HistoryTable')].{LogicalId:LogicalResourceId,PhysicalId:PhysicalResourceId}"
```

此命令會列出堆疊管理的每個資源。您可以依邏輯 ID 子字串進行篩選，以尋找任何資源。

### 步驟 4：遷移 DynamoDB 資料
<a name="recovery-step-4-migrate-dynamodb"></a>

從保留資料表匯出資料，並將其匯入新資料表。使用 DynamoDB 資料匯出或scan-and-write操作。

 **選項 A：使用 DynamoDB 匯出/匯入 （建議用於大型資料集）** 

對於具有數千個項目的資料表，請使用 DynamoDB 匯出至 S3，然後匯入：

```
# Export from retained table to S3
aws dynamodb export-table-to-point-in-time \
  --table-arn arn:aws:dynamodb:<region>:<account>:table/<old-scenarios-table> \
  --s3-bucket <temporary-export-bucket> \
  --s3-prefix dlt-migration/scenarios/ \
  --export-format DYNAMODB_JSON

# Wait for export to complete, then import into new table
aws dynamodb import-table \
  --s3-bucket-source S3Bucket=<temporary-export-bucket>,S3KeyPrefix=dlt-migration/scenarios/ \
  --table-creation-parameters '{"TableName":"<new-scenarios-table>","KeySchema":[{"AttributeName":"testId","KeyType":"HASH"}],"AttributeDefinitions":[{"AttributeName":"testId","AttributeType":"S"}],"BillingMode":"PAY_PER_REQUEST"}' \
  --input-format DYNAMODB_JSON
```

**注意**  
`import-table` API 會建立新的資料表。由於新的堆疊已建立目標資料表，請改用選項 B，或先刪除新的空白資料表，並透過匯入重新建立它 （這會導致堆疊偏離，請參閱下列警告）。

 **選項 B：掃描和 BatchWrite （建議）** 

此方法會直接從保留的資料表讀取，並寫入新堆疊的資料表，而不會造成堆疊偏離。它需要 Python 3 和程式`boto3`庫。

```
# Install boto3 if not already available
pip install boto3
```

```
#!/usr/bin/env python3
"""Migrate DynamoDB items directly from retained tables to new stack tables."""

import boto3

dynamodb = boto3.resource("dynamodb", region_name="<region>")

def migrate_table(source_table_name, target_table_name):
    source = dynamodb.Table(source_table_name)
    target = dynamodb.Table(target_table_name)

    # Scan all items from the retained table (handles pagination automatically)
    items = []
    response = source.scan()
    items.extend(response["Items"])
    while "LastEvaluatedKey" in response:
        response = source.scan(ExclusiveStartKey=response["LastEvaluatedKey"])
        items.extend(response["Items"])

    print(f"Scanned {len(items)} items from {source_table_name}")

    # Write items to the new table using batch_writer (handles batching automatically)
    with target.batch_writer() as batch:
        for item in items:
            batch.put_item(Item=item)

    print(f"Wrote {len(items)} items to {target_table_name}")

# Migrate scenarios
migrate_table("<old-scenarios-table>", "<new-scenarios-table>")

# Migrate history
migrate_table("<old-history-table>", "<new-history-table>")
```

對於大型資料表 （數萬個項目），請考慮使用平行掃描區段來加速讀取階段。

 **選項 C：從 PITR 還原 （如果在 35 天時段內）** 

如果在過去 35 天內刪除堆疊並啟用 PITR （預設為 )，您可以將資料表還原至某個時間點。不過，PITR 還原會使用不同的名稱建立新的資料表，因此您仍然需要使用選項 B 將資料複製到堆疊受管資料表。

```
# Restore to a new temporary table
aws dynamodb restore-table-to-point-in-time \
  --source-table-name <old-scenarios-table> \
  --target-table-name dlt-scenarios-restored \
  --restore-date-time <timestamp-before-deletion>

# Then scan from dlt-scenarios-restored and batch-write into the new stack's table
```

### 步驟 5：遷移 S3 資料
<a name="recovery-step-5-migrate-s3"></a>

將測試指令碼和結果檔案從保留的儲存貯體複製到新堆疊的儲存貯體。

```
# Copy all objects from the old scenarios bucket to the new one
aws s3 sync \
  s3://<old-scenarios-bucket> \
  s3://<new-scenarios-bucket> \
  --source-region <region> \
  --region <region>
```

這會複製：
+ 測試指令碼 (JMeter `.jmx` 檔案、K6 指令碼、Locust 檔案、ZIP 封存）
+ 測試結果 XML 檔案，依測試 ID 和區域組織
+ JMeter 架構資產和外掛程式

### 步驟 6：驗證遷移
<a name="recovery-step-6-verify"></a>

1. 使用新堆疊的 URL （可在`WebConsole`堆疊輸出中找到） 登入 DLT Web 主控台。

1. 確認所有測試案例都顯示在案例清單中。

1. 開啟個別案例，並確認測試執行歷史記錄可見。

1. 確認測試指令碼可從案例詳細資訊頁面下載。

1. 執行小型測試，以驗證新堆疊的end-to-end功能。

### 步驟 7：清除保留的資源
<a name="recovery-step-7-clean-up"></a>

驗證所有資料已成功遷移後，請刪除舊的保留資源，以避免持續的儲存成本。

```
# Delete old DynamoDB tables
aws dynamodb delete-table --table-name <old-scenarios-table>
aws dynamodb delete-table --table-name <old-history-table>

# Empty and delete old S3 buckets
aws s3 rm s3://<old-scenarios-bucket> --recursive
aws s3api delete-bucket --bucket <old-scenarios-bucket>

aws s3 rm s3://<old-logs-bucket> --recursive
aws s3api delete-bucket --bucket <old-logs-bucket>

aws s3 rm s3://<old-console-bucket> --recursive
aws s3api delete-bucket --bucket <old-console-bucket>
```

只有在確認新堆疊可完整運作且所有歷史資料皆完好之後，才能執行此步驟。

## 避免堆疊偏離
<a name="recovery-avoiding-stack-drift"></a>

當資源的實際狀態與 CloudFormation 預期不同時，就會發生堆疊偏離。若要避免在此復原程序期間發生偏離：
+ 請勿直接重新命名或修改新堆疊的 DynamoDB 資料表或 S3 儲存貯體。
+ 請勿使用 `import-table`取代新堆疊的資料表 （這需要先刪除 CloudFormation 受管資料表）。
+ 請勿在 CloudFormation 外部修改 IAM 政策、儲存貯體政策或資料表設定。
+ 請僅使用資料層級操作：`PutItem`、`BatchWriteItem`、`s3 sync`、`s3 cp`。
+ 將資料寫入 CloudFormation 建立的資料表和儲存貯體。將項目新增至 DynamoDB 資料表或物件新增至 S3 儲存貯體並不構成偏離。

將資料寫入 CloudFormation 受管資料表和儲存貯體是安全的，因為 CloudFormation 會追蹤資源組態 （資料表結構描述、計費模式、加密設定），而不是資料內容。

## 無法復原的內容
<a name="recovery-what-cannot-be-recovered"></a>

刪除堆疊且無法透過此程序還原時，會遺失下列項目：


| 項目 | Reason | 
| --- | --- | 
| Cognito 使用者帳戶 | 使用堆疊刪除使用者集區。使用者必須重新註冊。 | 
| 作用中 EventBridge 排程 | 排程測試規則已刪除。在 DLT UI 中手動重新建立排程。 | 
| CloudWatch 儀表板 | 每個測試儀表板 (`EcsLoadTesting*`) 都會刪除。新執行會建立新的儀表板。 | 
| 解決方案 UUID | 會產生新的隨機 UUID。這只會影響操作指標的相互關聯。 | 
| 區域堆疊關聯 | 區域堆疊必須重新部署，並與新的中樞堆疊重新關聯。 | 

## 預防性措施
<a name="recovery-preventive-measures"></a>

若要簡化未來的復原案例：

1. 在任何刪除之前記錄堆疊輸出。儲存 `ScenariosBucket`、 `ScenariosTable`和 歷史記錄資料表名稱。

1. 啟用 DynamoDB PITR （預設在 DLT 中啟用）。確認其保持作用中狀態。

1. 啟用 S3 版本控制 （在案例儲存貯體上預設為啟用）。這可避免意外刪除物件。

1. 請考慮在案例和歷史記錄表上啟用 DynamoDB 刪除保護，作為額外的保護：

   ```
   aws dynamodb update-table \
     --table-name <scenarios-table> \
     --deletion-protection-enabled
   ```

1. 使用 AWS Backup 建立 DynamoDB 資料表的排程備份，以長期保留超過 35 天 PITR 時段。