RCU & WCU

In traditional databases, you pay for servers (CPU, RAM). In DynamoDB, you pay for throughput.

This throughput is measured in Capacity Units. Understanding these units is critical for performance tuning and cost estimation.

1. The Currency of Throughput

DynamoDB abstracts hardware away. Instead of “CPU cycles,” you purchase units of work.

1. Read Capacity Unit (RCU)

One RCU represents one strongly consistent read per second for an item up to 4 KB.

  • Eventually Consistent Reads: Consumes 0.5 RCU (cheaper).
  • Transactional Reads: Consumes 2.0 RCU (expensive).
  • Item Size: Rounded up to the nearest 4 KB.
  • Read 100 bytes → 1 RCU.
  • Read 4.1 KB → 2 RCUs.

2. Write Capacity Unit (WCU)

One WCU represents one standard write per second for an item up to 1 KB.

  • Transactional Writes: Consumes 2.0 WCU.
  • Item Size: Rounded up to the nearest 1 KB.
  • Write 100 bytes → 1 WCU.
  • Write 1.1 KB → 2 WCUs.
The 4KB / 1KB Rule

DynamoDB is optimized for small items. Storing large blobs (e.g., base64 images) in DynamoDB is an anti-pattern because it burns through WCUs quickly. Store large objects in S3 and save the URL in DynamoDB.

2. Capacity Modes

Provisioned Mode

You say: “I need 1000 RCUs and 500 WCUs.”

  • Pros: Cheapest per unit (if fully utilized).
  • Cons: You pay even if you don’t use it.
  • Use Case: Predictable, steady traffic (e.g., e-commerce cart service).

On-Demand Mode

You say: “Handle whatever traffic comes.”

  • Pros: Zero capacity planning. Handles spiky traffic instantly.
  • Cons: ~5-7x more expensive per request than fully utilized provisioned capacity.
  • Use Case: New startups, unpredictable workloads, dev/test tables.

3. Interactive: Throughput Calculator

Visualize the cost of your data model.

Throughput Estimator

RCUs Needed
0
Blocks of 4KB
WCUs Needed
0
Blocks of 1KB
Provisioned Cost (Monthly) $0.00
*Est. us-east-1 pricing (0.00065/RCU, 0.00335/WCU)

4. Handling Throttling

If you consume more capacity than you provisioned, DynamoDB throws ProvisionedThroughputExceededException.

The client must handle this with Exponential Backoff and Jitter.

Java Implementation (Custom Retry)

The AWS SDK v2 has built-in retry logic, but you can customize it for high-throughput scenarios.

import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.time.Duration;

public class DynamoDbClientFactory {
    public static DynamoDbClient createClient() {
        // Strategy: Wait 100ms, then 200ms, 400ms... up to 2s
        // FullJitter adds randomness to prevent "thundering herd"
        FullJitterBackoffStrategy backoff = FullJitterBackoffStrategy.builder()
                .baseDelay(Duration.ofMillis(100))
                .maxBackoffTime(Duration.ofSeconds(2))
                .build();

        RetryPolicy retryPolicy = RetryPolicy.builder()
                .numRetries(5)
                .backoffStrategy(backoff)
                .build();

        return DynamoDbClient.builder()
                .overrideConfiguration(ClientOverrideConfiguration.builder()
                        .retryPolicy(retryPolicy)
                        .build())
                .build();
    }
}

Go Implementation (Custom Retry)

package main

import (
	"context"
	"log"
	"time"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/aws/retry"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

func CreateClient() *dynamodb.Client {
	// Custom retryer: Max 5 attempts, Max backoff 2s
	customRetryer := retry.NewStandard(func(o *retry.StandardOptions) {
		o.MaxAttempts = 5
		o.MaxBackoff = 2 * time.Second
	})

	cfg, err := config.LoadDefaultConfig(context.TODO(),
		config.WithRetryer(func() aws.Retryer {
			return customRetryer
		}),
	)
	if err != nil {
		log.Fatalf("unable to load SDK config, %v", err)
	}

	return dynamodb.NewFromConfig(cfg)
}