fedorthinks

Экспресс-курс · No. 15

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

20 понятий · схема у каждого · шпаргалка в конце

§ 01

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

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

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

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

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

BasicsCacheHit / missLocalityLayersCache hierarchyIn-memory (Redis)CDNHit ratioHit ratioCold / warm cacheMemory ↔ speedFreshnessStale dataTTLCache invalidationStrategiesCache-asideWrite-through / aroundEviction (LRU)TrapsCache stampedeStale readsWhat not to cacheUsing it wellHot · costly · stableStaleness budget
Основы сверху, ниже — шесть групп, по ним идут главы 2–7.

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

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

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

Appneeds an answerCachesmall · fastSource of truthDB · API · computeask firstonly if missingexpensive work once → cheap reads many times
Приложение сначала спрашивает кэш. К медленному источнику идёт, только если ответа нет.
ConceptCache· кэш
Проблема
Одна и та же дорогая работа делается снова и снова.
Идея
Сохранить результат в быстром месте и читать его оттуда.
Пример

Посчитанная страница, результат запроса к базе, скачанный файл лежат в кэше.

Цена
Память под копии и риск, что копия устареет.
Связи
Всё остальное в курсе — про то, где кэш живёт и когда ему верить.

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

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

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

HITRequestCachefound ✓Responsefast · cheapMISSRequestCachenot found ✗Sourceslow workstore the result → next time it's a hit
Попадание — ответ сразу. Промах — поход к источнику и сохранение результата на будущее.
TermCache hit / miss· попадание / промах
Что это
Hit — ответ нашёлся в кэше. Miss — не нашёлся.
Как работает

При промахе делаешь медленную работу и кладёшь результат в кэш — следующий раз будет hit.

Пример

Первый заход на страницу — miss и запрос к базе; второй — hit за миллисекунды.

Связи
Доля попаданий — это hit ratio, главный балл кэша.

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

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

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

requestsitems, most popular firsthot set — a small cache catches most requestslong tail — rarely asked, not worth caching
Несколько горячих элементов собирают большую часть запросов; длинный хвост спрашивают редко.
ConceptLocality· локальность, hot set
Что это
Одни и те же данные запрашивают снова и снова.
Почему важно
Маленький кэш горячих элементов ловит огромную долю запросов.
Пример
Популярная страница, профиль того же пользователя, тот же поиск.
Подвох
Нет повторения — кэш почти не попадает и только тратит память.
Связи
Именно локальность делает высокий hit ratio возможным.

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

§ 02

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

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

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

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

UserBrowseryour deviceCDNnear your cityApp cacheRedis · RAMDatabaseorigineach miss falls outward →closer: faster, smallerfarther: slower, biggerand inside every machine: CPU caches (L1 / L2 / L3), nanoseconds away
Запрос идёт от ближнего кэша к дальнему. Ближе — быстрее, но меньше.
ConceptCache Hierarchy· иерархия / слои кэшей
Проблема
Один кэш не может быть одновременно близким, быстрым и большим.
Идея
Цепочка кэшей: ближний маленький и быстрый, дальний большой и медленнее.
Пример
Браузер → CDN → кэш приложения (Redis) → база данных.
Цена
Больше мест, где может лежать устаревшая копия.
Связи
Слои — это CDN, in-memory cache и кэши CPU.

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

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

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

AppRedis / Memcached · in RAMuser:42 → {name, plan}page:/home → <html>top:products → [ … ]Databaseon disk · slowGETmiss
Redis хранит пары «ключ → значение» в оперативной памяти. В базу на диске идём только при промахе.
ToolIn-memory Cache· Redis, Memcached
Проблема
Запросы к базе на диске медленные, а одни и те же повторяются.
Идея
Держать горячие результаты в оперативной памяти по ключу.
Пример

Ключ user:42 хранит профиль; приложение читает его из Redis, а не из базы.

Цена
Ещё один сервис; память ограничена; копии могут устареть.
Когда брать
Чтобы ускорить бэкенд перед медленным источником истины.
Связи
Обычно наполняется по паттерну cache-aside.

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

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

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

Edge · Tokyocopy near usersEdge · Pariscopy near usersEdge · São Paulocopy near usersEdge · New Yorkcopy near usersOriginone servermiss → fetch from origin onceusers hit the nearest edge
Пользователь получает копию с ближайшего edge-сервера. К origin edge идёт только при промахе.
ToolCDN· content delivery network
Проблема

Сервер в одной стране — и далёкие пользователи ждут из-за расстояния.

Идея
Держать копии на edge-серверах по всему миру.
Пример

Картинки сайта отдаются из ближайшего к пользователю города, а не с origin.

Цена
Копии по всему миру тоже устаревают; их надо уметь обновить.
Когда брать
Статика, страницы и файлы для пользователей в разных местах.
Связи
Один из слоёв cache hierarchy.

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

§ 03

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

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

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

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

