A session store backed by ElastiCache for Redis started returning intermittent connection refused errors after what looked like a routine node failure. The replica promoted in under 30 seconds, right on schedule — but the application kept failing for another four minutes because the Redis client library had cached the old primary’s endpoint and wasn’t configured to refresh cluster topology on connection error. Redis did its job perfectly. The client just never asked it what changed.
Redis failover problems split cleanly into two categories: the cluster’s own failover behavior, and the client’s ability to notice and adapt to it. Here’s how to check both.
The Problem
Failures cluster around promotion timing and client-side topology awareness:
| Symptom | What It Means |
|---|---|
| Failover takes much longer than expected | Replica lag delaying promotion, or Multi-AZ not enabled |
MOVED or ASK errors in cluster mode |
Client isn’t cluster-aware and doesn’t follow slot redirection |
| Connections fail after failover completes | Client-side connection pool not refreshing topology or DNS |
CLUSTERDOWN errors |
A slot range has no available node — often during a botched resharding or node replacement |
| High latency spikes with no CPU pressure | Large key eviction, SWAPDB/FLUSHALL blocking, or a single slow command blocking the single-threaded event loop |
Redis’s own failover is fast and well-tested; the failure mode almost always lives in how the client discovers and reacts to the change.
Why Does This Happen?
- Multi-AZ with automatic failover not enabled: Without it, a primary node failure requires manual intervention or waits for the node to be replaced without automatic replica promotion — a much longer recovery window than most teams expect.
- Client library not cluster-mode aware: In cluster mode enabled deployments, keys are distributed across hash slots. A client that doesn’t implement the Redis Cluster protocol will fail outright or mishandle
MOVED/ASKredirection responses, especially after a resharding operation moves slots between nodes. - Connection pooling that doesn’t detect topology changes: Long-lived connections or a pool that only refreshes on explicit reconnect (not on error) will keep routing traffic to a node that’s no longer the primary for a given slot range.
- Replica lag delaying failover promotion: ElastiCache waits for a replica to be reasonably caught up before promoting it (to limit data loss), so a replica that’s lagged due to a large
SCAN, big key deletion, or replication buffer overflow takes longer to become failover-ready. - A single expensive command blocking the event loop: Redis is single-threaded for command execution. A
KEYS *command, a largeSORT, or an unboundedLRANGEagainst a huge list can block every other client for the duration — indistinguishable from a hang if you’re not looking at slow log data. - Reserved memory and eviction policy mismatch: If
maxmemory-policyis set tonoevictionand memory fills up, writes start failing withOOM command not allowedinstead of evicting older keys — often mistaken for a connectivity problem because the error surfaces as a failed command, not a clear “out of memory” message in application logs.
The Fix
Step 1: Confirm Multi-AZ and Automatic Failover Are Enabled
aws elasticache describe-replication-groups \
--replication-group-id orders-session-cache \
--query "ReplicationGroups[0].{MultiAZ:MultiAZ,AutomaticFailover:AutomaticFailover}"
If AutomaticFailover shows disabled, enable it:
aws elasticache modify-replication-group \
--replication-group-id orders-session-cache \
--automatic-failover-enabled \
--apply-immediately
Step 2: Check Replica Lag Before Trusting Failover Speed
aws cloudwatch get-metric-statistics \
--namespace AWS/ElastiCache \
--metric-name ReplicationLag \
--dimensions Name=CacheClusterId,Value=orders-session-cache-002 \
--start-time $(date -u -d '30 minutes ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 60 \
--statistics Maximum
Step 3: Verify the Client Library Supports Cluster Mode
For cluster mode enabled replication groups, confirm the client is using a cluster-aware library (redis-py-cluster/redis-py with cluster support, Lettuce, ioredis with cluster: true) rather than a plain single-node client pointed at the configuration endpoint. Check for MOVED errors in application logs — their presence confirms the client is at least receiving redirection responses but not following them automatically.
Step 4: Confirm the Application Uses the Cluster Configuration Endpoint, Not a Node Endpoint
aws elasticache describe-replication-groups \
--replication-group-id orders-session-cache \
--query "ReplicationGroups[0].ConfigurationEndpoint"
Applications should connect to this single configuration endpoint (which handles topology discovery) rather than hardcoding an individual node’s endpoint, which becomes stale the moment that node’s role changes.
Step 5: Check for Blocking Commands in the Slow Log
aws elasticache describe-cache-clusters \
--cache-cluster-id orders-session-cache-001 \
--show-cache-node-info
Connect directly and check the slow log for expensive commands:
redis-cli -h orders-session-cache.abc123.clustercfg.use1.cache.amazonaws.com -p 6379 SLOWLOG GET 10
Replace any KEYS * usage with SCAN with a small COUNT, and audit large collection commands (LRANGE, SMEMBERS, HGETALL) against keys that may have grown unexpectedly large.
Step 6: Check Memory Pressure and Eviction Policy
aws cloudwatch get-metric-statistics \
--namespace AWS/ElastiCache \
--metric-name DatabaseMemoryUsagePercentage \
--dimensions Name=CacheClusterId,Value=orders-session-cache-001 \
--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 300 \
--statistics Maximum
If memory usage is consistently high and maxmemory-policy is noeviction, switch to an eviction policy appropriate for a cache workload (commonly allkeys-lru):
aws elasticache modify-cache-parameter-group \
--cache-parameter-group-name orders-cache-params \
--parameter-name-values "ParameterName=maxmemory-policy,ParameterValue=allkeys-lru"
Step 7: Test Failover Deliberately
aws elasticache test-failover \
--replication-group-id orders-session-cache \
--node-group-id 0001
Measure actual application-observed downtime during this test, not just the console’s reported failover completion time — that gap is exactly where client-side topology staleness shows up.
Is This Safe?
The describe and CloudWatch calls are read-only. Enabling automatic failover and changing the eviction policy via modify-cache-parameter-group are low-risk and take effect on the next maintenance window unless applied immediately. test-failover performs a real failover with a brief real interruption — run it against a non-production replication group first, or during a maintenance window if run against production, since it’s meant to validate real behavior, not simulate it.
Key Takeaway
ElastiCache Redis failover itself is fast and reliable when Multi-AZ is enabled — the recovery time your application actually experiences is almost always determined by whether the client is cluster-aware, connects to the configuration endpoint instead of a node endpoint, and refreshes its topology on connection error. Test failover deliberately and measure the client’s actual recovery time, not the console’s reported promotion time — they are frequently very different numbers.
Have questions or ran into a different ElastiCache issue? Connect with me on LinkedIn or X.