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

В чем разница между горячим и холодным кэшем?

2.0 Middle🔥 141 комментариев
#Архитектура и паттерны

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

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

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

Разница между горячим и холодным кэшем

Хотя эти термины не стандартизированы, в контексте кэширования и производительности они обозначают два принципиально разных состояния кэша, влияющих на скорость доступа к данным.

Холодный кэш (Cold Cache)

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

Характеристики:

  • Кэш пуст или не содержит требуемых данных
  • Запрос идёт в основное хранилище (БД, файловая система, внешний API)
  • Медленные ответы (время загрузки полное)
  • Высокая нагрузка на источник данных
import time
import functools

class CacheSystem:
    def __init__(self):
        self.cache = {}  # холодный кэш
        self.hits = 0
        self.misses = 0
    
    def expensive_operation(self, key):
        """Эмулирует медленную операцию (БД запрос)"""
        time.sleep(0.5)  # 500ms
        return f"Data for {key}"
    
    def get_data(self, key):
        if key in self.cache:
            self.hits += 1
            return self.cache[key]
        
        self.misses += 1  # Cold cache miss
        data = self.expensive_operation(key)
        self.cache[key] = data
        return data

# Пример работы
cache_sys = CacheSystem()

# Первое обращение - холодный кэш
start = time.time()
result1 = cache_sys.get_data("user_1")
time1 = time.time() - start
print(f"First call (cold cache): {time1:.2f}s")  # ~0.50s

# Второе обращение - горячий кэш
start = time.time()
result2 = cache_sys.get_data("user_1")
time2 = time.time() - start
print(f"Second call (hot cache): {time2:.4f}s")  # ~0.00s

print(f"Hits: {cache_sys.hits}, Misses: {cache_sys.misses}")

Проблемы:

  • Cold start problem — приложение медленно запускается
  • Cache stampede — множество одновременных запросов к источнику при пустом кэше
  • Spike в нагрузке на БД — при перезагрузке приложения

Горячий кэш (Hot Cache)

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

Характеристики:

  • Кэш содержит требуемые данные
  • Запросы обслуживаются из кэша
  • Быстрые ответы (миллисекунды)
  • Низкая нагрузка на источник данных
  • Высокий процент попаданий (hit rate)
# Продолжение примера выше - горячий кэш
print("\n=== Горячий кэш ===")
for _ in range(5):
    start = time.time()
    result = cache_sys.get_data("user_1")  # уже в кэше
    elapsed = time.time() - start
    print(f"Call from hot cache: {elapsed:.4f}s")  # ~0.00s

print(f"Hits: {cache_sys.hits}, Misses: {cache_sys.misses}")
print(f"Hit rate: {cache_sys.hits / (cache_sys.hits + cache_sys.misses) * 100:.1f}%")

Процесс переходов

# Демонстрация переходов между холодным и горячим кэшем

class AdvancedCache:
    def __init__(self, ttl=60):  # TTL - время жизни записи
        self.cache = {}
        self.timestamps = {}
        self.ttl = ttl
    
    def is_expired(self, key):
        if key not in self.timestamps:
            return True
        return time.time() - self.timestamps[key] > self.ttl
    
    def warm_up(self, data_list):
        """Предварительное заполнение кэша (warming up)"""
        for key, value in data_list:
            self.cache[key] = value
            self.timestamps[key] = time.time()
        print(f"Cache warmed up with {len(data_list)} items")
    
    def get_with_expiry(self, key):
        if key in self.cache and not self.is_expired(key):
            return self.cache[key]  # горячий кэш
        else:
            # Кэш истёк - переходим в холодное состояние
            return None

# Использование
cache = AdvancedCache(ttl=2)

# Холодный старт
print("\nCold start:")
print(cache.get_with_expiry("user_1"))  # None

# Прогрев кэша
cache.warm_up([
    ("user_1", {"name": "Alice"}),
    ("user_2", {"name": "Bob"}),
    ("user_3", {"name": "Charlie"}),
])

# Горячий кэш
print("\nHot cache:")
print(cache.get_with_expiry("user_1"))  # {name: Alice}

# Истечение TTL - переход в холодное состояние
print("\nWaiting for expiry...")
time.sleep(3)
print(cache.get_with_expiry("user_1"))  # None (cache expired)

Стратегии оптимизации

1. Cache Warming (Прогрев кэша)

def warm_cache():
    """Загрузить часто используемые данные при старте"""
    popular_items = fetch_popular_items_from_db()
    for item in popular_items:
        cache[item[id]] = item
    return len(popular_items)

# Вызвать при инициализации приложения
@app.on_event("startup")
async def startup():
    items_loaded = warm_cache()
    print(f"Warmed cache with {items_loaded} items")

2. Lazy Loading (Ленивая загрузка)

def get_user(user_id):
    # Загружаем по мере необходимости
    if user_id in cache:
        return cache[user_id]  # горячий
    user = db.fetch_user(user_id)  # холодный доступ
    cache[user_id] = user
    return user

3. TTL и Refresh (Истечение и обновление)

import redis
from datetime import timedelta

redis_client = redis.Redis()

def get_cached_data(key, fetch_func, ttl=300):
    # Попытка получить из горячего кэша
    cached = redis_client.get(key)
    if cached:
        return json.loads(cached)  # горячий
    
    # Холодный кэш - загружаем с источника
    data = fetch_func()
    redis_client.setex(key, ttl, json.dumps(data))
    return data

4. Preload и Background Refresh

import asyncio
from apscheduler.schedulers.asyncio import AsyncIOScheduler

scheduler = AsyncIOScheduler()

@scheduler.scheduled_job(interval, minutes=5)
async def refresh_hot_cache():
    """Периодически обновляем горячий кэш"""
    popular_items = await fetch_popular_items()
    for item in popular_items:
        cache[item[id]] = item
    print("Hot cache refreshed")

@app.on_event("startup")
async def startup():
    scheduler.start()

Метрики

class CacheMetrics:
    def __init__(self):
        self.hits = 0
        self.misses = 0
        self.evictions = 0
    
    def hit_rate(self):
        total = self.hits + self.misses
        if total == 0:
            return 0
        return (self.hits / total) * 100
    
    def report(self):
        return {
            "hits": self.hits,
            "misses": self.misses,
            "hit_rate": f"{self.hit_rate():.2f}%",
            "evictions": self.evictions,
            "cache_state": "hot" if self.hit_rate() > 80 else "cold"
        }

# Типичные значения:
# Холодный кэш: 0-20% hit rate
# Теплый кэш: 20-80% hit rate
# Горячий кэш: 80-99% hit rate

Итог

Холодный кэш — начальное состояние, когда данные нужно загружать из медленного источника. Горячий кэш — оптимальное состояние, когда все нужные данные уже в памяти. Цель архитектора — минимизировать время в холодном состоянии через стратегии прогрева, предварительной загрузки и правильного управления временем жизни данных в кэше. Хороший кэш должен поддерживать high hit rate (>80%) при минимальной памяти.

В чем разница между горячим и холодным кэшем? | PrepBro