# Не вычисляй то, что можешь запомнить

Экспресс-курс о кэшировании. 20 понятий — cache hit и miss, hit ratio, CDN, Redis, TTL, cache invalidation, cache-aside, write-through, LRU, cache stampede и другие — у каждого английское название, схема, пример и карточка. От браузера и CDN до хранилищ в памяти и кэша процессора. В конце — шпаргалка по всем понятиям на одной странице.

- **Author:** Фёдор Чищин
- **Level:** intro
- **Reading time:** ~30 минут чтения
- **Published:** 2026-06-13
- **Source:** https://fedorthinks.com/ru/learn/caching-express

---

## 1. Что такое кэш

Кэш — это одна простая идея: держать копию ответа где-то быстро, чтобы не платить за его производство дважды. Пойми это — и любой кэш, что встретишь, окажется тем же трюком в другом месте.

### Карта: 20 понятий в семи группах

> Карта метро: сначала видишь линии целиком, потом едешь по станциям.

Сначала три **основы** — что такое кэш, попадание и промах, и почему это вообще работает. Дальше шесть групп, по одной на главу: **слои** кэшей, **hit ratio**, **свежесть**, **стратегии** обновления и вытеснения, **ловушки** и как **применять хорошо**.

У каждого понятия дальше одно и то же: **английское название** (запомни его — это термин), образ из жизни, **схема** и **карточка** с полями: _проблема_, _идея_, _пример_, _цена_, _когда брать_ и _связи_.

_Diagram: Основы сверху, ниже — шесть групп, по ним идут главы 2–7._

### Cache — кэш помнит ответ

> Блокнот на столе рядом с медленным шкафом документов — раз что-то нашёл, записываешь, чтобы в следующий раз прочитать заметку, а не идти через комнату снова.

**Кэш (cache)** — это маленькое, быстрое хранилище, что держит результат дорогой работы — запроса к базе, посчитанной страницы, скачанного файла, — чтобы следующий запрос за ним был дёшев. Дорогое случается раз; дешёвое чтение — много раз. Это весь принцип. Всё остальное — детали о том, где живёт блокнот и когда доверять тому, что на нём.

_Diagram: Приложение сначала спрашивает кэш. К медленному источнику идёт, только если ответа нет._

#### Cache (кэш)

- **Проблема:** Одна и та же дорогая работа делается снова и снова.
- **Идея:** Сохранить результат в быстром месте и читать его оттуда.
- **Пример:** Посчитанная страница, результат запроса к базе, скачанный файл лежат в кэше.
- **Цена:** Память под копии и риск, что копия устареет.
- **Связи:** Всё остальное в курсе — про то, где кэш живёт и когда ему верить.

### Cache hit и cache miss — два исхода

> Тянешься к заметке. Либо она там, и ты читаешь мгновенно, — либо пуста, и приходится всё же идти к шкафу.

Когда ответ в кэше — это **попадание (cache hit)**, быстро и дёшево. Когда нет — это **промах (cache miss)**: делаешь медленную работу и обычно сохраняешь результат, чтобы в следующий раз было попадание. Эти два слова описывают любое взаимодействие с кэшем. Вся игра кэширования — превращать промахи в попадания.

_Diagram: Попадание — ответ сразу. Промах — поход к источнику и сохранение результата на будущее._

#### Cache hit / miss (попадание / промах)

- **Что это:** Hit — ответ нашёлся в кэше. Miss — не нашёлся.
- **Как работает:** При промахе делаешь медленную работу и кладёшь результат в кэш — следующий раз будет hit.
- **Пример:** Первый заход на страницу — miss и запрос к базе; второй — hit за миллисекунды.
- **Связи:** Доля попаданий — это **hit ratio**, главный балл кэша.

### Locality — это работает благодаря повторению

> Кофейня, запоминающая заказы завсегдатаев, — оправдано лишь потому, что одни и те же люди просят одно и то же снова и снова.

Кэширование окупается, когда одни и те же ответы нужны многократно, — а почти всё в вычислениях повторяется. Это свойство называют **локальностью (locality)**: доступ не случаен, а скучен на нескольких **горячих (hot)** элементах. Одна популярная страница, профиль того же пользователя, тот же поиск, спрошенный тысячи раз. Поэтому маленький кэш популярных может впитать огромную долю работы. Нет повторения — нет смысла кэшировать.

_Diagram: Несколько горячих элементов собирают большую часть запросов; длинный хвост спрашивают редко._

#### Locality (локальность, hot set)

- **Что это:** Одни и те же данные запрашивают снова и снова.
- **Почему важно:** Маленький кэш горячих элементов ловит огромную долю запросов.
- **Пример:** Популярная страница, профиль того же пользователя, тот же поиск.
- **Подвох:** Нет повторения — кэш почти не попадает и только тратит память.
- **Связи:** Именно локальность делает высокий **hit ratio** возможным.

> **Вопрос рамки:** «Дорого ли этот ответ производить и спрашивают ли его многократно — два условия, что делают запоминание стоящим хлопот?»

> Кэш держит быструю копию дорогого ответа. Попадание — это прочесть заметку; промах — это поход к шкафу. Работа — превращать промахи в попадания.

## 2. Кэши повсюду

Кэширование — это не одна вещь в одном месте, а паттерн, повторённый на каждом слое между пользователем и данными. Чем ближе копия к тому, кому нужна, тем она быстрее.

### Cache Hierarchy — чем ближе кэш, тем быстрее попадание

> Запасы, что ты держишь на столе, в комнате, в здании и на складе через город, — чем ближе, тем быстрее достанешь, но тем меньше влезает.

Между пользователем и истиной есть лестница кэшей — **иерархия кэшей (cache hierarchy)**: **браузер** держит файлы на твоём устройстве, **CDN** держит копии рядом с твоим городом, **приложение** держит горячие данные в памяти, а у **процессора (CPU)** есть крошечные кэши в наносекундах. Ближние кэши быстрее, но меньше. Запрос пробует ближайший первым и отступает наружу при промахе.

_Diagram: Запрос идёт от ближнего кэша к дальнему. Ближе — быстрее, но меньше._

#### Cache Hierarchy (иерархия / слои кэшей)

- **Проблема:** Один кэш не может быть одновременно близким, быстрым и большим.
- **Идея:** Цепочка кэшей: ближний маленький и быстрый, дальний большой и медленнее.
- **Пример:** Браузер → CDN → кэш приложения (Redis) → база данных.
- **Цена:** Больше мест, где может лежать устаревшая копия.
- **Связи:** Слои — это **CDN**, **in-memory cache** и кэши CPU.

### In-memory Cache (Redis) — рабочая лошадка

> Клерк, что держит самые спрашиваемые файлы на столе под рукой, вместо того чтобы доставать каждый из подвального архива каждый раз.

Большинство приложений ставят выделенный **кэш в памяти (in-memory cache)** — инструмент вроде **Redis** или **Memcached** — между приложением и базой. Память драматически быстрее диска, так что держать горячие результаты там превращает медленный запрос к базе в почти мгновенное чтение. Когда говорят «добавь кэш», чтобы ускорить бэкенд, обычно имеют в виду именно это.

_Diagram: Redis хранит пары «ключ → значение» в оперативной памяти. В базу на диске идём только при промахе._

#### In-memory Cache (Redis, Memcached)

- **Проблема:** Запросы к базе на диске медленные, а одни и те же повторяются.
- **Идея:** Держать горячие результаты в оперативной памяти по ключу.
- **Пример:** Ключ `user:42` хранит профиль; приложение читает его из Redis, а не из базы.
- **Цена:** Ещё один сервис; память ограничена; копии могут устареть.
- **Когда брать:** Чтобы ускорить бэкенд перед медленным источником истины.
- **Связи:** Обычно наполняется по паттерну **cache-aside**.

### CDN — кэш веба рядом с пользователем

> Популярные книги, что лежат в местных библиотеках повсюду, чтобы никому не пришлось слать запрос в единственный центральный архив.

**CDN (content delivery network)** — это кэширование, применённое к географии: оно держит копии твоих страниц, картинок и файлов на серверах по всему миру (**edge**-серверах), обслуживая каждого пользователя с ближнего. Поэтому глобальный сайт грузится быстро везде, а не только рядом с исходным сервером (**origin**). Это та же идея попадание/промах — копия просто разбросана по карте, чтобы побить расстояние.

