← Назад к вопросам

Где реализуется кэшируемость?

2.0 Middle🔥 91 комментариев
#Архитектура систем

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Где реализуется кэшируемость

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

Уровни реализации кэширования

**1. Уровень браузера (Client-side)

Где реализуется: На клиентской машине пользователя в браузере

Механизмы:

a) HTTP кэш браузера

Сервер отправляет заголовки:
Cache-Control: max-age=3600     # кэшировать 1 час
ETag: "abc123"                  # идентификатор версии
Last-Modified: Mon, 28 Mar 2024

Браузер:
1. Сохраняет ответ локально
2. Следующий запрос на этот же URL
3. Проверяет, не истёк ли max-age
4. Да → возвращает из кэша (не идёт на сервер)
5. Нет → идёт на сервер с If-None-Match: abc123
6. Сервер: "не менялось" (304 Not Modified)
7. Браузер переиспользует старый кэш

Управление:

Cache-Control: public              # любой может кэшировать
Cache-Control: private             # только браузер
Cache-Control: no-cache            # всегда проверять у сервера
Cache-Control: max-age=3600        # кэшировать 3600 секунд
Cache-Control: must-revalidate     # не использовать, если истёк

b) LocalStorage / SessionStorage

// Сохраняем в браузере
localStorage.setItem('user_profile', JSON.stringify({name: 'John'}))

// При следующем посещении
const profile = localStorage.getItem('user_profile')
if (profile) {
  // используем кэшированные данные
  // не делаем API запрос
}

c) Service Workers

Service Worker — это скрипт, который работает в фоне
Может перехватывать сетевые запросы
Кэшировать ответы
Отдавать с диска, если сеть недоступна (offline-first)

Где используется:

  • Static assets (CSS, JS, изображения)
  • Часто запрашиваемые API ответы
  • Progressive Web Apps (PWA)

**2. Уровень CDN (Content Delivery Network)

Где реализуется: На серверах, расположенных географически близко к пользователю

Как работает:

Европа: CDN сервер в берлине        ← user1 (быстро, 10ms)
        ↓
    Кэшируемый контент
        ↓
Америка: CDN сервер в нью-йорке     ← user2 (быстро, 30ms)
        ↑
   Оригинальный сервер (происхождение) в сан-франциско

Примеры CDN:

  • Cloudflare
  • Akamai
  • AWS CloudFront
  • Fastly

Кэшируемый контент:

  • Статические файлы (JS, CSS, images)
  • API ответы (если marked as cacheable)
  • HTML (при условии, что он не слишком динамичный)

Управление:

Kэширование на CDN настраивается через Cache-Control заголовки:
Cache-Control: public, max-age=86400  # кэшировать 1 день на CDN

**3. Уровень прокси и шлюзов

Где реализуется: На корпоративных прокси, API шлюзах, обратных прокси (reverse proxy)

Примеры:

a) HTTP Reverse Proxy (Nginx, HAProxy)

User → Nginx (reverse proxy with cache) → Backend server
           ↓
    Кэширует GET /api/users/42
    При следующем запросе отдаёт из кэша
    Не заходит на backend (разгружает его)

b) API шлюз (API Gateway)

Клиент → API Gateway (+ кэш) → Microservices

API Gateway может:
- Кэшировать ответы микросервисов
- Управлять TTL для разных endpoints
- Инвалидировать кэш при изменении данных

Где используется:

  • Высоконагруженные endpoints
  • Public API
  • Микросервисные архитектуры

**4. Уровень приложения (Application layer)

Где реализуется: Непосредственно в коде приложения

a) In-Memory кэш

# Python + Flask
from functools import lru_cache

@lru_cache(maxsize=128)
def get_user(user_id):
    return db.query(User).filter(User.id == user_id).first()

# Второй вызов с тем же user_id использует кэш (очень быстро)

Примеры фреймворков:

  • Python: functools.lru_cache, Django cache framework
  • JavaScript: Node.js memory-cache
  • Java: Caffeine, Guava

b) Кэширование результатов функций

# Кэшируем вычислительно сложное вычисление
@cache.cached(timeout=3600, key_prefix='expensive_calc')
def calculate_stats(month):
    # Сложные вычисления...
    return result

# При следующем вызове с тем же month → возвращает из кэша

c) ORM уровень

# SQLAlchemy
from sqlalchemy.orm import Session

# Query кэшируется ORM
user = db.query(User).options(cache_ok=True).get(42)

Где используется:

  • Защита БД от множественных идентичных запросов
  • Мемоизация результатов сложных вычислений
  • Временные результаты (пока в памяти)

**5. Уровень In-Memory хранилища (Redis, Memcached)

Где реализуется: В выделенных KV хранилищах

Архитектура:

Запрос → Приложение → Проверяет Redis
                      ↓ miss
                   PostgreSQL → сохраняет в Redis → ответ
                   ↓ hit
              возвращает из Redis (очень быстро)

Практический пример:

# Python + Redis
import redis

rc = redis.Redis()

def get_user(user_id):
    # Проверяем кэш
    cached = rc.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    # Кэша нет → запрашиваем из БД
    user = db.get(User, user_id)
    
    # Сохраняем в кэш на 1 час
    rc.setex(f"user:{user_id}", 3600, json.dumps(user))
    
    return user

Управление TTL:

rediis.setex(key, 3600, value)    # кэшировать 1 час
redis.set(key, value)              # кэшировать до ручного удаления
redis.delete(key)                  # инвалидировать кэш

**6. Уровень базы данных (Database)

Где реализуется: Внутри самой БД

a) Query cache (устаревший подход)

-- MySQL старые версии кэшировали результаты запросов
SELECT * FROM users WHERE id = 42
→ результат кэшируется

-- Теперь этот подход почти не используется
-- PostgreSQL никогда его не имела

b) Index кэширование

Индексы кэшируются в буфере БД (Buffer Pool)
Поиск по индексу очень быстр
Индекс на часто ищущемся поле = кэширование

c) Connection pooling

Пулинг переиспользует соединения
Не создаёт новое соединение для каждого запроса
= экономия ресурсов = лучшая производительность

**7. Уровень файловой системы и ОС

Где реализуется: На уровне операционной системы

Buffer cache:

ОС кэширует часто читаемые файлы в памяти
Второй доступ к файлу — из памяти (очень быстро)
Третий доступ — также из памяти

Типы кэширования по источнику

По источнику данных:

УровеньИспользованиеПример
БраузерStatic assets, API ответыCSS, JS, картинки
CDNGlobal content deliveryКартинки, видео, статические файлы
HTTP LayerReverse proxy кэшированиеNginx, Cloudflare
App LayerМемоизация, функцииLRU cache, декораторы
Redis/MemcachedHot data, сессииUser data, sessions, queues
DatabaseIndex cache, буферИндексы, часто читаемые данные

Инвалидация кэша (важно!)

Проблема: Кэш может устаревать

Решения:

1. Time-based (TTL)

Кэш автоматически истекает через N секунд
Просто, но данные могут быть неактуальными

2. Event-based (инвалидация при изменении)

def update_user(user_id, data):
    # Обновляем в БД
    db.update(User, user_id, data)
    
    # Инвалидируем кэш
    redis.delete(f"user:{user_id}")
    
    # При следующем запросе — переобновится из БД

3. Tag-based

Тегируем кэш: cache.tag('user:42')
При изменении пользователя инвалидируем все с тегом 'user:42'
Удобно для сложных зависимостей

Практические рекомендации

Используй кэширование, когда:

  • ✅ Данные часто читаются
  • ✅ Данные редко обновляются
  • ✅ Операция дорогая (БД запрос, вычисления)
  • Инвалидация просто реализуется

НЕ используй кэширование, когда:

  • ❌ Данные часто меняются (race conditions)
  • Консистентность критична (финансовые данные)
  • Размер данных огромный (не влезет в память)
  • Сложная инвалидация

Резюме

Кэшируемость реализуется на 7+ уровнях — от браузера до файловой системы. Каждый уровень имеет свой назначение: браузер кэширует static assets, CDN раздаёт global, Redis кэширует hot data, БД кэширует индексы. Правильное использование кэширования может дать 10x-100x ускорение, но требует продуманной инвалидации для сохранения консистентности.