# Кэш (вычисления)

> Быстрое хранилище копий данных, которое ускоряет повторный доступ к медленному источнику; от кэшей процессора и страничного кэша ОС до HTTP-кэша, CDN и Redis — с вечными вопросами инвалидации и вытеснения.

Источник: https://llmdocs.ru/wiki/cache/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Назначение**: ускорить повторный доступ к данным за счёт их копии в быстром хранилище
- **Метрика**: доля попаданий (hit ratio)
- **Политики вытеснения**: LRU, LFU, FIFO, TTL, ARC, W-TinyLFU
- **Стратегии записи**: write-through, write-back, write-around
- **Уровни**: регистры → L1/L2/L3 → ОЗУ → страничный кэш → диск → сеть
- **Прикладные кэши**: Redis, Memcached, Varnish, CDN, HTTP-кэш браузера
**Кэш** (англ. *cache*) — небольшое быстрое хранилище, в котором держат копии данных из более медленного источника, чтобы повторные обращения обслуживались быстрее. Кэши есть на всех уровнях вычислительной системы: в процессоре, операционной системе, базах данных, приложениях, браузере и сети доставки контента. Если нужные данные нашлись в кэше — это **попадание** (*cache hit*), если нет — **промах** (*cache miss*), и данные приходится доставать из источника.

## Иерархия памяти

Кэширование работает потому, что программы обладают **локальностью**: недавно использованные данные скорее всего понадобятся снова (временная локальность), а соседние с ними — тоже (пространственная).[1] Порядки задержек сильно различаются:[7]

| Уровень | Типичная задержка |
|---|---|
| Кэш L1 процессора | ~1 нс |
| Кэш L2 / L3 | ~4 / ~40 нс |
| Оперативная память | ~100 нс |
| Чтение с NVMe SSD | ~20–100 мкс |
| Запрос в пределах дата-центра | ~0,5 мс |
| Запрос через континент | ~50–150 мс |

Процессор читает память строками кэша по 64 байта, поэтому последовательный проход по массиву многократно быстрее «прыжков» по связному списку, хотя асимптотика обоих — O(n) (см. [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md)). Операционная система держит недавно прочитанные блоки файлов в **страничном кэше** — поэтому свободная память в [Linux](https://llmdocs.ru/wiki/linux.md) почти всегда «занята» под buff/cache, и это нормально.

## Где кэшируют в приложениях

- **Мемоизация функций** — запоминание результата для одинаковых аргументов:[4]

```python
from functools import lru_cache

@lru_cache(maxsize=1024)
def get_rate(currency: str) -> float:
    return fetch_from_api(currency)      # медленный внешний вызов
```

- **Кэш перед базой данных** — [Redis](https://llmdocs.ru/wiki/redis.md) или Memcached хранят результаты частых запросов, сессии, счётчики.
- **HTTP-кэш** — браузер, [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) и [CDN](https://llmdocs.ru/wiki/cdn.md) сохраняют ответы по правилам заголовков `Cache-Control`, `ETag`, `Last-Modified` (RFC 9111).[2][3]

```http
Cache-Control: public, max-age=31536000, immutable    # статика с хешем в имени
Cache-Control: no-cache                                # хранить, но проверять каждый раз
ETag: "33a64df5"                                       # клиент спросит If-None-Match → 304
```

- **Кэши сборки** — слои Docker-образов, кэш зависимостей в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), `__pycache__`, кэш компилятора.
- **Кэш в LLM** — KV-кэш внимания при генерации и [кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md) у API-провайдеров.

## Стратегии чтения и записи

- **Cache-aside** (ленивая загрузка) — самая распространённая: приложение ищет в кэше, при промахе читает из БД и кладёт результат в кэш с TTL.[6]

```python
def get_user(uid):
    if (cached := redis.get(f"user:{uid}")) is not None:
        return json.loads(cached)
    user = db.fetch_user(uid)
    redis.set(f"user:{uid}", json.dumps(user), ex=300)   # TTL 5 минут
    return user
```

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

## Вытеснение

Кэш ограничен, поэтому при заполнении нужно решать, что выбросить:

- **LRU** (*least recently used*) — дольше всего не использовавшийся элемент; классическая реализация — [хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) плюс двусвязный список, обе операции за O(1);
- **LFU** — используемый реже всего;
- **FIFO**, случайное вытеснение;
- **TTL** — элемент истекает по времени;
- адаптивные алгоритмы — ARC, W-TinyLFU (библиотеки Caffeine, Ristretto).

В Redis политика задаётся параметром `maxmemory-policy`, например `allkeys-lru` или `volatile-ttl`.[5]

## Инвалидация и типовые проблемы

Известная шутка Фила Карлтона: «В информатике есть только две сложные вещи — инвалидация кэша и придумывание имён». Главные трудности:

- **Устаревшие данные** — источник изменился, а кэш отдаёт старое. Решения: короткий TTL, явное удаление ключа при изменении, версии в ключах (`user:42:v7`), хеш содержимого в имени файла для статики.
- **Лавина промахов** (*cache stampede*) — популярный ключ истёк, и тысячи запросов одновременно идут в БД. Помогают блокировка на перестроение, ранний случайный перерасчёт и устаревшие ответы на время обновления (`stale-while-revalidate`).
- **Холодный старт** — после перезапуска кэш пуст, нагрузка на источник резко растёт.
- **Кэширование персональных данных** — ответ одного пользователя, ошибочно закэшированный общим кэшем, увидят другие; для таких ответов нужен `Cache-Control: private` или `no-store`.
- **Согласованность** между несколькими кэшами и экземплярами приложения — требует [распределённых](https://llmdocs.ru/wiki/distributed-systems.md) механизмов инвалидации.

Кэш — оптимизация, а не источник истины: система должна работать корректно (пусть и медленнее), если кэш пуст или недоступен.

## См. также

- [Redis](https://llmdocs.ru/wiki/redis.md)
- [CDN](https://llmdocs.ru/wiki/cdn.md)
- [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md)
- [HTTP](https://llmdocs.ru/wiki/http.md)

## Источники

1. [Hennessy, Patterson — Computer Architecture: A Quantitative Approach (6th ed.), ch. 2 Memory Hierarchy](https://www.elsevier.com/books/computer-architecture/hennessy/978-0-12-811905-1)
2. [RFC 9111 — HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111)
3. [MDN — HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching)
4. [Python — functools.lru_cache and functools.cache](https://docs.python.org/3/library/functools.html#functools.lru_cache)
5. [Redis — Key eviction](https://redis.io/docs/latest/develop/reference/eviction/)
6. [AWS — Caching best practices](https://aws.amazon.com/caching/best-practices/)
7. [Peter Norvig — Latency numbers every programmer should know](https://norvig.com/21-days.html#answers)