_Diagram: Пользователь получает копию с ближайшего edge-сервера. К origin edge идёт только при промахе._

#### CDN (content delivery network)

- **Проблема:** Сервер в одной стране — и далёкие пользователи ждут из-за расстояния.
- **Идея:** Держать копии на edge-серверах по всему миру.
- **Пример:** Картинки сайта отдаются из ближайшего к пользователю города, а не с origin.
- **Цена:** Копии по всему миру тоже устаревают; их надо уметь обновить.
- **Когда брать:** Статика, страницы и файлы для пользователей в разных местах.
- **Связи:** Один из слоёв **cache hierarchy**.

> **Вопрос слоёв:** «На каком слое — браузер, CDN, память приложения, база — стоит кэшировать этот ответ, учитывая, кто его спрашивает и насколько близко я могу положить его к ним?»

> Кэширование — паттерн, повторённый на каждом слое: браузер, CDN, хранилище в памяти, процессор. Ближе — быстрее, но меньше, а промах отступает наружу к следующему.

## 3. Hit ratio — вот суть

Кэш стоит своей сложности, только если реально ловит большинство запросов. Одно число — hit ratio — говорит, отрабатывает ли кэш своё содержание.

### Hit Ratio — тот балл, что важен

> Вратаря судят по доле ударов, что он берёт. Тот, кто берёт 95%, преображает игру; тот, кто берёт 10%, едва её меняет.

**Hit ratio** (доля попаданий) — это доля запросов, обслуженных из кэша, а не из медленного источника. Hit ratio 95% значит, что лишь один запрос из двадцати доходит до базы — огромное снижение нагрузки и задержки. Hit ratio 10% значит, что кэш в основном накладные расходы. Это единственное число — то, как ты судишь, работает ли кэш.

_Diagram: 95%: до базы доходит один запрос из двадцати. 10%: кэш почти ничего не ловит._

#### Hit Ratio (доля попаданий)

- **Что это:** hits ÷ (hits + misses) — доля запросов, обслуженных из кэша.
- **Пример:** 95% — до базы доходит 1 запрос из 20. 10% — кэш почти бесполезен.
- **Зачем:** Главный способ понять, работает ли кэш, и главный рычаг настройки.
- **Связи:** Растёт благодаря **locality** и умному **eviction**; падает при **cold cache** и коротком **TTL**.

### Cold и Warm Cache — холодный кэш должен прогреться

> Новый магазин с пустыми полками сперва никого не обслуживает быстро — он затоваривается по мере спроса, пока популярное не окажется всегда под рукой.

Сразу после старта кэш **холодный (cold)** — пуст, так что каждый запрос промахивается и идёт к медленному источнику. По мере реального трафика он наполняется популярными ответами и становится **тёплым (warm)**, а hit ratio растёт. Поэтому производительность может выглядеть плохо сразу после рестарта или деплоя, а потом устаканиться. Некоторые системы **прогревают (pre-warm)** кэш намеренно, загружая известно-горячие данные до прихода пользователей.

_Diagram: После рестарта hit ratio начинается с нуля и растёт. Прогретый заранее кэш стартует высоко._

#### Cold / Warm Cache (холодный / тёплый кэш, pre-warming)

- **Что это:** Cold — пустой кэш, всё промахивается. Warm — наполненный, попадает.
- **Пример:** После деплоя сайт пару минут тормозит, пока кэш не наполнится популярным.
- **Подвох:** Рестарт всех узлов сразу бьёт всей нагрузкой по базе.
- **Решение:** **Pre-warm**: загрузить горячие данные до прихода пользователей.
- **Связи:** Объясняет провалы **hit ratio** после рестартов.

### Memory–Speed Trade-off — кэш меняет память на скорость

> Аренда стола побольше, чтобы под рукой влезло больше файлов, — это стоит места, но к шкафу ходишь куда реже.

Кэширование не бесплатно: ты тратишь **память (memory)**, что ограничена и стоит денег, чтобы сэкономить **время**. Кэш побольше держит больше и попадает чаще, но всё закэшировать нельзя — так что искусство в кэшировании _правильных_ вещей: горячих, дорогих, многократно спрашиваемых ответов, что дают больше всего скорости на байт. Кэш — это намеренный **размен (trade-off)**.

