TGViewer
About Python [ru] About Python [ru] @python_tesst · 6.45K subscribers
Post #2753 403
⁣Cache stampede в Python-сервисах: singleflight, jitter и stale-while-revalidate без героического тушения latency spike

Cache stampede возникает, когда популярный ключ истёк, и сотни запросов одновременно пересчитывают одно значение: SQL-агрегацию, внешний API или ML inference. Частая ошибка - считать, что обычный TTL сам по себе защищает production.

Singleflight: один refresh на ключ
Для одного cache_key в момент времени должен работать один пересчёт, остальные ждут или получают stale.

Внутри процесса подойдёт asyncio.Lock на ключ, но это не защита для нескольких uvicorn/gunicorn workers или pod’ов. Там нужен Redis SET NX PX, lease-lock, PostgreSQL advisory lock или singleflight поверх общего хранилища.

lock = locks.setdefault(key, asyncio.Lock())

async with lock:
item = await cache.get(key)
if item and item["expires_at"] > time.time():
return item["value"]

value = await fetch()
await store(cache, key, value)


Jitter: не синхронизируйте истечение
Если после деплоя прогреть 50k ключей с ttl=60, через минуту они начнут истекать пачкой.

Практичнее так:

ttl = 60
ttl = ttl + random.uniform(0, ttl * 0.15)


Особенно важно для агрегатов, feature flags, кэша внешних API и scheduled prewarm jobs.

Stale-while-revalidate: старое лучше лавины
Формат записи:

{
"value": value,
"expires_at": expires_at,
"stale_until": expires_at + 300,
}


Логика простая:
- свежий TTL жив - отдаём кэш;
- TTL истёк, но stale_until жив - отдаём stale и обновляем в фоне;
- stale-окно истекло - ждём refresh или возвращаем controlled error.

Production-нюансы
- lock обязан иметь TTL, иначе упавший воркер заблокирует refresh;
- refresh должен иметь timeout, retry budget и circuit breaker;
- stale нельзя бездумно включать для балансов, прав доступа и лимитов;
- метрики обязательны: cache_hit, stale_hit, lock_wait_seconds, refresh_errors.

Вывод:
Защита от cache stampede - это не один lock, а согласованный дизайн TTL, singleflight, jitter, stale-окон и отказоустойчивого refresh.
More from @python_tesst
  1. Sep 29, 2026Стикмену теперь под силу снести любой сайт. Чувак под это навайбкодил целую игруху: грузиш…
  2. Sep 28, 2026Post #3191
  3. Sep 27, 2026OpenAI метит в подписку за 500 баксов Что там в описании тарифа? Пока что от ChatGPT Pro о…
  4. Sep 27, 2026Свежая обложка The Economist подъехала Журналисты: да мы вообще не сгущаем краски Те же жу…
  5. Sep 27, 2026Ночная годнота: Docker выкатила первые официальные скиллы для ИИ-агентов, которые ковыряют…
  6. Sep 26, 2026Claude Code больше не будет рубить всё на полуслове, если 5-часовой лимит прилетит прямо п…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →