Skip to content

Azure Cache for Redis

First PublishedByAtif Alam

Azure Cache for Redis is a fully managed, in-memory data store based on Redis. It’s used for caching, session management, leaderboards, rate limiting, and real-time messaging — the same use cases as AWS ElastiCache Redis.

Without cache:
Client ──► App Server ──► Database (50-100 ms)
With cache:
Client ──► App Server ──► Redis (1-2 ms) ──hit──► return cached data
└──miss──► Database ──► store in Redis ──► return

Caching reduces database load, lowers latency, and improves scalability.

TierDescriptionSizeSLAKey Features
BasicSingle node, no SLA250 MB – 53 GBNoneDevelopment/testing only
StandardPrimary + replica250 MB – 53 GB99.9%Replication, failover
PremiumClustered, VNet, persistence6 GB – 1.2 TB99.9%Clustering, geo-replication, data persistence
EnterpriseRedis Enterprise (RediSearch, RedisJSON, etc.)Up to 10+ TB99.999%Redis modules, active-active geo-replication
Enterprise FlashRedis Enterprise on NVMe + RAMVery large datasets99.999%Cost-effective for large data
ScenarioTier
Local development, testingBasic
Production with HAStandard
Large datasets, clustering, VNetPremium
Advanced data structures (JSON, search, time series)Enterprise
Terminal window
# Create a Standard tier cache (6 GB, primary + replica)
az redis create \
--resource-group myapp-rg \
--name myapp-cache \
--location eastus \
--sku Standard \
--vm-size C1 \
--enable-non-ssl-port false \
--minimum-tls-version 1.2
# Get connection details
az redis show \
--resource-group myapp-rg \
--name myapp-cache \
--query "{host: hostName, port: sslPort}" -o table
# Get access key
az redis list-keys \
--resource-group myapp-rg \
--name myapp-cache \
--query "primaryKey" -o tsv
import redis
r = redis.Redis(
host="myapp-cache.redis.cache.windows.net",
port=6380,
password="<access-key>",
ssl=True,
decode_responses=True
)
# Basic operations
r.set("user:123:name", "Alice", ex=3600) # set with 1 hour TTL
name = r.get("user:123:name") # "Alice"

With Managed Identity (Entra ID Authentication)

Section titled “With Managed Identity (Entra ID Authentication)”
from azure.identity import DefaultAzureCredential
import redis
credential = DefaultAzureCredential()
token = credential.get_token("https://redis.azure.com/.default").token
r = redis.Redis(
host="myapp-cache.redis.cache.windows.net",
port=6380,
username="<object-id-of-managed-identity>",
password=token,
ssl=True,
decode_responses=True
)
const Redis = require("ioredis");
const redis = new Redis({
host: "myapp-cache.redis.cache.windows.net",
port: 6380,
password: "<access-key>",
tls: { servername: "myapp-cache.redis.cache.windows.net" },
});
await redis.set("session:abc", JSON.stringify({ userId: 123 }), "EX", 1800);
const session = JSON.parse(await redis.get("session:abc"));

The most common pattern — application checks cache first, falls back to database:

def get_product(product_id):
# 1. Check cache
cached = r.get(f"product:{product_id}")
if cached:
return json.loads(cached)
# 2. Cache miss — fetch from database
product = db.query("SELECT * FROM products WHERE id = %s", product_id)
# 3. Store in cache with TTL
r.set(f"product:{product_id}", json.dumps(product), ex=600) # 10 min TTL
return product

Pros: Only caches data that is actually requested. Cons: First request is always slow (cache miss); stale data until TTL expires.

Write to cache and database at the same time:

def update_product(product_id, data):
# Write to database
db.execute("UPDATE products SET ... WHERE id = %s", product_id)
# Write to cache
r.set(f"product:{product_id}", json.dumps(data), ex=600)

Pros: Cache is always up to date. Cons: Write latency increases; unused data may fill cache.

Write to cache immediately, flush to database asynchronously:

def update_product(product_id, data):
# Write to cache
r.set(f"product:{product_id}", json.dumps(data))
# Queue a database write
r.lpush("db:write-queue", json.dumps({"table": "products", "id": product_id, "data": data}))

Pros: Fastest writes. Cons: Risk of data loss if cache crashes before flush; complexity.

