Skip to content

Instantly share code, notes, and snippets.

@Eugene-Fed
Created March 24, 2025 14:47
Show Gist options
  • Select an option

  • Save Eugene-Fed/e6a932c54406e8a48c369b657cc0105f to your computer and use it in GitHub Desktop.

Select an option

Save Eugene-Fed/e6a932c54406e8a48c369b657cc0105f to your computer and use it in GitHub Desktop.

Для интеграции Memcached в FastAPI можно использовать библиотеки вроде pymemcache (синхронный) или aiomcache (асинхронный). Вот подробное руководство:


1. Установка зависимостей

pip install fastapi pymemcache aiomcache

2. Базовая конфигурация

2.1 Синхронный клиент (pymemcache)

from pymemcache.client.base import Client
from fastapi import FastAPI

app = FastAPI()

# Подключение к Memcached
memcached_client = Client(("localhost", 11211))

2.2 Асинхронный клиент (aiomcache)

import aiomcache
from fastapi import FastAPI

app = FastAPI()

# Асинхронный клиент
async def get_memcached_client():
    return aiomcache.Client("localhost", 11211)

3. Примеры использования

3.1 Кэширование результатов

@app.get("/cache/{key}")
def get_cached_data(key: str):
    value = memcached_client.get(key)
    if value:
        return {"cached_value": value.decode()}
    else:
        # Имитация долгой операции
        result = f"Data for {key}"
        memcached_client.set(key, result, expire=300)  # TTL = 5 минут
        return {"result": result}

3.2 Асинхронный кэш

@app.get("/async-cache/{key}")
async def get_async_cache(key: str):
    client = await get_memcached_client()
    value = await client.get(key)
    if value:
        return {"cached_value": value.decode()}
    else:
        result = f"Data for {key}"
        await client.set(key, result, exptime=300)
        return {"result": result}

4. Продвинутые примеры

4.1 Кэширование сложных объектов

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float

@app.post("/cache-item/{item_id}")
def cache_item(item_id: str, item: Item):
    memcached_client.set(
        f"item:{item_id}",
        item.json(),  # Сериализация в JSON
        expire=300
    )
    return {"status": "cached"}

4.2 Удаление ключей

@app.delete("/cache/{key}")
def delete_cache(key: str):
    memcached_client.delete(key)
    return {"status": "deleted"}

5. Интеграция с FastAPI через Middleware

5.1 Автоматическое кэширование ответов

from fastapi import Request, Response
from pymemcache.client.base import Client

memcached_client = Client(("localhost", 11211))

@app.middleware("http")
async def cache_middleware(request: Request, call_next):
    response_key = f"cache:{request.url}"
    cached_response = memcached_client.get(response_key)
    
    if cached_response:
        return Response(content=cached_response, media_type="application/json")
    
    response = await call_next(request)
    
    if response.status_code == 200:
        memcached_client.set(response_key, response.body, expire=300)
    
    return response

6. Настройка через переменные окружения

import os
from pymemcache.client.base import Client

MEMCACHED_HOST = os.getenv("MEMCACHED_HOST", "localhost")
MEMCACHED_PORT = int(os.getenv("MEMCACHED_PORT", 11211))

memcached_client = Client((MEMCACHED_HOST, MEMCACHED_PORT))

7. Асинхронная работа с aiomcache

7.1 Пример асинхронного эндпоинта

import aiomcache
from fastapi import FastAPI, Depends

app = FastAPI()

async def get_async_client():
    return aiomcache.Client("localhost", 11211)

@app.get("/async/{key}")
async def get_async(key: str, client=Depends(get_async_client)):
    value = await client.get(key.encode())
    return {"value": value.decode() if value else "Not found"}

8. Интеграция с Docker

8.1 docker-compose.yml

version: '3.8'
services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - MEMCACHED_HOST=memcached
    depends_on:
      - memcached

  memcached:
    image: memcached:latest
    ports:
      - "11211:11211"

9. Пример полного приложения

9.1 main.py

from fastapi import FastAPI, Request
from pymemcache.client.base import Client
from pydantic import BaseModel

app = FastAPI()

memcached_client = Client(("localhost", 11211))

class Item(BaseModel):
    name: str
    price: float