_Diagram: Платишь памятью, покупаешь время. Hit ratio показывает, окупается ли сделка._

#### Memory–Speed Trade-off (размен памяти на скорость)

- **Идея:** Платишь памятью за то, чтобы реже ходить к медленному источнику.
- **Пример:** Больше RAM под Redis — больше ключей влезает, чаще попадания.
- **Цена:** Память ограничена и стоит денег; всё не закэшируешь.
- **Когда брать:** Кэшируй то, что даёт больше всего скорости на байт: горячее и дорогое.
- **Связи:** Окупаемость меряет **hit ratio**; место освобождает **eviction**.

> **Вопрос доли:** «Какую долю запросов этот кэш реально обслуживает — и достаточно ли эта доля высока, чтобы оправдать память, что он стоит?»

> Hit ratio — это табель кэша. Ты тратишь память, чтобы купить скорость, — так кэшируй горячие, дорогие ответы, что зарабатывают больше всего попаданий на байт.

## 4. Держать свежим

Запомненный ответ может устареть, пока ты ему всё ещё доверяешь. Знать, когда перестать доверять копии, — центральная, по-настоящему сложная задача кэширования.

### Stale Data — устаревшие данные, цена кэширования

> Тот номер телефона, что ты черкнул на стикере, — золото, ровно до тех пор, пока друг не переедет и заметка тихо не станет неверной.

Оборотная сторона запоминания ответа в том, что настоящий ответ может измениться, а твоя копия — нет. **Устаревшее (stale)** значение — это закэшированное значение, что больше не совпадает с истиной: старая цена, удалённый пост, остаток на складе час назад. Любой кэш рискует отдать устаревшее, и решить, сколько устаревания ты терпишь, — первый настоящий вопрос проектирования любого кэша.

_Diagram: Цена в источнике изменилась, а копию в кэше никто не обновил — она устарела._

#### Stale Data (устаревшие данные)

- **Что это:** Значение в кэше, которое больше не совпадает с источником.
- **Пример:** Старая цена, удалённый пост, остаток на складе час назад.
- **Почему бывает:** Истина поменялась, а копия — нет.
- **Связи:** Ограничивают **TTL** и **invalidation**; допустимую меру задаёт **staleness budget**.

### TTL — пусть истекает по таймеру

> Молоко с датой «годно до» — после неё ты не доверяешь ему без проверки, даже если выглядит нормально.

Простейший инструмент свежести — **TTL (time to live)**: каждая запись кэша получает срок, и после него запись считается исчезнувшей, вынуждая свежий запрос. Короткий TTL — свежее данные, но больше промахов; длинный TTL — больше попаданий, но больше устаревания. Выбор TTL — это выбор твоей точки на размене «свежесть против скорости» — под каждый вид данных, по тому, как быстро он реально меняется.

_Diagram: Пока TTL не истёк, ответ берут из кэша. После — следующий запрос идёт за свежими данными._

#### TTL (time to live, срок жизни)

- **Проблема:** Копия может устареть, а кэш об этом не знает.
- **Идея:** Дать каждой записи срок годности; после него — перезапросить.
- **Пример:** Курс валют в кэше с TTL 60 секунд: не старше минуты.
- **Цена:** Короткий TTL — больше промахов; длинный — больше устаревания.
- **Когда брать:** Почти всегда как базовая страховка; подбирай под каждый вид данных.
- **Связи:** Одновременное истечение горячего ключа вызывает **cache stampede**.

### Cache Invalidation — почему это знаменито сложно

> Знать миг, когда факт изменился где-то ещё в мире, чтобы порвать заметку ровно в нужный момент, — легко сказать, бесит делать.

Есть ходячая шутка, что в информатике лишь две сложные задачи, и **инвалидация кэша (cache invalidation)** — знать, когда закэшированное значение надо выбросить, — одна из них. Сложна она потому, что кэш часто не знает, что лежащие данные изменились; изменение случилось где-то ещё. Следующая глава — набор стратегий против ровно этой задачи.

