Cum să implementezi caching pentru un API Python cu Redis
In this tutorial, you'll learn about Cum să implementezi caching pentru un API Python cu Redis. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Caching-ul reduce timpul de răspuns și încărcarea serverului prin stocarea temporară a rezultatelor frecvent accesate. În acest ghid vei învăța cum să implementezi Caching pentru API-ul tău Python cu Redis, cache in-memory și HTTP cache headers.
Problema
Endpoint-urile API lente suprasolicită baza de date și oferă o experiență proastă utilizatorilor. Fiecare request repetat execută aceleași operații costisitoare, iar timpul de răspuns crește odată cu numărul de utilizatori.
Soluția Rapidă
1. Cache in-memory simplu
from functools import lru_cache
import time
@lru_cache(maxsize=128)
def get_produse_din_db():
"""Simulează un query lent la baza de date"""
time.sleep(2) # simulare întârziere
return [{"id": 1, "nume": "Laptop", "pret": 3500}]
@app.get("/produse")
def lista_produse():
return get_produse_din_db()
Primul request durează 2 secunde, următoarele sunt instantanee.
2. Cache cu Redis
pip install redis
import redis
import json
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
def get_or_set_cache(key, ttl=60):
"""Preia din cache sau calculează și stochează"""
def decorator(func):
async def wrapper(*args, **kwargs):
cache_key = f"{key}:{hash(str(args))}:{hash(str(kwargs))}"
cached = r.get(cache_key)
if cached:
return json.loads(cached)
result = await func(*args, **kwargs) if asyncio.iscoroutinefunction(func) else func(*args, **kwargs)
r.setex(cache_key, ttl, json.dumps(result, default=str))
return result
return wrapper
return decorator
@app.get("/produse")
@get_or_set_cache("produse", ttl=300)
def lista_produse():
# query costisitor
return [{"id": 1, "nume": "Laptop", "pret": 3500}]
3. HTTP Cache Headers
from fastapi.responses import JSONResponse
@app.get("/produse")
def lista_produse():
response = JSONResponse(
content=[{"id": 1, "nume": "Laptop"}]
)
response.headers["Cache-Control"] = "public, max-age=300"
response.headers["ETag"] = '"abc123"'
return response
Clientul și proxy-urile intermediare pot cache-ui răspunsul timp de 5 minute.
4. Invalidare cache la modificare
@app.post("/produse")
def creeaza_produs(p: Produs):
# salvează în baza de date
r.delete("produse:lista") # invalidează cache-ul
return {"id": 1, **p.model_dump()}
@app.put("/produse/{id}")
def actualizeaza_produs(id: int, p: Produs):
r.delete(f"produse:{id}")
r.delete("produse:lista")
return {"id": id, **p.model_dump()}
5. Cache cu Flask-Caching
pip install flask-caching
from flask import Flask
from flask_caching import Cache
app = Flask(__name__)
cache = Cache(app, config={
"CACHE_TYPE": "RedisCache",
"CACHE_REDIS_URL": "redis://localhost:6379/0",
"CACHE_DEFAULT_TIMEOUT": 300
})
@app.route("/produse")
@cache.cached(timeout=60)
def lista_produse():
return jsonify([{"id": 1, "nume": "Laptop"}])
Prevenție
- Setează TTL-uri realiste -- prea lung = date învechite, prea scurt = cache ineficient
- Invalidează cache-ul la modificări (CREATE, UPDATE, DELETE)
- Nu cache-ui date specifice utilizatorului fără identificator în cheie
- Monitorizează memoria Redis -- un cache prea mare consumă RAM
Greșeli Comune
- Cache fără invalidare -- utilizatorii văd date învechite mult timp după actualizare
- TTL prea lung pentru date volatile -- prețurile și stocurile trebuie actualizate frecvent
- Cache pe endpoint-uri de autentificare -- nu cache-ui răspunsuri care conțin token-uri
- Chei de cache fără prefix -- conflicte între diferite endpoint-uri
- Serializarea obiectelor complexe -- obiectele cu date nu se serializează automat în JSON
Exercițiu Practic
Implementează un API cu Caching Redis pentru un catalog de produse. Folosește TTL de 5 minute pentru listă și invalidare la crearea unui produs nou. Măsoară timpul de răspuns cu și fără cache.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro