intermediate

Caching patterns

Применяйте cache-aside, write-through, TTL jitter, stampede protection и invalidation вокруг actual consistency needs.

Паттерны кэширования определяют, как приложение и Redis делят истину: когда читать кэш первым, когда write-through, как инвалидировать и переживать stampede. Redis — слой производительности; правила корректности остаются у source of record.

					// Cache-aside (lazy loading)
async function getProduct(id) {
  const cached = await redis.get(`product:${id}`)
  if (cached) return JSON.parse(cached)
  const row = await db.products.findById(id)
  await redis.set(`product:${id}`, JSON.stringify(row), 'EX', 300 + Math.floor(Math.random() * 30))
  return row
}

// Invalidate on write
await db.products.update(id, patch)
await redis.del(`product:${id}`)
				

| Паттерн | Идея | |---------|------| | Cache-aside | Приложение грузит кэш на miss | | Write-through | DB и кэш пишутся вместе | | Write-behind | Сначала кэш, async DB — рискованно | | TTL + jitter | Ограничение staleness; размазывание expire | | Защита от stampede | Lock, single-flight или early refresh |

Задайте допустимую staleness по сущности. Probabilistic early expiration или mutex (`SET lock NX EX`) при одновременном expire горячих ключей. Версионируйте ключи (`product:9:v3`) для rolling invalidation.

На интервью: пройдите read и write paths для одной сущности и назовите inconsistency, которую может увидеть пользователь.

Типовые ошибки: кэш как единственный источник истины; нет invalidation при update; thundering herd на популярном TTL; кэширование ошибок или пустых результатов; игнор eviction при нехватке памяти.

Компромисс — снижение latency и нагрузки vs сложность consistency: каждый паттерн переносит staleness и failure modes туда, что нужно документировать и тестировать.

Чеклист:

  • Выберите cache-aside vs write-through по сущности.
  • TTL с jitter на горячих ключах.
  • Invalidation на каждом write path.
  • Защита от stampede для топ-ключей.