_Diagram: Один сервис меняет базу, другой читает старую копию из кэша. Кто скажет кэшу, что пора?_

#### Cache Invalidation (инвалидация кэша)

- **Проблема:** Данные изменились где-то ещё, а кэш об этом не знает.
- **Идея:** Выбросить или обновить копию, когда истина меняется.
- **Пример:** После смены цены удалить ключ товара из кэша.
- **Цена:** Надо найти все места, где лежит копия, и не пропустить ни одного.
- **Связи:** Стратегии — **cache-aside**, **write-through**, **write-around**; страховка — **TTL**.

> **Вопрос свежести:** «Насколько устаревшими эти данные могут безопасно быть — и хватит ли простого TTL, или нужно активно выбрасывать копию, когда истина меняется?»

> Любой закэшированный ответ может устареть. TTL истекает по таймеру — а знать точно, когда инвалидировать, это одна из по-настоящему сложных задач вычислений.

## 5. Инвалидация и вытеснение

Две силы решают, что в кэше и можно ли ему доверять: как ты обновляешь его, когда истина меняется, и как освобождаешь место, когда он полон. У обеих есть именованные стратегии, что стоит знать.

### Cache-aside — приложение наполняет кэш

> Сначала смотришь в блокнот; если пусто, идёшь к шкафу, читаешь файл и записываешь ответ, прежде чем продолжить.

Самый частый паттерн — **cache-aside** (ещё его зовут **lazy loading**, ленивая загрузка): на чтении приложение смотрит в кэш; при промахе достаёт из источника, сохраняет результат и возвращает. Кэш наполняется по требованию ровно тем, что реально спрашивают. Это просто и популярно — а слабое место в устаревании, ведь значение лежит в кэше, пока что-то не истечёт или не инвалидирует его.

_Diagram: Шаги cache-aside: спросить кэш → промах → прочитать базу → положить в кэш → отдать._

#### Cache-aside (lazy loading, ленивая загрузка)

- **Проблема:** Нужно наполнять кэш, не зная заранее, что спросят.
- **Идея:** Приложение само: смотрит в кэш, при промахе читает базу и кладёт результат в кэш.
- **Пример:** `GET user:42` → промах → `SELECT` из базы → `SET user:42` с TTL.
- **Цена:** Значение может устареть, пока не истечёт TTL или его не удалят.
- **Когда брать:** Дефолт для большинства кэшей перед базой.
- **Связи:** Часто вместе с **TTL**; на записи дополняется **write-through**.

### Write-through и Write-around — держать записи согласованными

> Когда факт меняется, можно обновить заметку на столе в тот же миг, что и мастер-файл, — или пропустить заметку и дать перечитать её свежей в следующий раз.

Когда данные _пишутся_, ты выбираешь, как кэш поспевает. **Write-through** обновляет кэш и источник вместе, так что кэш никогда не устаревает (ценой медленных записей). **Write-around** пишет только в источник и даёт кэшу промахнуться и перезагрузить позже, избегая кэширования данных, что никто не перечитывает. Что выбрать, зависит от твоего баланса чтений и записей.

_Diagram: Write-through пишет в кэш и базу сразу. Write-around пишет только в базу, кэш догонит на промахе._

#### Write-through / Write-around (политики записи)

- **Проблема:** При записи кэш и источник расходятся.
- **Идея:** Write-through — обновить кэш и базу вместе. Write-around — писать только в базу.
- **Пример:** Профиль, который сразу перечитывают, — write-through. Логи, которые почти не читают, — write-around.
- **Цена:** Write-through — медленнее записи. Write-around — первый промах после записи.
- **Когда брать:** По балансу чтений и записей.
- **Связи:** Способы **cache invalidation** на стороне записи.

### Eviction (LRU, LFU) — что выбросить, когда полно

> Маленький стол, что полон, — чтобы добавить новый файл, надо убрать один, так что убираешь тот, что не трогал вечность, а не тот, что используешь ежечасно.

У кэша ограниченное место, так что, наполнившись, он должен **вытеснить (evict)** что-то. Самая частая политика — **LRU (least recently used)**: выбрось то, что дольше всех не трогали, на ставке, что скоро оно не понадобится. Есть и другие — **LFU (least frequently used)** выбрасывает реже всего используемое. Вытеснение — это как маленький кэш автоматически держит горячее и сбрасывает холодное, не разрастаясь вечно.

_Diagram: Кэш полон, приходит F. По LRU уходит B — его дольше всех не трогали._

#### Eviction (вытеснение · LRU, LFU)

- **Проблема:** Место в кэше кончилось, а новые данные приходят.
- **Идея:** Выбросить то, что вряд ли скоро понадобится.
- **Пример:** LRU — выбросить давно нетронутое. LFU — выбросить реже всего используемое.
- **Цена:** Иногда выбрасывается то, что вот-вот спросят, — лишний промах.
- **Связи:** Держит **hit ratio** высоким без роста памяти. Не путать с **invalidation**: та про неверное, eviction — про место.

> **Вопрос стратегии:** «Когда лежащие данные меняются, как этот кэш об этом узнаёт — и когда он полон, выбрасывает ли он по-настоящему холодные записи?»

> Инвалидация решает, когда закэшированное значение неверно; вытеснение решает, что выбросить, когда место кончилось. Cache-aside, write-through, LRU — имена для этих двух работ.

## 6. Когда кэш кусает

Мощь кэширования идёт с острыми краями. Классические сбои не экзотичны — они предсказуемы, у них есть имена, и знать их — половина того, чтобы их избежать.

### Cache Stampede — когда горячий ключ истекает

> Популярный товар распродаётся, и в тот же миг сотня покупателей разом ломится к стойке спросить его — захлёстывая единственного клерка, что пополняет запас.

Когда популярная запись кэша истекает, каждый запрос, что её хотел, промахивается _в один и тот же миг_ и все бьют в медленный источник вместе — это **cache stampede** (или **thundering herd**, «гром стада»). База, защищённая часами, вдруг принимает всю толпу разом и может прогнуться. Лекарства известны — дать одному запросу обновить, пока другие ждут, или разнести сроки истечения, — но это надо предвидеть: stampede появляется ровно тогда, когда трафик выше всего.

_Diagram: Горячий ключ истёк — все запросы разом летят в базу. Внизу два известных лекарства._

#### Cache Stampede (thundering herd, «гром стада»)

- **Проблема:** Горячий ключ истёк, и все запросы одновременно промахиваются и бьют в базу.
- **Пример:** Главная страница истекает в пик трафика — тысячи запросов разом строят её заново.
- **Лекарство:** Один запрос обновляет, остальные ждут; или случайный разброс TTL (jitter).
- **Когда думать:** Для каждого горячего ключа с **TTL**.
- **Связи:** Следствие **TTL** на популярных данных.

### Stale Reads — быстро, уверенно и неверно

> Прочитать цену со старого стикера и уверенно её назвать — число выдано мгновенно, и это неверное число.

Кэш с радостью отдаст **устаревшее** значение быстро и с полной уверенностью — это **устаревшее чтение (stale read)**. Обычно это нормально — слегка старый счётчик просмотров никому не вредит. Но для данных, где правильность критична — баланс банка, остатки, права доступа, — устаревшее чтение может быть настоящим багом. Навык — знать, какие данные терпят устаревание, а какие должны быть всегда свежими, и никогда не кэшировать второй вид небрежно.

#### Stale Read (устаревшее чтение)

- **Проблема:** Кэш отдаёт старое значение быстро и уверенно.
- **Не страшно:** Счётчик просмотров на минуту старше.
- **Настоящий баг:** Баланс банка, остатки на складе, права доступа.
- **Лекарство:** Решить заранее, какие данные терпят устаревание, а какие нет.
- **Связи:** Проявление **stale data**; лечится **staleness budget**.

### What Not to Cache — некоторое вообще не стоит кэшировать

> Ты не держишь ксерокопию документа, что переписывают каждую минуту, или чьего-то приватного письма на общем столе, — копия неверна или ей там не место.

Не всё уместно в кэше. Данные, что **меняются постоянно**, дают плохой hit ratio и частое устаревание. **Чувствительные или попользовательские (per-user)** данные рискуют утечь, если общий кэш вручит копию одного пользователя другому. А **редко спрашиваемые** данные просто тратят место. Знать, что _не_ кэшировать, так же важно, как знать, что кэшировать.