@app.get("/items/{item_id}")
def get_item(item_id: str):
    cached_item = memcached_client.get(item_id)
    if cached_item:
        return {"item": cached_item.decode()}
    
    # Имитация БД-запроса
    item = {"id": item_id, "name": "Sample", "price": 9.99}
    memcached_client.set(item_id, str(item), expire=300)
    return item

@app.delete("/items/{item_id}")
def delete_item(item_id: str):
    memcached_client.delete(item_id)
    return {"status": "deleted"}

10. Бест-практисы

10.1 Генерация уникальных ключей

def generate_key(endpoint: str, **kwargs) -> str:
    return f"{endpoint}:{'_'.join([f'{k}_{v}' for k, v in kwargs.items()])}"

10.2 Обработка ошибок

try:
    value = memcached_client.get(key)
except Exception as e:
    print(f"Memcached error: {str(e)}")
    value = None

10.3 Сериализация данных

# Для сложных объектов
import json

def set_cached_data(key: str, data: dict, ttl: int = 300):
    memcached_client.set(key, json.dumps(data), expire=ttl)

11. Продакшен-настройки

11.1 Таймауты и переподключения

memcached_client = Client(
    ("localhost", 11211),
    connect_timeout=0.5,
    timeout=0.5,
    no_delay=True,
    ignore_exc=True
)

11.2 Асинхронный пул соединений

from aiomcache import Client
import asyncio

async def get_async_pool():
    return await Client.create_pool("localhost", 11211)

12. Кэширование с Pydantic моделями

from pydantic import BaseModel
import json

class Product(BaseModel):
    id: str
    name: str
    price: float

@app.get("/products/{product_id}", response_model=Product)
def get_product(product_id: str):
    cached = memcached_client.get(f"product:{product_id}")
    if cached:
        return Product.parse_raw(cached)
    
    # Имитация БД-запроса
    product = Product(id=product_id, name="Example", price=19.99)
    memcached_client.set(f"product:{product_id}", product.json(), expire=300)
    return product

13. Интеграция с SQLAlchemy

from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from fastapi import Depends

engine = create_engine("sqlite:///./test.db")

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
def get_user(user_id: str, db: Session = Depends(get_db)):
    cached_user = memcached_client.get(f"user:{user_id}")
    if cached_user:
        return json.loads(cached_user.decode())
    
    user = db.query(UserModel).filter(UserModel.id == user_id).first()
    memcached_client.set(f"user:{user_id}", json.dumps(user.__dict__), expire=300)
    return user

14. Очистка кэша

@app.post("/clear-cache/{prefix}")
def clear_cache(prefix: str):
    # Удаляет все ключи, начинающиеся с prefix
    keys = memcached_client.behaviors["binary"] = True
    keys = memcached_client.get_multi([f"{prefix}*"])
    for key in keys:
        memcached_client.delete(key)
    return {"status": "cache cleared"}

15. Пример .gitignore

# Memcached
memcached.sock

16. Библиотеки и инструменты

  • pymemcache: Официальный синхронный клиент.
  • aiomcache: Асинхронный клиент.
  • fastapi-memcached: Дополнительные инструменты для FastAPI (если есть).

17. Тестирование

from fastapi.testclient import TestClient
import pytest

def test_cache():
    client = TestClient(app)
    response = client.get("/items/123")
    assert response.status_code == 200
    assert memcached_client.get("items/123") is not None

18. Бест-практисы

  1. Используйте асинхронные клиенты (aiomcache) для асинхронных приложений.
  2. Ограничьте размер данных: Memcached хранит данные до 1 МБ.
  3. Используйте префиксы для ключей, чтобы избежать конфликтов.
  4. Настройте TTL согласно политике кэширования.
  5. Избегайте хранения больших объектов: Используйте сериализацию (JSON) для сложных структур.

19. Пример Dockerfile

FROM python:3.9-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

20. Итоговые рекомендации

Для работы с Memcached в FastAPI:

  1. Используйте aiomcache для асинхронных приложений.
  2. Настройте TTL для автоматической очистки устаревших данных.
  3. Сериализуйте данные (например, в JSON) перед сохранением.
  4. Интегрируйте через middleware для автоматического кэширования ответов.
  5. Используйте Docker для локального тестирования и деплоя.

Это ускорит работу приложения и снизит нагрузку на БД.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment