Skip to main content

ElastiCache Global Datastore

The multi-region shopping mall platform uses ElastiCache for Valkey 7.2 to implement a high-performance caching layer. Data is automatically replicated between us-east-1 and us-west-2 through Global Datastore.

Architecture

Cluster Specifications

Itemus-east-1 (Primary)us-west-2 (Secondary)
Replication Group IDproduction-elasticache-us-east-1production-elasticache-us-west-2
EngineValkey 7.2Valkey 7.2
Node Typecache.r7g.xlargecache.r7g.xlarge
Shard Count33
Replicas per Shard22
Total Nodes9 (3 x 3)9 (3 x 3)
Read/WriteRead/WriteRead Only
EncryptionAt-rest + In-transitAt-rest + In-transit

Connection Endpoints

us-east-1

Endpoint TypeValue
Configurationclustercfg.production-elasticache-us-east-1.xxxxxx.use1.cache.amazonaws.com:6379

us-west-2

Endpoint TypeValue
Configurationclustercfg.production-elasticache-us-west-2.yyyyyy.usw2.cache.amazonaws.com:6379
Important

us-west-2 is read-only. Write operations are only possible on the primary cluster in us-east-1.

Terraform Configuration

resource "aws_elasticache_subnet_group" "this" {
name = "${var.environment}-elasticache-global-${var.region}"
description = "Subnet group for ElastiCache Global cluster in ${var.region}"
subnet_ids = var.data_subnet_ids
}

resource "aws_elasticache_parameter_group" "this" {
name = "${var.environment}-elasticache-global-${var.region}"
family = "valkey7"

parameter {
name = "maxmemory-policy"
value = "volatile-lru"
}
}

# Primary region creates the global replication group
resource "aws_elasticache_global_replication_group" "this" {
count = var.is_primary ? 1 : 0

global_replication_group_id_suffix = "${var.environment}-global"
primary_replication_group_id = aws_elasticache_replication_group.this.id

global_replication_group_description = "Global replication group for ${var.environment}"
}

resource "aws_elasticache_replication_group" "this" {
replication_group_id = "${var.environment}-elasticache-${var.region}"
description = "ElastiCache Global replication group in ${var.region}"

# For secondary regions, join the global replication group
global_replication_group_id = var.is_primary ? null : var.global_replication_group_id

# Primary-only settings
engine = var.is_primary ? "valkey" : null
engine_version = var.is_primary ? "7.2" : null
node_type = var.is_primary ? var.node_type : null # cache.r7g.xlarge

num_node_groups = var.is_primary ? var.num_node_groups : null # 3
replicas_per_node_group = var.is_primary ? var.replicas_per_node_group : null # 2

automatic_failover_enabled = var.is_primary ? true : null
multi_az_enabled = var.is_primary ? true : null

subnet_group_name = aws_elasticache_subnet_group.this.name
security_group_ids = [var.security_group_id]

parameter_group_name = var.is_primary ? aws_elasticache_parameter_group.this.name : null

at_rest_encryption_enabled = var.is_primary ? true : null
kms_key_id = var.kms_key_arn
transit_encryption_enabled = var.is_primary ? true : null

snapshot_retention_limit = var.is_primary ? 7 : null
snapshot_window = var.is_primary ? "03:00-04:00" : null
maintenance_window = var.is_primary ? "sun:04:00-sun:05:00" : null
}

Cache Key Patterns

Key Naming Convention

{service}:{entity}:{identifier}:{field?}

Cache Key List

Key PatternDescriptionTTLExample
session:{sessionId}User session24hsession:abc123
user:{userId}:profileUser profile cache1huser:USER-001:profile
user:{userId}:cartShopping cart7duser:USER-001:cart
product:{productId}Product details30mproduct:PROD-001
product:{productId}:inventoryInventory info1mproduct:PROD-001:inventory
category:{categoryId}:productsProducts by category5mcategory:electronics:products
search:{queryHash}Search result cache10msearch:a1b2c3d4
rate_limit:{ip}:{endpoint}Rate Limiting1mrate_limit:1.2.3.4:/api/orders
flash_sale:{saleId}:stockFlash sale stock-flash_sale:SALE-001:stock
popular:products:{region}Popular products15mpopular:products:us-east-1

Data Type Usage

Cache Pattern Examples

Session Management (String)

// Save session
func SetSession(ctx context.Context, sessionID string, data []byte) error {
return rdb.Set(ctx,
fmt.Sprintf("session:%s", sessionID),
data,
24*time.Hour,
).Err()
}

// Get session
func GetSession(ctx context.Context, sessionID string) ([]byte, error) {
return rdb.Get(ctx, fmt.Sprintf("session:%s", sessionID)).Bytes()
}

Product Cache (Hash)

// Cache product info
func CacheProduct(ctx context.Context, product *Product) error {
key := fmt.Sprintf("product:%s", product.ID)

return rdb.HSet(ctx, key, map[string]interface{}{
"name": product.Name,
"price": product.Price,
"stock": product.Stock,
"category": product.Category,
}).Err()
}

// Set TTL
func SetProductTTL(ctx context.Context, productID string) error {
return rdb.Expire(ctx,
fmt.Sprintf("product:%s", productID),
30*time.Minute,
).Err()
}

Shopping Cart (List)

// Add to cart
func AddToCart(ctx context.Context, userID, productID string, quantity int) error {
key := fmt.Sprintf("user:%s:cart", userID)
item := fmt.Sprintf("%s:%d", productID, quantity)

return rdb.RPush(ctx, key, item).Err()
}

// Get cart
func GetCart(ctx context.Context, userID string) ([]string, error) {
return rdb.LRange(ctx,
fmt.Sprintf("user:%s:cart", userID),
0, -1,
).Result()
}
// Update popular products
func IncrementProductView(ctx context.Context, region, productID string) error {
key := fmt.Sprintf("popular:products:%s", region)

return rdb.ZIncrBy(ctx, key, 1, productID).Err()
}

// Get top 10 popular products
func GetPopularProducts(ctx context.Context, region string) ([]string, error) {
key := fmt.Sprintf("popular:products:%s", region)

return rdb.ZRevRange(ctx, key, 0, 9).Result()
}

Cluster Mode vs Non-Cluster Mode

ItemCluster Mode (Current)Non-Cluster Mode
ShardingAutomatic (hash slots)Not available
ScalabilityHorizontal scaling possibleVertical scaling only
Key DistributionAutomaticN/A
Multi-key OperationsSame slot onlyUnlimited
Global DatastoreSupportedSupported
Cluster Mode Notes

Multi-key operations (MGET, MSET, etc.) can only be used on keys in the same hash slot. Use hash tags {tag} to place related keys in the same slot:

user:{USER-001}:profile
user:{USER-001}:cart
user:{USER-001}:session

Disaster Recovery

Node Failure

  • Automatic failover within shard (~30 seconds)
  • Multi-AZ deployment for availability zone failure handling

Regional Failover

# Promote secondary to primary
aws elasticache failover-global-replication-group \
--global-replication-group-id production-global \
--primary-region us-west-2 \
--primary-replication-group-id production-elasticache-us-west-2

Monitoring

Key Metrics

MetricDescriptionAlarm Threshold
CPUUtilizationCPU usage> 75%
DatabaseMemoryUsagePercentageMemory usage> 80%
CacheHitRateCache hit rate< 90%
ReplicationLagReplication lag> 1 second
CurrConnectionsCurrent connections> 5000
EvictionsCache evictions> 100/min

Next Steps