_Diagram: Три вида данных, которым не место в кэше. Внизу — как общий кэш отдаёт данные A пользователю B._

#### What Not to Cache (что не кэшировать)

- **Быстро меняющееся:** Плохой hit ratio и постоянное устаревание.
- **Чувствительное:** Попользовательские и секретные данные в общем кэше могут уйти чужому пользователю.
- **Непопулярное:** Редко спрашивают — только занимает место.
- **Связи:** Обратная сторона **cache target**.

> **Вопрос ловушки:** «Что станет с моим медленным источником в тот миг, как горячая запись истечёт, — и нет ли в этом кэше чего-то слишком критичного по свежести или слишком чувствительного, чтобы там быть вообще?»

> Классические укусы кэширования именованы: stampede, когда горячий ключ истекает, устаревшие чтения, выданные с ложной уверенностью, и кэширование того, что никогда не следовало.

## 7. Применять хорошо

Кэширование — силовой инструмент: огромная скорость за немного памяти, оплаченная риском выдать прошлое. Применённое намеренно, это один из лучших разменов в вычислениях.

### Cache Target — кэшируй горячее, дорогое и медленно меняющееся

> Ты запоминаешь привычные заказы завсегдатаев и дорогу, что объясняешь десять раз в день, — а не разовые просьбы или то, что меняется поминутно.

Идеальная цель кэша (**cache target**) — **часто читаемое, дорогое в производстве и редко меняемое**: эта комбинация даёт больше всего скорости при наименьшем риске устаревания. Популярная страница, построенная из медленного запроса, пересчитываемая одинаково весь день, — идеальна. Постоянно меняющееся, редко читаемое, чувствительное значение — наоборот.

_Diagram: Три условия вместе дают идеальную цель для кэша._

#### Cache Target (что кэшировать)

- **Идея:** Часто читаемое + дорогое в производстве + редко меняемое.
- **Пример:** Популярная страница из медленного запроса, одинаковая весь день.
- **Антипример:** Постоянно меняющееся, редко читаемое, чувствительное значение.
- **Связи:** Противоположность **what not to cache**; даёт высокий **hit ratio**.

### Staleness Budget — реши бюджет устаревания заранее

> Договориться заранее, насколько устаревшее приемлемо, — виджет погоды может быть на минуты старым; баланс банка не может быть на секунды старым.

Прежде чем что-то кэшировать, реши, сколько **устаревания** оно терпит, — это и есть **бюджет устаревания (staleness budget)**. Этот выбор гонит всё остальное — TTL, нужна ли активная инвалидация, безопасно ли кэшировать вообще. Сделай это явно под каждый вид данных. «Насколько неверным ему позволено быть и как долго?» — вопрос, что превращает кэширование из источника загадочных багов в управляемый, намеренный размен.

_Diagram: Слева — данные, что терпят устаревание, справа — что должны быть всегда свежими._

#### Staleness Budget (бюджет устаревания)

- **Проблема:** Без явного решения устаревание всплывает как загадочные баги.
- **Идея:** Для каждого вида данных заранее решить: насколько старым можно быть.
- **Пример:** Погода — минуты можно. Баланс банка — ни секунды.
- **Что задаёт:** Длину **TTL**, нужна ли **invalidation**, кэшировать ли вообще.
- **Связи:** Отвечает на риск **stale data** и **stale reads**.

### Как понятия связаны

> Две чаши весов: на одной скорость, на другой свежесть. Каждое понятие курса двигает одну из них.

Всё кэширование — это перетягивание между **скоростью** и **свежестью**. Слева то, что поднимает **hit ratio**: локальность, прогретый кэш, разумное вытеснение. Справа то, что держит **stale data** под контролем: бюджет устаревания задаёт **TTL**, а **invalidation** выбрасывает неверное. Короткий TTL — свежее, но меньше попаданий; на горячем ключе он же рождает **stampede**.

_Diagram: Слева силы скорости, справа силы свежести. Бюджет задаёт TTL; TTL ограничивает устаревание и может вызвать stampede._

#### Прежде чем добавить кэш

