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

Для чего нужен Memcached?

2.0 Middle🔥 251 комментариев
#Архитектура и паттерны#Базы данных (NoSQL)

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

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

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

Memcached: распределённый кэш в оперативной памяти

Memcached — это открытый, высокопроизводительный распределённый кэш в оперативной памяти (in-memory data store), предназначенный для ускорения веб-приложений. Он хранит данные в оперативной памяти в виде пар ключ-значение и обеспечивает быстрый доступ к часто используемым данным.

Основные характеристики

  • In-memory: данные хранятся в оперативной памяти (очень быстро, но теряются при перезагрузке)
  • Распределённый: может работать на нескольких серверах, образуя кластер
  • Простой: простой протокол, лёгкий в настройке
  • Быстрый: операции O(1) для get/set
  • LRU eviction: при нехватке памяти удаляет давно не используемые данные

Зачем нужен Memcached

1. Ускорение БД запросов

# БЕЗ кэша: каждый раз запрашиваем БД (медленно)
from django.views import View
from django.shortcuts import render
from .models import Product

class ProductListView(View):
    def get(self, request):
        # SELECT * FROM products WHERE category = ? (медленно!)
        products = Product.objects.filter(category="electronics")
        return render(request, "products.html", {"products": products})

# С КЭШЕМ: первый раз запрашиваем БД, потом берём из памяти
import memcache

mc = memcache.Client(["127.0.0.1:11211"])

class ProductListView(View):
    def get(self, request):
        # Проверяем кэш
        cache_key = "products:electronics"
        products = mc.get(cache_key)
        
        if products is None:
            # Кэша нет — запрашиваем БД
            products = Product.objects.filter(category="electronics")
            # Сохраняем в кэш на 1 час (3600 секунд)
            mc.set(cache_key, products, 3600)
        
        return render(request, "products.html", {"products": products})

2. Снижение нагрузки на БД

# Представь 10000 запросов в секунду
# БЕЗ кэша: все 10000 запросов идут в БД → БД падает
# С кэшем: 9900 запросов берут данные из памяти (быстро)
#           100 запросов идут в БД, остальные берут обновлённые данные

3. Ускорение сессий пользователей

# Вместо того, чтобы загружать данные сессии из БД каждый раз,
# храним их в Memcached
from django.contrib.sessions.backends.cache import SessionStore

# Django использует Memcached для хранения сессий
# CACHES = {
#     "default": {
#         "BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
#         "LOCATION": "127.0.0.1:11211",
#     }
# }

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

Клиент                 Memcached             БД
   |                       |                  |
   |--get("user:123")------>|                 |
   |                    (в памяти)            |
   |<-----data-returned------|
   |                       |                  |
   |--get("product:456")---->|                 |
   |                    (не в памяти)        |
   |                       |--query--------->
   |                       |<----results-----|
   |                       |--store in RAM---|
   |<-----data-returned-----|

Практический пример с Redis (альтернатива)

# Redis часто используется вместо Memcached (更мощный)
import redis

rc = redis.Redis(host="localhost", port=6379, db=0)

# Кэширование результатов дорогостоящей функции
def get_user_stats(user_id):
    cache_key = f"user_stats:{user_id}"
    
    # Проверяем кэш
    cached = rc.get(cache_key)
    if cached:
        return json.loads(cached)
    
    # Вычисляем дорогостоящие статистики
    stats = calculate_complex_stats(user_id)  # Медленная операция
    
    # Сохраняем в кэш на 1 час
    rc.setex(cache_key, 3600, json.dumps(stats))
    return stats

# Инвалидация кэша при обновлении данных
def update_user_profile(user_id, new_data):
    user = User.objects.get(id=user_id)
    user.update(**new_data)
    
    # Инвалидируем кэш
    rc.delete(f"user_stats:{user_id}")
    rc.delete(f"user_profile:{user_id}")

Сравнение: Memcached vs Redis

АспектMemcachedRedis
Тип данныхТолько строкиStrings, Lists, Sets, Hashes, Sorted Sets
ПерсистентностьНетДа (RDB, AOF)
РаспределённостьВстроенаТребует реализации
ПростотаОчень простойБолее сложный
ПроизводительностьОчень быстрыйБыстрый
TTL (время жизни)ДаДа
РепликацияНетДа (Sentinel, Cluster)

Когда использовать Memcached

Подходит для:

  • Кэширования результатов запросов
  • Хранения сессий
  • Кэширования HTML страниц (fragment caching)
  • Счётчиков
  • Простых пар ключ-значение

Не подходит для:

  • Персистентного хранилища (данные теряются)
  • Сложных структур данных (Lists, Sets)
  • Когда нужна высокая надёжность

Стратегии кэширования

# 1. Cache-Aside (Lazy Loading)
def get_product(product_id):
    # Сначала смотрим кэш, если нет — идём в БД
    data = cache.get(f"product:{product_id}")
    if not data:
        data = db.get_product(product_id)
        cache.set(f"product:{product_id}", data, 3600)
    return data

# 2. Write-Through (обновляем БД и кэш одновременно)
def update_product(product_id, new_data):
    db.update_product(product_id, new_data)
    cache.set(f"product:{product_id}", new_data)

# 3. Write-Behind (обновляем кэш, потом БД)
def update_product_async(product_id, new_data):
    cache.set(f"product:{product_id}", new_data)
    schedule_task(db.update_product, product_id, new_data)

Возможные проблемы

1. Cache Invalidation ("два самых сложных вещи в программировании")

# Проблема: как убедиться, что кэш актуален?
# Решение: устанавливать TTL (время жизни)
cache.set(key, data, ttl=3600)  # Кэш на час

2. Cache Stampede

# Проблема: когда кэш истекает, много запросов идёт в БД одновременно
# Решение: использовать probabilistic early expiration
import random
if random.random() < 0.1:  # 10% шанс
    refresh_cache_early()

3. Потеря данных

# Memcached может потерять данные при перезагрузке
# Решение: использовать Memcached для данных, которые можно перевычислить

Заключение

Memcached — это простой и эффективный инструмент для кэширования данных в памяти. Он идеален для снижения нагрузки на БД в высоконагруженных приложениях, но требует правильной стратегии инвалидации кэша и понимания его ограничений. Для более сложных сценариев часто используется Redis, который предоставляет больше возможностей.

Для чего нужен Memcached? | PrepBro