---
title: "Spread the reads of one hot cache key · Agent Wranglers"
url: https://agentwranglers.se/playbook/scaling/caching/hot-cache-keys
id: SCL-42
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 945
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Spread the reads of one hot cache key

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Caching](https://agentwranglers.se/playbook/scaling/caching.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: SCL-42
- Level: Recommended
- Chapter: [Caching](https://agentwranglers.se/playbook/scaling/caching.md)
- Rule: Find the cache keys that take more than 10% of all reads. Keep a copy of each in every app process for a few seconds, or copy it to several keys spread across the cache servers.
- Check: Under the load test at the planned peak, the busiest cache server's CPU is at most 2 times the average of the others. No single key takes more than 10% of the reads that reach the cache.
- How: A cache cluster spreads keys across servers, but one key always lives on one server. A price list or a feature flag read on every request sends all that traffic to one cache server. It saturates while the others idle. Count reads per key with the cache's own tools, such as `redis-cli --hotkeys` with an LFU eviction policy, or by sampling in the app. Keep a small local copy in each app process for 1 to 5 seconds. Each process then asks the cache once per lifetime. When even that is too much, write the value under several keys, such as `price-list:0` to `price-list:7`, and let each reader pick one at random. Hot rows in the database follow [Spread writes that all land on one row](https://agentwranglers.se/playbook/scaling/growing-the-database/hot-rows.md). A rebuild of a hot key follows [Let one caller rebuild an expired entry](https://agentwranglers.se/playbook/scaling/caching/stampede-protection.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
const LOCAL_TTL_MS = 2000;
const localCopies = new Map();

export async function readHot(cache, key) {
  const local = localCopies.get(key);
  if (local && local.expiresAt > Date.now()) return local.value;
  const value = await cache.get(key);
  localCopies.set(key, { value, expiresAt: Date.now() + LOCAL_TTL_MS });
  return value;
}
```

### Python example

```python
import time

LOCAL_TTL_SECONDS = 2.0
local_copies: dict[str, tuple[float, object]] = {}

def read_hot(cache, key: str):
    expires_at, value = local_copies.get(key, (0.0, None))
    if expires_at > time.monotonic():
        return value
    value = cache.get(key)
    local_copies[key] = (time.monotonic() + LOCAL_TTL_SECONDS, value)
    return value
```

## Sources

- [Redis key eviction and LFU](https://redis.io/docs/latest/develop/reference/eviction/)

## Related rules

- SCL-40 [Spread writes that all land on one row](https://agentwranglers.se/playbook/scaling/growing-the-database/hot-rows.md) in Scaling
- SCL-13 [Let one caller rebuild an expired entry](https://agentwranglers.se/playbook/scaling/caching/stampede-protection.md) in Scaling

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/scaling/caching/hot-cache-keys">Agent Wranglers scaling playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Decide how stale a cache may be](https://agentwranglers.se/playbook/scaling/caching/cache-freshness.md)
- Next: [Cache public pages at the edge for a few seconds](https://agentwranglers.se/playbook/scaling/caching/edge-micro-cache.md)
- [Caching](https://agentwranglers.se/playbook/scaling/caching.md)