- **Горячие ли данные** — спрашивают ли их достаточно часто, чтобы дать реальный hit ratio?
- **Дорого ли** их производить, чтобы попадание реально экономило ощутимую работу?
- **Насколько устаревшими** они могут быть — какой TTL, и нужна ли активная инвалидация?
- **Что станет, когда горячая запись истечёт** — не вызовет ли это stampede?
- **Безопасно ли кэшировать** — не попользовательские ли это секретные данные в общем кэше?
- **Как я узна́ю, что работает** — меряю ли я hit ratio?

#### Признаки, что ты кэшируешь хорошо

- Можешь назвать **hit ratio** своих важных кэшей.
- У каждого кэшируемого — **намеренный TTL**, подогнанный под то, как быстро оно реально меняется.
- Ничего **попользовательского или секретного** не сидит в общем кэше случайно.
- Твои горячие ключи не **застемпедят** источник разом при истечении.
- Ты кэшируешь **горячие, дорогие, медленно меняющиеся** ответы — а остальное пропускаешь.

## Шпаргалка: все 20 понятий

### Основы

- **Cache** (кэш): Быстрая копия дорогого ответа, чтобы не делать работу дважды.
- **Cache hit / miss** (попадание / промах): Ответ нашёлся в кэше — или пришлось идти к источнику.
- **Locality** (локальность, hot set): Одни и те же данные спрашивают снова и снова — поэтому кэш работает.

### Слои

- **Cache Hierarchy** (иерархия кэшей): Браузер → CDN → память приложения → база. Ближе — быстрее, но меньше.
- **In-memory Cache** (Redis, Memcached): Горячие данные в RAM перед медленной базой.
- **CDN** (content delivery network): Копии файлов и страниц на серверах рядом с пользователями.

### Hit ratio

- **Hit Ratio** (доля попаданий): Доля запросов из кэша. Главный балл кэша.
- **Cold / Warm Cache** (холодный / тёплый): Пустой кэш всё промахивает; наполненный попадает. Pre-warm — прогрев заранее.
- **Memory–Speed Trade-off** (память ↔ скорость): Платишь памятью, покупаешь время. Кэшируй больше скорости на байт.

### Свежесть

- **Stale Data** (устаревшие данные): Копия больше не совпадает с истиной.
- **TTL** (time to live): Срок жизни записи; после него — перезапрос.
- **Cache Invalidation** (инвалидация): Выбросить копию, когда истина изменилась. Знаменито сложно.

### Стратегии

- **Cache-aside** (lazy loading): Приложение смотрит в кэш, при промахе читает базу и кладёт результат.
- **Write-through / Write-around** (политики записи): Писать в кэш и базу сразу — или только в базу.
- **Eviction (LRU / LFU)** (вытеснение): Когда полно — выбросить давно нетронутое или редко используемое.

### Ловушки

- **Cache Stampede** (thundering herd): Горячий ключ истёк — все разом бьют в базу.
- **Stale Read** (устаревшее чтение): Быстро, уверенно и неверно. Опасно для денег, остатков, прав.
- **What Not to Cache** (что не кэшировать): Быстро меняющееся, чувствительное, непопулярное.

### Применять хорошо

- **Cache Target** (что кэшировать): Часто читаемое, дорогое, редко меняемое.
- **Staleness Budget** (бюджет устаревания): Заранее решить, насколько старым можно быть. Задаёт TTL и инвалидацию.

> Кэширование меняет немного памяти на огромную скорость, рискуя выдать прошлое. Сделанное хорошо, оно намеренно: правильные ответы и бюджет устаревания, что ты выбрал нарочно.

Конец экспресс-курса · 7 глав · 20 понятий

Дальше — практика: найди самую медленную повторяющуюся операцию в чём-то, что ты построил, — запрос, вызов API, посчитанную страницу — и поставь перед ней маленький кэш с явным TTL. Потом смотри, как меняются hit ratio и задержка. Размен становится реальным в тот миг, как ты его меряешь. Но держи одну мысль выше прочих: кэширование — это просто запоминание дорогого ответа вместо переделки работы, — и каждая сложная часть на деле один вопрос, заданный честно: когда то, что я запомнил, перестало быть правдой?
