Для чего нужен Memcached?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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
| Аспект | Memcached | Redis |
|---|---|---|
| Тип данных | Только строки | 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, который предоставляет больше возможностей.