Esta página está disponível apenas em inglês.
Redis Caching
Pathrule2 regras • 3 memórias • 1 skill
A practical baseline for caching with Redis. The hard part of caching is never the read path; it is expiry, invalidation, and what happens under concurrency and partial failure. This pattern uses the cache-aside read path, gives every key a TTL, prevents the cache stampede that turns an expiry into a database outage, and picks an invalidation strategy that matches how fresh the data must be. It also says plainly what not to cache.
Mapa de caminhos sugerido
O Pathrule coloca cada item no caminho correspondente, para que seu assistente só o veja onde ele pertence. Este é o escopo que você recebe ao importar; você pode ajustá-lo no seu espaço de trabalho.
Regras
2Give every cached key a TTL/src/cachealtaestritaSet an expiry on every key you cache; a cache without TTL is a second source of truth that drifts from the database forever.
| 1 | A key with no expiry never self-heals. If invalidation ever misses it, that value is wrong until something happens to overwrite it, which may be never. |
| 2 | |
| 3 | - Set a TTL on every cached value (`SET key val EX seconds`, or `EXPIRE`). The TTL is your safety net: even if explicit invalidation fails, the data is wrong for at most one TTL. |
| 4 | - Choose the TTL from how stale the data may acceptably be, not a global default. Reference data tolerates minutes or hours; data a user just changed tolerates seconds. |
| 5 | - Do not treat Redis as durable storage. It is a cache: assume any key can vanish at any time (eviction, restart) and the code must fall back to the source of truth cleanly. |
| 6 | - Add small random jitter to TTLs of related keys so they do not all expire on the same second and stampede together (see the stampede rule). |
Prevent cache stampedes on hot keys/src/cachealtaconsultivaWhen a hot key expires, stop every request from hitting the database at once; use a lock, early recompute, or staggered TTLs.
| 1 | When a popular key expires, every concurrent request misses at the same instant and slams the database together. That stampede (also called a thundering herd) is how a cache expiry becomes a database outage. |
| 2 | |
| 3 | - Serialize the recompute: on a miss for a hot key, let one request acquire a short lock (`SET key val NX EX`) and rebuild the value while the others briefly wait or serve the previous value. Only one query hits the database. |
| 4 | - Or recompute early: refresh a key before it expires (probabilistic early expiration / background refresh) so it is rarely cold at request time. |
| 5 | - Stagger expirations with TTL jitter so a batch of related keys does not expire on the same tick. |
| 6 | - Guard against cache penetration too: a flood of requests for keys that do not exist bypasses the cache entirely. Cache a short-lived negative result (or use a bloom filter) so missing keys do not hammer the database. |
Memórias
3Cache-aside is the default read path/src/cacheRead from cache, fall back to the database on a miss, then populate the cache; the application owns the cache, and a Redis outage degrades to direct DB reads.
| 1 | We use the cache-aside (lazy-loading) pattern as the default. The application, not Redis, owns the relationship between cache and database. |
| 2 | |
| 3 | - Read path: check Redis; on a hit return it; on a miss read the database, write the value to Redis with a TTL, and return it. Only data that is actually requested gets cached. |
| 4 | - Because the app controls the fallback, a Redis outage degrades to reading the database directly rather than failing the request. Wrap cache reads so a cache error is logged and falls through, never throws to the user. |
| 5 | - Cache-aside pairs with cache invalidation on write (see the invalidation memory): the write path updates the database and then invalidates or refreshes the affected keys. |
| 6 | - Use write-through (write cache and DB together) only when you need the cache always warm and can accept the extra write latency; cache-aside is the simpler, more resilient default. |
| 7 | |
| 8 | See /src/cache for the TTL and stampede rules and the invalidation and key-design memories. |
Choose an invalidation strategy by required freshness/src/cacheUse TTL-only for data that may lag, event-driven invalidation on writes for accuracy, and tag/group invalidation when one change affects many keys.
| 1 | Cache invalidation is the hard problem; the trick is to match the strategy to how fresh the data must be rather than reaching for the most complex option everywhere. |
| 2 | |
| 3 | - TTL-only: simplest and often enough. Let data refresh on its own schedule when a short lag is acceptable. No write-path coupling. |
| 4 | - Event-driven (write-path) invalidation: when a record changes, invalidate or update the specific keys derived from it. Use this when staleness is user-visible or incorrect. Invalidate the precise keys, not the whole cache. |
| 5 | - Tag / group invalidation: when one change should drop many related entries (a product update affecting many cached views), group keys under a tag and invalidate the group, rather than deleting entries one by one or flushing everything. |
| 6 | - Avoid the over-broad flush: dropping all of a record's cached data because one unrelated field changed wastes the cache. Scope invalidation to what actually changed. |
| 7 | - Prefer delete-then-recompute over update-in-place for derived values; recomputing from the source on the next read avoids subtle write-order races between cache and database. |
| 8 | |
| 9 | See /src/cache for the cache-aside read path and the TTL rule. |
Key design, serialization, and round-trips/src/cacheUse namespaced, versioned keys, an explicit serialization format, and pipelining/batching to avoid one-command-at-a-time latency.
| 1 | The mechanics of how you store and fetch keys decide whether the cache is fast and debuggable or a mystery. |
| 2 | |
| 3 | - Namespace keys with a stable convention (`entity:id:field`, e.g. `user:42:profile`) so keys are greppable, scopable for invalidation, and collision-free across features. Include a schema version segment so a shape change can invalidate a whole generation at once. |
| 4 | - Pick one serialization format (JSON for simplicity and debuggability; a compact binary format when size/latency matters) and apply it consistently. Store the minimal data the read path needs, not whole objects. |
| 5 | - Avoid sending one command per round-trip in a loop; that latency dominates. Use pipelining or `MGET`/multi-key commands to batch reads and writes into fewer round-trips. |
| 6 | - Do not use `KEYS` in production to find keys to invalidate; it blocks the server. Track the keys you need to invalidate (via tags/sets) or use `SCAN`. |
| 7 | - What not to cache: secrets, anything per-request and unique, data with hard real-time accuracy requirements, and values cheaper to recompute than to fetch from Redis. |
| 8 | |
| 9 | See /src/cache for the cache-aside and invalidation memories. |
Skills
1redis-cache-review/rootChecklist before adding or changing a Redis cache: TTL, stampede, invalidation, key design, and resilience.
| 1 | --- |
| 2 | name: redis-cache-review |
| 3 | description: Review checklist for adding or changing a Redis cache. Run before merging any code that reads from or writes to a cache. |
| 4 | --- |
| 5 | |
| 6 | # Redis cache review |
| 7 | |
| 8 | - [ ] Every cached key has a TTL chosen from acceptable staleness, with small jitter on related keys. |
| 9 | - [ ] Read path is cache-aside: miss falls back to the source of truth and repopulates with a TTL. |
| 10 | - [ ] A Redis error logs and falls through to the database; it never throws to the user. |
| 11 | - [ ] Hot keys are protected from stampede (lock/single-flight, early recompute, or staggered TTL). |
| 12 | - [ ] Requests for nonexistent keys cannot bypass the cache and hammer the DB (negative caching / bloom filter). |
| 13 | - [ ] Writes invalidate or refresh the precise affected keys; strategy (TTL-only / event-driven / tag) matches required freshness. |
| 14 | - [ ] Keys are namespaced and versioned (`entity:id:field`), with one consistent serialization format and minimal stored data. |
| 15 | - [ ] Multi-key access uses pipelining / MGET, not one command per round-trip; no `KEYS` in production. |
| 16 | - [ ] Nothing sensitive, per-request-unique, or hard-real-time is cached; Redis is treated as ephemeral, not durable. |
Por que este padrão
AI agents add a cache with no TTL, no stampede protection, and no invalidation plan, so reads get fast but data goes stale and an expiry wave can take the database down.
Feito para: Backend teams adding a Redis cache in front of a database or expensive computation.
Evita que seu assistente:
- Caching values forever with no TTL so data goes silently stale
- Letting a popular key expire and stampede every request onto the database
- Having no invalidation plan, so a write leaves the cache wrong
- Caching sensitive or fast-changing data that should never be cached
- Licença
- Apache-2.0
- Versão
- 1.0.1
- Atualizado em
- 2026-08-25