95%19 hits · only 1 request in 20 reaches the database10%2 hits · 18 misses — the cache is mostly overheadhitmiss
95%: до базы доходит один запрос из двадцати. 10%: кэш почти ничего не ловит.
TermHit Ratio· доля попаданий
Что это
hits ÷ (hits + misses) — доля запросов, обслуженных из кэша.
Пример
95% — до базы доходит 1 запрос из 20. 10% — кэш почти бесполезен.
Зачем
Главный способ понять, работает ли кэш, и главный рычаг настройки.
Связи

Растёт благодаря locality и умному eviction; падает при cold cache и коротком TTL.

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

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

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

hit ratiotime →restart / deploy: cold, all misseswarm: popular answers cacheddashed: pre-warmed before users arrive
После рестарта hit ratio начинается с нуля и растёт. Прогретый заранее кэш стартует высоко.
TermCold / Warm Cache· холодный / тёплый кэш, pre-warming
Что это
Cold — пустой кэш, всё промахивается. Warm — наполненный, попадает.
Пример

После деплоя сайт пару минут тормозит, пока кэш не наполнится популярным.

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

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

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

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

Spend memorylimited · costs moneyCachethe right answersBuy timefewer slow tripsyou can't cache everything → most speed per byte storedthe hit ratio tells you if the trade is paying
Платишь памятью, покупаешь время. Hit ratio показывает, окупается ли сделка.
ConceptMemory–Speed Trade-off· размен памяти на скорость
Идея
Платишь памятью за то, чтобы реже ходить к медленному источнику.
Пример
Больше RAM под Redis — больше ключей влезает, чаще попадания.
Цена
Память ограничена и стоит денег; всё не закэшируешь.
Когда брать

Кэшируй то, что даёт больше всего скорости на байт: горячее и дорогое.

Связи
Окупаемость меряет hit ratio; место освобождает eviction.

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

§ 04

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

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

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

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

10:0010:05Source: $10the truthSource: $12price changedCache: $10✓ matchesCache: $10✗ stalecopyupdatenobody told the cachestale = a cached value that no longer matches the truth
Цена в источнике изменилась, а копию в кэше никто не обновил — она устарела.
TermStale Data· устаревшие данные
Что это
Значение в кэше, которое больше не совпадает с источником.
Пример
Старая цена, удалённый пост, остаток на складе час назад.
Почему бывает
Истина поменялась, а копия — нет.
Связи

Ограничивают TTL и invalidation; допустимую меру задаёт staleness budget.

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

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

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

fresh — served from cache (TTL = 60s)expired → refetchstored+60sEach entry carries an expiry timer.short TTL → fresher data, more misseslong TTL → more hits, more staleness
Пока TTL не истёк, ответ берут из кэша. После — следующий запрос идёт за свежими данными.
PracticeTTL· time to live, срок жизни
Проблема
Копия может устареть, а кэш об этом не знает.
Идея
Дать каждой записи срок годности; после него — перезапросить.
Пример
Курс валют в кэше с TTL 60 секунд: не старше минуты.
Цена
Короткий TTL — больше промахов; длинный — больше устаревания.
Когда брать

Почти всегда как базовая страховка; подбирай под каждый вид данных.

Связи
Одновременное истечение горячего ключа вызывает cache stampede.

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

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

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

Service AwritesDatabasechangedCacheold copyService BreadsUPDATEstale? who tells the cachethe change happened elsewhere
Один сервис меняет базу, другой читает старую копию из кэша. Кто скажет кэшу, что пора?
ConceptCache Invalidation· инвалидация кэша
Проблема
Данные изменились где-то ещё, а кэш об этом не знает.
Идея
Выбросить или обновить копию, когда истина меняется.
Пример
После смены цены удалить ключ товара из кэша.
Цена
Надо найти все места, где лежит копия, и не пропустить ни одного.
Связи

Стратегии — cache-aside, write-through, write-around; страховка — TTL.

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

§ 05

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

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

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

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

AppCacheDatabase1. GET key2. miss3. read from DB4. result5. SET key (+TTL)6. return to user — next read is a hit
Шаги cache-aside: спросить кэш → промах → прочитать базу → положить в кэш → отдать.
PatternCache-aside· lazy loading, ленивая загрузка
Проблема
Нужно наполнять кэш, не зная заранее, что спросят.
Идея

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

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

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

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

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

Write-throughWriteCacheupdatedDatabaseupdatedcache never stalecost: slower writesWrite-aroundWriteCacheskippedDatabaseupdatedcache reloads on the next missskips data nobody re-reads
Write-through пишет в кэш и базу сразу. Write-around пишет только в базу, кэш догонит на промахе.
PatternWrite-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) выбрасывает реже всего используемое. Вытеснение — это как маленький кэш автоматически держит горячее и сбрасывает холодное, не разрастаясь вечно.

