Implement data operations
Redis data operations on Azure Managed Redis with redis-py: strings, hashes, lists, TTL commands, eviction policies and cache invalidation patterns.
What this covers
This page is the core of the data-operations skill. It shows how to store and read data in AMR with redis-py, which data type fits which job, how to set and check expiration, which eviction policy applies when memory fills up, and the four invalidation patterns that keep cached AI results fresh: time-based, explicit delete on write, cache-aside with TTL, and pattern-based deletion with SCAN.
Exam weight: Develop AI solutions by using Azure data management services (30–35%)
Skills measured
- "Implement Azure Managed Redis data operations, including caching, expiration, and invalidation"
Key concepts
Data types
| Type | Commands | Typical AI-backend use |
|---|---|---|
| String | SET, GET, MSET, MGET, SETEX | Serialized responses, cached embeddings, flags |
| Hash | HSET, HGET, HGETALL | Object-like records (user profile, model metadata). Uses less memory than one key per field |
| List | LPUSH/RPUSH, LPOP/RPOP, LRANGE | Simple FIFO/LIFO queues, recent-items feeds |
| Counter | INCR, DECR, INCRBY, DECRBY | Atomic counters and rate limits, with no race conditions |
decode_responses=True returns str instead of bytes. Keep it False for binary payloads such as pickled objects or vector bytes.
Expiration commands
Expiration applies to the key, so it works for every data type:
SETEX key seconds value/PSETEX(milliseconds): set a string and its TTL in one atomic step.EXPIRE,PEXPIRE,EXPIREAT(Unix time): add a TTL to an existing key. For hashes and lists, write the data first, then callEXPIRE.TTL/PTTL: remaining time. -1 means the key has no expiry and -2 means the key doesn't exist.PERSIST: remove the TTL.- A plain
SETwithoutEX/KEEPTTLclears any existing TTL on that key.
Suggested TTLs from the module:
| Data | TTL |
|---|---|
| Changes often | 1–5 minutes |
| Moderate change | 15–60 minutes |
| Fairly stable | 1–24 hours |
| Static reference data | 24 hours or more |
Eviction policies
When used memory hits the limit, the eviction policy decides what happens. The values are NoEviction, AllKeysLRU, AllKeysLFU, AllKeysRandom, VolatileLRU, VolatileLFU, VolatileRandom and VolatileTTL. VolatileLRU is the default: it evicts only keys that have a TTL, least recently used first. AllKeys* policies can evict any key, which suits a pure cache. NoEviction returns errors on writes when memory is full, and RediSearch requires it.
Invalidation patterns
- Time-based: every cached entry gets a TTL, and stale data ages out.
- Explicit delete on update: after writing to the database,
DELevery derived key (profile, summary, dashboard). - Cache-aside with TTL: read from the cache, and on a miss load from the database and
SETEX. - Pattern-based:
SCANwithMATCH user:1001:*in a loop, deleting each batch. Never useKEYS, because it blocks the server.
To tell several app instances to clear their in-process caches, publish an event on a pub/sub channel (see broadcast vs coordinated distribution).
How it works
Reads go to Redis first. Misses load from the system of record and populate the cache with a TTL. Writes go to the database and then invalidate the cached copies, so the next read reloads fresh data.
Hands-on
Azure portal
- When you create the instance, choose the Eviction policy on the Advanced tab. Keep the default (VolatileLRU) for a cache, or choose NoEviction if you enable RediSearch. You can change it later with
az redisenterprise database update. - Open Monitoring > Metrics and add Cache Hits, Cache Misses, Evicted Keys and Expired Keys to see whether TTLs and memory are sized well.
Azure CLI
az group create --name rg-ai200 --location eastus
# Pure cache: let Redis evict any key by LFU when memory is full
az redisenterprise database update --cluster-name <cache-name> \
--resource-group rg-ai200 --eviction-policy AllKeysLFU
az redisenterprise database show --cluster-name <cache-name> \
--resource-group rg-ai200 --query evictionPolicyPython
import time
import redis
from redis_entraid.cred_provider import create_from_default_azure_credential
provider = create_from_default_azure_credential(("https://redis.azure.com/.default",))
r = redis.Redis(host="<cache-name>.<region>.redis.azure.net", port=10000, ssl=True,
decode_responses=True, credential_provider=provider)
# Strings and hashes
r.set("user:1001:name", "Alice Smith")
r.hset("user:1001", mapping={"name": "Alice Smith", "email": "alice@example.com", "age": "28"})
print(r.hget("user:1001", "name"), r.hgetall("user:1001"))
# Multi-key and pipelines
r.mset({"user:1001:email": "alice@example.com", "user:1001:age": "28"})
pipe = r.pipeline()
pipe.hgetall("user:1001"); pipe.hgetall("user:1002")
profiles = pipe.execute()
print(r.exists("user:1001:name", "user:9999:name")) # count of existing keys -> 1
# Expiration
r.setex("session:abc123", 60, "user_data")
r.psetex("temp:data", 5000, "temporary_value")
r.expire("user:1001", 3600)
r.expireat("user:1001:name", int(time.time()) + 7200)
print(r.ttl("user:1001")) # seconds; -1 no TTL, -2 missing
r.persist("user:1001")
# Cache-aside with TTL
def get_user_data(user_id, ttl=3600):
key = f"user:{user_id}:data"
if (cached := r.get(key)) is not None:
return cached
value = f"User data for {user_id}" # replace with a DB query
r.setex(key, ttl, value)
return value
# Explicit invalidation after a write
def update_user_profile(user_id, new_data):
# save_to_database(user_id, new_data)
r.delete(f"user:{user_id}:profile", f"user:{user_id}:summary", f"dashboard:user:{user_id}")
# Pattern invalidation with SCAN (non-blocking)
def invalidate_user_cache(user_id):
deleted, cursor = 0, 0
while True:
cursor, keys = r.scan(cursor, match=f"user:{user_id}:*", count=100)
if keys:
deleted += r.delete(*keys)
if cursor == 0:
break
return deletedExam traps
| Need | Command or setting |
|---|---|
| Set a value and TTL atomically | SETEX (or SET key value EX n) |
| TTL on a hash or list | Write first, then EXPIRE |
| Check whether a key will expire | TTL (-1 none, -2 missing) |
| Remove the expiry | PERSIST |
| Delete keys by pattern | SCAN + DEL/UNLINK, never KEYS |
| Evict only keys that have a TTL | VolatileLRU (default) |
| Instance used for vector search | NoEviction (required by RediSearch) |
Quick review
- Use hashes for object-like records, because they use less memory than one key per field.
SETEX/PSETEXset a value and its TTL atomically.EXPIREadds a TTL to any type.TTLreturns -1 (no expiry) and -2 (missing key).PERSISTremoves the TTL.- The invalidation patterns are TTL, delete on write, cache-aside with TTL, and SCAN-based pattern delete.
- The default eviction policy is VolatileLRU. RediSearch requires NoEviction.
- Pipelines cut round trips when you work with many keys.
Practice
Practice: Azure Managed Redis data operations