Sizing and Capacity Planning
This guide helps you estimate memory requirements, plan for growth, and understand when to scale your Swytch deployment.
Every key stored in Swytch has fixed overhead beyond the key and value bytes:
| Component | Bytes | Notes |
|---|---|---|
| Key storage | len(key) | Your key string |
| Value storage | len(value) | Your value bytes |
| Entry metadata | ~64 | Timestamps, flags, hash, etc. |
| Index entry | ~24 | In-memory hash table slot |
Rule of thumb: Each key-value pair uses len(key) + len(value) + 90 bytes of memory.
Total Memory = (num_keys × 90) + total_key_bytes + total_value_bytes
Example: 10 million keys with average 20-byte keys and 200-byte values:
Memory = (10,000,000 × 90) + (10,000,000 × 20) + (10,000,000 × 200)
= 900MB + 200MB + 2000MB
= 3.1GB
Add 20% headroom for runtime overhead: ~3.7GB recommended maxmemory
Different Redis data types have additional per-element overhead:
| Type | Per-element overhead | Notes |
|---|---|---|
| String | 0 | Stored as raw bytes |
| List | ~16 bytes | Doubly-linked list nodes |
| Hash | ~24 bytes per field | Field name + value + metadata |
| Set | ~16 bytes per member | Hash set entry |
| Sorted Set | ~32 bytes per member | Score + skip list nodes |
| Stream | ~48 bytes per entry | Entry ID + field overhead |
Example: A hash with 100 fields averaging 10-byte names and 50-byte values:
Hash overhead = 100 × (24 + 10 + 50) = 8,400 bytes per hash
Your working set is the subset of data actively accessed within a time window. Swytch keeps all data in memory — when the cache is full, the eviction algorithm removes infrequently accessed keys to make room.
Use these metrics to understand whether your working set fits in memory:
| Metric | Meaning |
|---|---|
swytch_redis_cache_hits_total | Successful cache lookups |
swytch_redis_cache_misses_total | Cache misses (key not found) |
swytch_redis_cache_hit_rate | Hit rate (0-1) |
swytch_redis_evictions_total | Keys evicted from cache |
Working set fits in memory when:
- Hit rate is high (>90%)
- Evictions are infrequent
- p99 latency is stable
Working set exceeds memory when:
- Hit rate is dropping
- Consistent eviction pressure
- Frequently accessed keys are being evicted and re-populated
Hit Rate = cache_hits / (cache_hits + cache_misses)
Or use the pre-computed gauge:
swytch_redis_cache_hit_rate
Target: Hit rate > 90% for latency-sensitive workloads.
| Signal | Action |
|---|---|
| Hit rate < 80% | Increase --maxmemory |
| Evictions > 1000/sec sustained | Increase --maxmemory |
| p99 latency increasing | Check eviction rate and hit rate |
| OOM kills | Increase container memory limit |
| Signal | Action |
|---|---|
| CPU utilization > 80% sustained | Add cores or optimize queries |
| Command queue backing up | Check INFO for blocked clients |
| Lua script timeouts | Optimize scripts or add CPU |
| Signal | Action |
|---|---|
| Single node cannot hold working set | Add nodes to distribute load |
High cluster_reads_remote_fetch_total | Data is spread across nodes; add memory or review key distribution |
| Network bandwidth saturated | Add nodes to reduce per-node traffic |
Use this worksheet to plan your deployment:
Current keys: ____________
Average key size: ____________ bytes
Average value size: ____________ bytes
Growth rate (monthly): ____________ %
Current data size = keys × (key_size + value_size + 90)
= ____________ GB
6-month projection = current × (1 + growth_rate)^6
= ____________ GB
Swytch is an in-memory cache. All active data must fit in --maxmemory. When the limit is reached, the eviction
algorithm removes infrequently accessed effects automatically.
maxmemory = data_size × 1.2 (20% headroom)
If your total dataset is larger than available memory, Swytch functions as a cache — frequently accessed keys stay in memory while cold keys are evicted. In this case, size for your working set:
maxmemory = working_set_size × 1.2
If unknown, start generous and monitor hit rate.
Reduce gradually until hit rate drops below your target.
container_memory = maxmemory + max(512MB, maxmemory × 0.2)
container_cpu = based on expected ops/sec (see Deployment guide)
The extra memory beyond --maxmemory accounts for connection buffers, Lua scripting overhead, the Go runtime, and
cluster replication state (if clustered).
Set up alerts for proactive scaling:
# Prometheus alerting rules
groups:
- name: swytch-capacity
rules:
- alert: SwytchMemoryPressure
expr: swytch_redis_memory_bytes / swytch_redis_memory_max_bytes > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "Swytch memory usage above 90%"
- alert: SwytchHighEvictionRate
expr: rate(swytch_redis_evictions_total[5m]) > 1000
for: 10m
labels:
severity: warning
annotations:
summary: "High eviction rate indicates memory pressure"
- alert: SwytchLowHitRate
expr: swytch_redis_cache_hit_rate < 0.8
for: 15m
labels:
severity: warning
annotations:
summary: "Cache hit rate below 80%"
| Scenario | Recommended maxmemory | Notes |
|---|---|---|
| Small app (<1M keys) | 256MB - 1GB | Start small, scale up |
| Medium app (1-10M keys) | 1GB - 8GB | Monitor hit rate |
| Large app (10-100M keys) | 8GB - 64GB | Profile access patterns |
| Very large (>100M keys) | 64GB+ | Consider clustering or app-level sharding |