F (new)cache is fullAused 1s agoBused 2h agoCused 5m agoDused 10s agoEused 1m agoB evicted — least recently used (LRU)LFU instead drops the least frequently used
Кэш полон, приходит F. По LRU уходит B — его дольше всех не трогали.
PolicyEviction· вытеснение · LRU, LFU
Проблема
Место в кэше кончилось, а новые данные приходят.
Идея
Выбросить то, что вряд ли скоро понадобится.
Пример

LRU — выбросить давно нетронутое. LFU — выбросить реже всего используемое.

Цена
Иногда выбрасывается то, что вот-вот спросят, — лишний промах.
Связи

Держит hit ratio высоким без роста памяти. Не путать с invalidation: та про неверное, eviction — про место.

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

§ 06

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

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

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

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

requestrequestrequestrequestrequestrequestHot keyjust expiredDatabaseall at once → bucklesall miss at onceFixesOne refreshes, rest waitlock / single flightStagger expiriesTTL + random jitter
Горячий ключ истёк — все запросы разом летят в базу. Внизу два известных лекарства.
PitfallCache Stampede· thundering herd, «гром стада»
Проблема

Горячий ключ истёк, и все запросы одновременно промахиваются и бьют в базу.

Пример

Главная страница истекает в пик трафика — тысячи запросов разом строят её заново.

Лекарство

Один запрос обновляет, остальные ждут; или случайный разброс TTL (jitter).

Когда думать
Для каждого горячего ключа с TTL.
Связи
Следствие TTL на популярных данных.

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

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

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

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

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

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

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

Fast-changingpoor hit ratio · staleSensitive / per-usercan leakRarely requestedwastes spacehow a leak happens:User AGET /accountShared cache/account → A's dataUser Bsees A's data ✗knowing what NOT to cache matters as much as what to cache
Три вида данных, которым не место в кэше. Внизу — как общий кэш отдаёт данные A пользователю B.
PracticeWhat Not to Cache· что не кэшировать
Быстро меняющееся
Плохой hit ratio и постоянное устаревание.
Чувствительное

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

Непопулярное
Редко спрашивают — только занимает место.
Связи
Обратная сторона cache target.

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

§ 07

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

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

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

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

Read oftenhot · high hit ratioExpensive to makeslow query · computeRarely changeslow staleness riskIdeal cache targetmost speed · least risk
Три условия вместе дают идеальную цель для кэша.
PracticeCache Target· что кэшировать
Идея
Часто читаемое + дорогое в производстве + редко меняемое.
Пример
Популярная страница из медленного запроса, одинаковая весь день.
Антипример
Постоянно меняющееся, редко читаемое, чувствительное значение.
Связи
Противоположность what not to cache; даёт высокий hit ratio.

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

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

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

can be stale for a whilemust be freshstatic filesview countweather: minutesinventorypermissionsbank balancethe budget sets the TTL, invalidation — or "don't cache"
Слева — данные, что терпят устаревание, справа — что должны быть всегда свежими.
PracticeStaleness Budget· бюджет устаревания
Проблема
Без явного решения устаревание всплывает как загадочные баги.
Идея
Для каждого вида данных заранее решить: насколько старым можно быть.
Пример
Погода — минуты можно. Баланс банка — ни секунды.
Что задаёт
Длину TTL, нужна ли invalidation, кэшировать ли вообще.
Связи
Отвечает на риск stale data и stale reads.

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

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

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

LocalityCold / warmEviction (LRU)Hit ratiospeedStampedeStale datafreshnessStaleness budgetTTLInvalidationaside · throughspeed ↔ freshnessmore hits ← cache longer · fresher ← cache shorter
Слева силы скорости, справа силы свежести. Бюджет задаёт 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 CacheRedis, Memcached

Горячие данные в RAM перед медленной базой.

CDNcontent delivery network

Копии файлов и страниц на серверах рядом с пользователями.

Hit ratio

Hit Ratioдоля попаданий

Доля запросов из кэша. Главный балл кэша.

Cold / Warm Cacheхолодный / тёплый

Пустой кэш всё промахивает; наполненный попадает. Pre-warm — прогрев заранее.

Memory–Speed Trade-offпамять ↔ скорость

Платишь памятью, покупаешь время. Кэшируй больше скорости на байт.

Свежесть

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

Копия больше не совпадает с истиной.

TTLtime to live

Срок жизни записи; после него — перезапрос.

Cache Invalidationинвалидация

Выбросить копию, когда истина изменилась. Знаменито сложно.

Стратегии

Cache-asidelazy loading

Приложение смотрит в кэш, при промахе читает базу и кладёт результат.

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

Писать в кэш и базу сразу — или только в базу.

Eviction (LRU / LFU)вытеснение

Когда полно — выбросить давно нетронутое или редко используемое.

Ловушки

Cache Stampedethundering herd

Горячий ключ истёк — все разом бьют в базу.

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

Быстро, уверенно и неверно. Опасно для денег, остатков, прав.

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

Быстро меняющееся, чувствительное, непопулярное.

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

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

Часто читаемое, дорогое, редко меняемое.

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

Заранее решить, насколько старым можно быть. Задаёт TTL и инвалидацию.

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

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

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