StrategyWhen to Use
TTL (Time-to-Live)Simple, good enough for most cases
Explicit deleteDelete cache key when data changes
Pub/SubNotify other services to invalidate their local caches
Event-drivenUse Event Grid or Service Bus to trigger cache invalidation
# Explicit invalidation on update
def update_product(product_id, data):
db.execute("UPDATE products SET ...")
r.delete(f"product:{product_id}") # next read will re-cache
import uuid, json
def create_session(user_id):
session_id = str(uuid.uuid4())
r.set(f"session:{session_id}", json.dumps({
"user_id": user_id,
"created": "2026-02-17T10:00:00Z"
}), ex=1800) # 30-minute session
return session_id
def get_session(session_id):
data = r.get(f"session:{session_id}")
if data:
r.expire(f"session:{session_id}", 1800) # sliding expiration
return json.loads(data)
return None
# Add score
r.zadd("leaderboard:daily", {"player-alice": 1500, "player-bob": 1200})
# Get top 10
top_10 = r.zrevrange("leaderboard:daily", 0, 9, withscores=True)
# [("player-alice", 1500), ("player-bob", 1200), ...]
# Get player rank
rank = r.zrevrank("leaderboard:daily", "player-alice") # 0 (first place)
def is_rate_limited(user_id, limit=100, window=60):
key = f"ratelimit:{user_id}"
current = r.incr(key)
if current == 1:
r.expire(key, window)
return current > limit
# Publisher
r.publish("notifications", json.dumps({
"user_id": 123,
"message": "Your order has shipped"
}))
# Subscriber (in a separate process)
pubsub = r.pubsub()
pubsub.subscribe("notifications")
for message in pubsub.listen():
if message["type"] == "message":
handle_notification(json.loads(message["data"]))
import time
def acquire_lock(lock_name, timeout=10):
"""Acquire a distributed lock using Redis SET NX."""
lock_key = f"lock:{lock_name}"
acquired = r.set(lock_key, "locked", nx=True, ex=timeout)
return acquired
def release_lock(lock_name):
r.delete(f"lock:{lock_name}")
# Usage
if acquire_lock("process-order-123"):
try:
process_order(123)
finally:
release_lock("process-order-123")

Premium tier supports Redis Cluster for horizontal scaling:

Terminal window
# Create a Premium cache with 3 shards
az redis create \
--resource-group myapp-rg \
--name myapp-cache-premium \
--location eastus \
--sku Premium \
--vm-size P1 \
--shard-count 3

Data is automatically distributed across shards by hash slot. More shards = more throughput and memory.

Link two Premium caches for cross-region replication:

Terminal window
# Link primary (East US) to secondary (West Europe) for geo-replication
az redis server-link create \
--name myapp-cache-primary \
--resource-group myapp-rg \
--server-to-link /subscriptions/.../myapp-cache-secondary \
--replication-role Secondary
TypeDescriptionRPO
RDB snapshotsPoint-in-time snapshots to Azure StorageMinutes (snapshot interval)
AOF (Append Only File)Log every write operation~1 second
Terminal window
# Enable RDB persistence (snapshot every 15 minutes)
az redis update \
--resource-group myapp-rg \
--name myapp-cache-premium \
--set "redisConfiguration.rdb-backup-enabled=true" \
--set "redisConfiguration.rdb-backup-frequency=15" \
--set "redisConfiguration.rdb-storage-connection-string=<connection-string>"

Inject the cache into your VNet for private access:

Terminal window
az redis create \
--resource-group myapp-rg \
--name myapp-cache-private \
--location eastus \
--sku Premium \
--vm-size P1 \
--subnet-id /subscriptions/.../subnets/redis-subnet

With VNet integration, the cache is only accessible from within the VNet — no public endpoint.

MetricWhat to Watch
Cache hit ratioShould be >90%; low ratio means inefficient caching
Used memoryApproaching max → eviction starts
Connected clientsUnexpected spikes may indicate connection leaks
Server load>80% sustained → scale up or out
Evicted keysKeys removed due to memory pressure
LatencyP99 should be <5 ms for same-region access
Terminal window
# View cache metrics
az monitor metrics list \
--resource /subscriptions/.../Microsoft.Cache/redis/myapp-cache \
--metric "cacheHits,cacheMisses,usedmemory,serverLoad" \
--interval PT5M
FeatureAzure Cache for RedisAWS ElastiCache Redis
ManagedFully managedFully managed
ClusteringPremium tierYes (cluster mode)
Geo-replicationPremium (active-passive), Enterprise (active-active)Global Datastore (active-passive)
ModulesEnterprise tier (RediSearch, RedisJSON, RedisTimeSeries)Not supported
Entra ID authYesIAM auth
VNet integrationPremium tier (VNet injection)VPC subnets
PersistenceRDB + AOF (Premium)RDB + AOF
  • Azure Cache for Redis is a fully managed in-memory data store for sub-millisecond access.
  • Cache-aside is the most common pattern — check cache first, fall back to database on miss.
  • Common use cases: session storage, leaderboards (sorted sets), rate limiting (INCR + EXPIRE), pub/sub, distributed locks.
  • Standard tier provides HA with replication; Premium adds clustering, VNet, persistence, and geo-replication.
  • Enterprise tier unlocks Redis modules (RediSearch, RedisJSON) and active-active geo-replication.
  • Monitor cache hit ratio (>90%) and server load (<80%) to ensure healthy performance.