How to Use Amazon CloudWatch Contributor Insights to Identify Top-N DynamoDB Partition Keys Causing Throttling

Intermediate

Introduction: The Silent Killer of DynamoDB Performance

You’ve provisioned what should be more than enough Read and Write Capacity Units (RCUs/WCUs) for your DynamoDB table, yet you’re still seeing ProvisionedThroughputExceededException errors in your application logs. Your CloudWatch metrics show that your overall consumed capacity is well below your provisioned limit. So what’s going on?

The answer is almost always a hot partition — a small number of partition keys are receiving a disproportionate share of traffic, overwhelming the throughput allocated to their specific partition while the rest of the table sits idle. The frustrating part? Standard CloudWatch metrics for DynamoDB (ConsumedReadCapacityUnits, ConsumedWriteCapacityUnits) only show you aggregate table-level numbers. They don’t tell you which partition keys are the culprits.

This is exactly the problem Amazon CloudWatch Contributor Insights for DynamoDB solves. It continuously analyzes your DynamoDB traffic patterns and surfaces the Top-N most accessed partition keys and sort keys in near real-time — no custom instrumentation, no application-level logging changes, and no sampling.

Who should read this: Backend engineers, DevOps engineers, and SREs who manage DynamoDB tables in production and need to diagnose throttling, identify hot keys, or proactively monitor access patterns. You should have basic familiarity with DynamoDB concepts (partition keys, sort keys, capacity modes) and be comfortable with the AWS CLI.

Prerequisites

  • An AWS account with permissions to manage DynamoDB and CloudWatch
  • AWS CLI v2 installed and configured (aws --version should return 2.x)
  • At least one DynamoDB table (we’ll create a sample one if needed)
  • IAM permissions including dynamodb:EnableKinesisStreamingDestination, dynamodb:DescribeContributorInsights, dynamodb:UpdateContributorInsights, cloudwatch:GetInsightRuleReport, and cloudwatch:DescribeInsightRules
  • Python 3.8+ with boto3 installed (for the code examples)

Understanding How Contributor Insights for DynamoDB Works

Before diving into implementation, let’s understand the mechanics. CloudWatch Contributor Insights is a general-purpose CloudWatch feature that analyzes log group data using rules to find top contributors. For DynamoDB, AWS provides a built-in, managed integration that doesn’t require you to configure log groups or write custom rules manually.

When you enable Contributor Insights on a DynamoDB table or Global Secondary Index (GSI), AWS automatically creates two CloudWatch Insight Rules per table/index:

  • DynamoDBContributorInsights-PKC-[table-name] — Tracks the most accessed partition keys (by consumed capacity)
  • DynamoDBContributorInsights-PKT-[table-name] — Tracks the most throttled partition keys

If your table has a sort key, two additional rules are created:

  • DynamoDBContributorInsights-SKC-[table-name] — Most accessed partition key + sort key combinations
  • DynamoDBContributorInsights-SKT-[table-name] — Most throttled partition key + sort key combinations

These rules analyze traffic continuously and report the top contributors over configurable time windows. The data is available with a ~1 minute delay and retains 24 hours of per-minute data and 14 days of per-hour data.

Key Concepts

Concept Description
Contributor A unique partition key (or PK+SK combination) that appears in DynamoDB requests
Occurrence The number of times a contributor appeared (i.e., number of requests for that key)
Top-N The N contributors with the highest occurrence count in the selected time window (default N=10, max 500)
PKC Rule Partition Key — most Consumed capacity
PKT Rule Partition Key — most Throttled requests

Step 1: Enable Contributor Insights on Your DynamoDB Table

Let’s start by enabling Contributor Insights. You can do this via the AWS Console, CLI, SDK, or Infrastructure as Code. Here’s the CLI approach:

# Enable Contributor Insights on a table
aws dynamodb update-contributor-insights \
    --table-name Orders \
    --contributor-insights-action ENABLE

# Verify it's enabled
aws dynamodb describe-contributor-insights \
    --table-name Orders

The response should show:

{
    "TableName": "Orders",
    "ContributorInsightsRuleList": [
        "DynamoDBContributorInsights-PKC-Orders",
        "DynamoDBContributorInsights-PKT-Orders",
        "DynamoDBContributorInsights-SKC-Orders",
        "DynamoDBContributorInsights-SKT-Orders"
    ],
    "ContributorInsightsStatus": "ENABLED",
    "LastUpdateDateTime": "2024-01-15T10:30:00+00:00"
}

To enable it on a Global Secondary Index (GSI):

# Enable on a GSI
aws dynamodb update-contributor-insights \
    --table-name Orders \
    --index-name GSI-CustomerEmail \
    --contributor-insights-action ENABLE

For CloudFormation / AWS SAM, add this to your table resource:

# In your CloudFormation template
Resources:
  OrdersTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: Orders
      AttributeDefinitions:
        - AttributeName: orderId
          AttributeType: S
        - AttributeName: customerId
          AttributeType: S
      KeySchema:
        - AttributeName: orderId
          KeyType: HASH
        - AttributeName: customerId
          KeyType: RANGE
      BillingMode: PAY_PER_REQUEST
      ContributorInsightsSpecification:
        Enabled: true

Step 2: Query Contributor Insights to Find Hot Partition Keys

Once enabled, give it a few minutes to start collecting data. Then query the insight rules using the CloudWatch API. The key API call is cloudwatch:GetInsightRuleReport.

# Find the top 10 most THROTTLED partition keys in the last hour
aws cloudwatch get-insight-rule-report \
    --rule-name "DynamoDBContributorInsights-PKT-Orders" \
    --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
    --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
    --period 3600 \
    --max-contributor-count 10

For the top most accessed (by consumed capacity) partition keys:

# Find the top 10 most accessed partition keys in the last hour
aws cloudwatch get-insight-rule-report \
    --rule-name "DynamoDBContributorInsights-PKC-Orders" \
    --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
    --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
    --period 3600 \
    --max-contributor-count 10

The response includes a Contributors array. Each contributor has:

  • Keys: The actual partition key value (and sort key if applicable)
  • ApproximateAggregateValue: Total consumed/throttled capacity units for this key
  • Datapoints: Time-series breakdown within the queried period

Python Script to Identify Hot Keys

Here’s a practical Python script that queries Contributor Insights and outputs a formatted report of your hottest partition keys:

import boto3
from datetime import datetime, timedelta, timezone

def get_top_contributors(table_name, rule_type="PKT", top_n=10, hours=1):
    """
    Retrieve top-N contributors from DynamoDB Contributor Insights.

    Args:
        table_name: DynamoDB table name
        rule_type: PKC (most consumed), PKT (most throttled),
                   SKC (sort key consumed), SKT (sort key throttled)
        top_n: Number of top contributors to return (max 500)
        hours: Lookback window in hours
    """
    cw_client = boto3.client("cloudwatch")
    rule_name = f"DynamoDBContributorInsights-{rule_type}-{table_name}"

    end_time = datetime.now(timezone.utc)
    start_time = end_time - timedelta(hours=hours)

    try:
        response = cw_client.get_insight_rule_report(
            RuleName=rule_name,
            StartTime=start_time,
            EndTime=end_time,
            Period=3600,
            MaxContributorCount=top_n,
            Metrics=["UniqueContributors", "MaxContributorValue", "SampleCount"],
            OrderBy="Sum"
        )
    except cw_client.exceptions.ResourceNotFoundException:
        print(f"Rule '{rule_name}' not found. Is Contributor Insights enabled?")
        return

    contributors = response.get("Contributors", [])

    if not contributors:
        print(f"No {rule_type} contributors found for '{table_name}' in the last {hours}h.")
        print("This is good news if checking throttled keys (PKT/SKT)!")
        return

    label = "THROTTLED" if "T" in rule_type else "CONSUMED"
    key_type = "Partition Key + Sort Key" if "SK" in rule_type else "Partition Key"

    print(f"\n{'='*70}")
    print(f"Top {top_n} Most {label} {key_type}s — Table: {table_name}")
    print(f"Time window: {start_time.strftime('%H:%M')} - {end_time.strftime('%H:%M')} UTC")
    print(f"{'='*70}")
    print(f"{'Rank':<6}{'Key Value':<40}{'Total (CU)':<15}")
    print(f"{'-'*6}{'-'*40}{'-'*15}")

    for i, contributor in enumerate(contributors, 1):
        key_values = " | ".join(contributor["Keys"])
        approx_value = contributor["ApproximateAggregateValue"]
        print(f"{i:<6}{key_values:<40}{approx_value:<15.1f}")

    print(f"\nAggregate stats:")
    print(f"  Unique contributors: {response.get('ApproximateUniqueCount', 'N/A')}")
    print(f"  Total aggregate value: {response.get('AggregateValue', 'N/A')}")


if __name__ == "__main__":
    TABLE = "Orders"

    # Check for throttled partition keys (the most critical check)
    get_top_contributors(TABLE, rule_type="PKT", top_n=10, hours=6)

    # Check for most accessed partition keys (to find hot keys before they throttle)
    get_top_contributors(TABLE, rule_type="PKC", top_n=10, hours=6)

    # Check throttled PK+SK combinations
    get_top_contributors(TABLE, rule_type="SKT", top_n=10, hours=6)

Example output when throttling is detected:

======================================================================
Top 10 Most THROTTLED Partition Keys — Table: Orders
Time window: 04:30 - 10:30 UTC
======================================================================
Rank  Key Value                               Total (CU)
----------------------------------------------
1     customer-8832                           45230.0
2     customer-1194                           38102.0
3     customer-0051                           12450.0
4     SYSTEM_BATCH_JOB                         9870.0
5     customer-7721                            3200.0
======================================================================

In this example, customer-8832 is clearly your hottest key. The SYSTEM_BATCH_JOB key at rank 4 suggests a batch process is hammering a single partition — a common anti-pattern we'll discuss later.

Step 3: Set Up Automated Alarms for Hot Key Detection

Don't wait for users to report errors. You can create CloudWatch Alarms on Contributor Insights rules to get proactive notifications when a single key starts consuming disproportionate throughput.

Unfortunately, you cannot create alarms directly on Insight Rule reports via the CLI in one step. Instead, use CloudWatch Anomaly Detection on your throttling metrics combined with the Contributor Insights data for investigation. However, you can create a CloudWatch Alarm on the built-in Insight Rule metric using the MaxContributorValue metric:

import boto3

def create_hot_key_alarm(table_name, threshold_cu=1000):
"""
Create a CloudWatch alarm that fires when any single partition key
consumes more than threshold_cu capacity units in a 5-minute window.
"""
cw_client = boto3.client("cloudwatch")

rule_name = f"DynamoDBContributorInsights-PKC-{table_name}"

cw_client.put_metric_alarm(
AlarmName=f"DynamoDB-HotKey-{table_name}",
AlarmDescription=(
f"Alarm when a single partition key in {table_name} "
f"consumes more than {threshold_cu} CU in 5 minutes"
),
Namespace="AWS/DynamoDB",
MetricName="ConsumedWriteCapacityUnits

Leave a Comment

Your email address will not be published. Required fields are marked *