Help us improve the AWS re:Post Knowledge Center by sharing your feedback in a brief survey. Your input can influence how we create and update our content to better support your AWS journey.
如何同時變更多個 Amazon DynamoDB 表的容量模式?
我想要同時變更多個 Amazon DynamoDB 表的容量模式。
簡短描述
當變更多個 DynamoDB 表的容量模式時,必須指定佈建容量模式或隨需容量模式。在變更容量模式之前,請參閱在 DynamoDB 中切換容量模式時的注意事項。
若要同時變更多個 DynamoDB 表的容量模式,請使用下列其中一種方法:
- AWS Command Line Interface (AWS CLI)
- AWS CloudFormation
- Python
解決方法
最佳做法
在變更多個 DynamoDB 表的容量模式時,請遵循以下最佳做法:
- 在啟動變更之前,請設定適當的 AWS CLI 憑證。
- 請確認您擁有適當的 AWS Identity and Access Management (IAM) 權限。
- 先將您的變更部署到非生產環境。
- 等待幾分鐘讓每張資料表完成切換。
- 每張資料表每 24 小時僅可切換一次容量模式。
- 分析使用模式以選取適當的容量模式,並根據 AWS 區域要求進行調整。
- 監控切換後的成本,以確保您擁有適當的佈建容量。
AWS CLI
**注意:**如果您在執行 AWS Command Line Interface (AWS CLI) 命令時收到錯誤訊息,請參閱對 AWS CLI 錯誤進行疑難排解。此外,請確定您使用的是最新的 AWS CLI 版本。
佈建模式
若要使用 AWS CLI 將多個 DynamoDB 表的容量模式變更為佈建模式,請完成下列步驟:
-
開啟文字編輯器,輸入以下程式碼來建立一個新的 shell 指令碼:
#!/bin/bash # Set the AWS region AWS_REGION=[REGION] # Change this to your desired region # OPTION1: List of table names you want to switch TABLES=("table1" "table2" "table3") # OPTION2: Get all table names in the account TABLES=$(aws dynamodb list-tables —region $AWS_REGION —query 'TableNames[]' —output text) # Default provisioned capacity units READ_CAPACITY=READ_CAPACITY_VALUE WRITE_CAPACITY=WRITE_CAPACITY_VALUE echo "Using AWS Region: $AWS_REGION" for TABLE_NAME in $TABLES do # Check current billing mode CURRENT_MODE=$(aws dynamodb describe-table —region $AWS_REGION —table-name $TABLE_NAME —query 'Table.BillingModeSummary.BillingMode' —output text) if [ "$CURRENT_MODE" = "PAY_PER_REQUEST" ]; then echo "Processing table: $TABLE_NAME" # Get GSI configurations GSI_CONFIG="" GSI_LIST=$(aws dynamodb describe-table —region $AWS_REGION —table-name $TABLE_NAME —query 'Table.GlobalSecondaryIndexes[*].IndexName' —output text) if [ ! -z "$GSI_LIST" ]; then echo "Found GSIs: $GSI_LIST" # Build GSI provisioned throughput configuration GSI_CONFIG="—global-secondary-index-updates“ for GSI_NAME in $GSI_LIST do if [ -z "$FIRST_GSI" ]; then GSI_CONFIG="$GSI_CONFIG [{\"Update\":{\"IndexName\":\"$GSI_NAME\",\"ProvisionedThroughput\":{\"ReadCapacityUnits\":$READ_CAPACITY,\"WriteCapacityUnits\":$WRITE_CAPACITY}}}" FIRST_GSI="false" else GSI_CONFIG="$GSI_CONFIG,{\"Update\":{\"IndexName\":\"$GSI_NAME\",\"ProvisionedThroughput\":{\"ReadCapacityUnits\":$READ_CAPACITY,\"WriteCapacityUnits\":$WRITE_CAPACITY}}}" fi done GSI_CONFIG="$GSI_CONFIG]" fi # Update table and GSIs if [ ! -z "$GSI_CONFIG" ]; then echo "Updating table and GSIs..." aws dynamodb update-table \ --region $AWS_REGION \ --table-name $TABLE_NAME \ --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=$READ_CAPACITY,WriteCapacityUnits=$WRITE_CAPACITY \ $GSI_CONFIG else echo "Updating table (no GSIs)..." aws dynamodb update-table \ --region $AWS_REGION \ --table-name $TABLE_NAME \ --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=$READ_CAPACITY,WriteCapacityUnits=$WRITE_CAPACITY fi echo "Request submitted for $TABLE_NAME" else echo "Skipping $TABLE_NAME - already in PROVISIONED mode" fi # Reset GSI tracking for next table FIRST_GSI="" echo "----------------------------------------" done若要將所有 DynamoDB 表的容量模式變更為隨需模式,請移除下列程式碼片段:
#OPTION1: List of table names you want to switch TABLES=("table1" "table2" "table3")若要將特定 DynamoDB 表的容量模式變更為隨需模式,請將 “table1” “table2” “table3” 替換為您的資料表名稱。然後,移除以下程式碼片段:
#OPTION2: Get all table names in the account TABLES=$(aws dynamodb list-tables —query 'TableNames[]' —output text)**注意:**將 READ_CAPACITY_VALUE 和 WRITE_CAPACITY_VALUE 替換為您的讀取和寫入容量值。
-
使用名稱 switch-all-tables-with-gsi-to-provisioned.sh 儲存該檔案。
-
若要使檔案可執行,請開啟終端並執行以下命令:
chmod +x switch-all-tables-with-gsi-to-provisioned.sh -
若要在終端中執行 shell 指令碼,請執行以下命令:
./switch-all-tables-with-gsi-to-provisioned.sh
隨需模式
若要使用 AWS CLI 將多個 DynamoDB 表的容量模式變更為隨需模式,請完成下列步驟:
-
開啟文字編輯器,然後輸入以下程式碼來建立新的 shell 指令碼:
#!/bin/bash # Set the AWS region AWS_REGION=[REGION] # Change this to your desired region # OPTION1: List of table names you want to switch TABLES=("table1" "table2" "table3") # OPTION2: Get all table names in the account #TABLES=$(aws dynamodb list-tables --region $AWS_REGION --query 'TableNames[]' --output text) for TABLE_NAME in $TABLES do # Check current billing mode CURRENT_MODE=$(aws dynamodb describe-table --region $AWS_REGION --table-name $TABLE_NAME --query 'Table.BillingModeSummary.BillingMode' --output text) if [ "$CURRENT_MODE" = "PROVISIONED" ]; then echo "Processing table: $TABLE_NAME" # Check if table has any GSIs GSI_LIST=$(aws dynamodb describe-table --region $AWS_REGION --table-name $TABLE_NAME --query 'Table.GlobalSecondaryIndexes[*].IndexName' --output text) if [ ! -z "$GSI_LIST" ]; then echo "Table has GSIs: $GSI_LIST" echo "Note: GSIs will automatically switch to On-Demand with the table" fi # Update table to On-Demand echo "Switching $TABLE_NAME to PAY_PER_REQUEST mode..." aws dynamodb update-table \ --region $AWS_REGION \ --table-name $TABLE_NAME \ --billing-mode PAY_PER_REQUEST echo "Request submitted for $TABLE_NAME" else echo "Skipping $TABLE_NAME - already in PAY_PER_REQUEST mode" fi echo "----------------------------------------" done若要將所有 DynamoDB 表的容量模式變更為隨需模式,請移除下列程式碼片段:
#OPTION1: List of table names you want to switch TABLES=("table1" "table2" "table3")若要將特定 DynamoDB 表的容量模式變更為隨需模式,請將 “table1” “table2” “table3” 替換為您的資料表名稱。然後,移除以下程式碼片段:
`#OPTION2: Get all table names in the account` TABLES=$(aws dynamodb list-tables —region $AWS\_REGION —query 'TableNames\[\]' —output text)**注意:**將 REGION 替換為您的 Region。使用區域代碼,例如 us-east-1。
-
若要使檔案可執行,請開啟終端並執行命令:
chmod +x switch-all-tables-with-gsi-to-ondemand.sh -
若要在終端中執行 shell 指令碼,請執行命令:
./switch-all-tables-with-gsi-to-ondemand.sh
CloudFormation
請使用下列最佳做法:
- 將 AWS Lambda 範本設定為使用 Python 3.9 執行時期。
- 監控 Amazon CloudWatch Logs 以追蹤 Lambda 函式的進度。
**注意:**開始之前,請設定您的 AWS 憑證。執行以下設定 AWS CLI 命令:
aws configure
佈建模式
若要使用 CloudFormation 將多個 DynamoDB 表的容量模式變更為佈建模式,請完成下列步驟:
-
開啟文字編輯器並輸入以下程式碼,以建立新的 YAML 檔案:
AWSTemplateFormatVersion: '2010-09-09' Description: 'Switch specific DynamoDB tables from On-Demand to Provisioned capacity mode' Parameters: ReadCapacityUnits: Type: Number Default: 5 Description: Read Capacity Units for tables and GSIs WriteCapacityUnits: Type: Number Default: 5 Description: Write Capacity Units for tables and GSIs TableNames: Type: CommaDelimitedList Description: Comma-separated list of DynamoDB table names to update Resources: DynamoDBTableUpdates: Type: Custom::DynamoDBTableUpdates Properties: ServiceToken: !GetAtt UpdateTablesFunction.Arn ReadCapacityUnits: !Ref ReadCapacityUnits WriteCapacityUnits: !Ref WriteCapacityUnits TableNames: !Ref TableNames UpdateTablesFunction: Type: AWS::Lambda::Function Properties: Runtime: python3.9 Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: | import boto3 import cfnresponse def handler(event, context): try: if event['RequestType'] in ['Create', 'Update']: dynamodb = boto3.client('dynamodb') # Get parameters read_capacity = event['ResourceProperties']['ReadCapacityUnits'] write_capacity = event['ResourceProperties']['WriteCapacityUnits'] table_names = event['ResourceProperties']['TableNames'] for table_name in table_names: try: # Get table details table = dynamodb.describe_table(TableName=table_name)['Table'] current_mode = table.get('BillingModeSummary', {}).get('BillingMode', '') if current_mode == 'PAY_PER_REQUEST': # Prepare GSI updates if any gsi_updates = [] if 'GlobalSecondaryIndexes' in table: for gsi in table['GlobalSecondaryIndexes']: gsi_updates.append({ 'Update': { 'IndexName': gsi['IndexName'], 'ProvisionedThroughput': { 'ReadCapacityUnits': int(read_capacity), 'WriteCapacityUnits': int(write_capacity) } } }) # Update table update_params = { 'TableName': table_name, 'BillingMode': 'PROVISIONED', 'ProvisionedThroughput': { 'ReadCapacityUnits': int(read_capacity), 'WriteCapacityUnits': int(write_capacity) } } if gsi_updates: update_params['GlobalSecondaryIndexUpdates'] = gsi_updates dynamodb.update_table(**update_params) print(f"Switching {table_name} to PROVISIONED mode") else: print(f"Table {table_name} is not in PAY_PER_REQUEST mode. Skipping.") except Exception as e: print(f"Error processing table {table_name}: {str(e)}") continue cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) else: cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, {}) LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: DynamoDBAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:UpdateTable Resource: '*' -
使用名稱 switch-to-provisioned.yaml 儲存該檔案。
-
執行以下 create-stack AWS CLI 命令:
# For Provisioned mode aws cloudformation create-stack \ --stack-name switch-to-provisioned \ --template-body file://switch-to-provisioned.yaml \ --capabilities CAPABILITY_IAM \ --region [REGION] \ --parameters ParameterKey=TableNames,ParameterValue="Table1,Table2,Table3" \ ParameterKey=ReadCapacityUnits,ParameterValue=[RCU_VALUE] \ ParameterKey=WriteCapacityUnits,ParameterValue=[WCU_VALUE]**注意:**將 “Table1,Table2,Table3” 替換為您的資料表名稱,將 RCU_VALUE 和 WCU_VALUE 替換為您的 RCU 和 WCU 值,並將 REGION 替換為您的區域,例如 us-east-1。
隨需模式
若要使用 CloudFormation 將多個 DynamoDB 表的容量模式變更為隨需模式,請完成下列步驟:
-
開啟文字編輯器並輸入以下程式碼,以建立新的 YAML 檔案:
AWSTemplateFormatVersion: '2010-09-09' Description: 'Switch specific DynamoDB tables from Provisioned to On-Demand capacity mode' Parameters: TableNames: Type: CommaDelimitedList Description: Comma-separated list of DynamoDB table names to update Resources: DynamoDBTableUpdates: Type: Custom::DynamoDBTableUpdates Properties: ServiceToken: !GetAtt UpdateTablesFunction.Arn TableNames: !Ref TableNames UpdateTablesFunction: Type: AWS::Lambda::Function Properties: Runtime: python3.9 Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: | import boto3 import cfnresponse def handler(event, context): try: if event['RequestType'] in ['Create', 'Update']: dynamodb = boto3.client('dynamodb') # Get table names from the event table_names = event['ResourceProperties']['TableNames'] for table_name in table_names: try: # Get table details table = dynamodb.describe_table(TableName=table_name)['Table'] current_mode = table.get('BillingModeSummary', {}).get('BillingMode', '') if current_mode == 'PROVISIONED': # Update table to On-Demand dynamodb.update_table( TableName=table_name, BillingMode='PAY_PER_REQUEST' ) print(f"Switching {table_name} to PAY_PER_REQUEST mode") else: print(f"Table {table_name} is not in PROVISIONED mode. Skipping.") except Exception as e: print(f"Error processing table {table_name}: {str(e)}") continue cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) else: cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, {}) LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: DynamoDBAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:UpdateTable Resource: '*' -
儲存該檔案,並將其命名為 switch-to-ondemand.yaml。
-
執行以下 create-stack AWS CLI 命令:
# For On-Demand mode aws cloudformation create-stack \ --stack-name switch-to-ondemand \ --template-body file://switch-to-ondemand.yaml \ --capabilities CAPABILITY_IAM \ --region [REGION] \ --parameters ParameterKey=TableNames,ParameterValue="Table1,Table2,Table3"**注意:**將 “Table1,Table2,Table3” 替換為您的資料表名稱,並將 REGION 替換為您的區域。
Python
您可以使用 Amazon Elastic Compute Cloud (EC2) 執行個體、Lambda 或您自己的桌面來執行 Python 指令碼。在變更容量模式之前,請確認您已安裝 Python、pip 和 boto3。
在開始之前,請先設定您的 AWS 憑證。執行以下設定 AWS CLI 命令:
aws configure
佈建模式
若要使用 Python 指令碼將特定區域內所有 DynamoDB 表的容量模式變更為佈建模式,請完成下列步驟:
-
開啟 Python,輸入以下程式碼,建立新檔案:
import boto3 import time from botocore.exceptions import ClientError def switch_to_provisioned(read_capacity=5, write_capacity=5, region=None): """ Switch all DynamoDB tables from On-Demand to Provisioned capacity mode """ # Initialize DynamoDB client dynamodb = boto3.client('dynamodb', region_name=region) # Get all table names tables = [] paginator = dynamodb.get_paginator('list_tables') for page in paginator.paginate(): tables.extend(page['TableNames']) print(f"Found {len(tables)} tables") for table_name in tables: try: # Get table details response = dynamodb.describe_table(TableName=table_name) table = response['Table'] current_mode = table.get('BillingModeSummary', {}).get('BillingMode', '') if current_mode == 'PAY_PER_REQUEST': print(f"\nProcessing table: {table_name}") # Prepare GSI updates if any gsi_updates = [] if 'GlobalSecondaryIndexes' in table: print(f"Found GSIs for table {table_name}") for gsi in table['GlobalSecondaryIndexes']: gsi_updates.append({ 'Update': { 'IndexName': gsi['IndexName'], 'ProvisionedThroughput': { 'ReadCapacityUnits': read_capacity, 'WriteCapacityUnits': write_capacity } } }) # Prepare update parameters update_params = { 'TableName': table_name, 'BillingMode': 'PROVISIONED', 'ProvisionedThroughput': { 'ReadCapacityUnits': read_capacity, 'WriteCapacityUnits': write_capacity } } if gsi_updates: update_params['GlobalSecondaryIndexUpdates'] = gsi_updates # Update table print(f"Switching {table_name} to PROVISIONED mode...") dynamodb.update_table(**update_params) print(f"Update request submitted for {table_name}") else: print(f"\nSkipping {table_name} - already in PROVISIONED mode") except ClientError as e: if e.response['Error']['Code'] == 'LimitExceededException': print(f"\nError: Cannot update {table_name}. You can only switch between billing modes once per 24 hours.") else: print(f"\nError processing table {table_name}: {str(e)}") continue except Exception as e: print(f"\nUnexpected error processing table {table_name}: {str(e)}") continue # Small delay to avoid API throttling time.sleep(1) if __name__ == "__main__": # You can modify these values READ_CAPACITY = [RCU_VALUE] WRITE_CAPACITY = [WCU_VALUE] REGION = [REGION] # Change to your desired region switch_to_provisioned( read_capacity=READ_CAPACITY, write_capacity=WRITE_CAPACITY, region=REGION )**注意:**將 RCU_VALUE 和 WCU_VALUE 替換為您的 RCU 和 WCU 值,並將 REGION 替換為您的區域,例如 us-east-1。
-
使用 switch_to_provisioned.py 名稱儲存該檔案。
-
開啟終端並執行以下命令,以執行 Python 指令碼:
python switch_to_provisioned.py
隨需模式
若要使用 Python 指令碼將特定區域內所有 DynamoDB 表的容量模式變更為隨需模式,請完成下列步驟:
-
開啟 Python,輸入以下程式碼,建立新檔案:
import boto3 import time from botocore.exceptions import ClientError def switch_to_ondemand(region=None): """ Switch all DynamoDB tables from Provisioned to On-Demand capacity mode """ # Initialize DynamoDB client dynamodb = boto3.client('dynamodb', region_name=region) # Get all table names tables = [] paginator = dynamodb.get_paginator('list_tables') for page in paginator.paginate(): tables.extend(page['TableNames']) print(f"Found {len(tables)} tables") for table_name in tables: try: # Get table details response = dynamodb.describe_table(TableName=table_name) table = response['Table'] current_mode = table.get('BillingModeSummary', {}).get('BillingMode', '') if current_mode == 'PROVISIONED': print(f"\nProcessing table: {table_name}") # Check for GSIs if 'GlobalSecondaryIndexes' in table: print(f"Table {table_name} has GSIs - they will automatically switch to On-Demand") # Update table print(f"Switching {table_name} to PAY_PER_REQUEST mode...") dynamodb.update_table( TableName=table_name, BillingMode='PAY_PER_REQUEST' ) print(f"Update request submitted for {table_name}") else: print(f"\nSkipping {table_name} - already in PAY_PER_REQUEST mode") except ClientError as e: if e.response['Error']['Code'] == 'LimitExceededException': print(f"\nError: Cannot update {table_name}. You can only switch between billing modes once per 24 hours.") else: print(f"\nError processing table {table_name}: {str(e)}") continue except Exception as e: print(f"\nUnexpected error processing table {table_name}: {str(e)}") continue # Small delay to avoid API throttling time.sleep(1) def check_table_status(table_name, region=None): """ Check the current billing mode of a specific table """ dynamodb = boto3.client('dynamodb', region_name=region) try: response = dynamodb.describe_table(TableName=table_name) mode = response['Table'].get('BillingModeSummary', {}).get('BillingMode', 'Unknown') print(f"Table {table_name} is in {mode} mode") return mode except Exception as e: print(f"Error checking table {table_name}: {str(e)}") return None if __name__ == "__main__": REGION = [REGION] # Change to your desired region switch_to_ondemand(region=REGION)**注意:**將 REGION 替換為您的區域。
-
使用名稱 switch_to_ondemand.py 儲存該檔案。
-
開啟終端並執行以下命令,以執行 Python 指令碼:
python switch_to_ondemand.py
相關資訊
相關內容
- 已提問 3 年前
