לדלג לתוכן

1.5 רדיס פתרון

פתרון תרגול – הוספת Redis למערכת TRIP


1. חיבור Redis למערכת

הרצה מקומית

docker run --name redis-test -p 6379:6379 -d redis:latest

חיבור בפייתון

import redis

redis_client = redis.Redis(
    host="localhost",
    port=6379,
    decode_responses=True
)

בדיקת חיבור:

redis_client.set("ping", "pong")
redis_client.get("ping")

2. Cache ל־GET Trip

עקרון

  • Redis נבדק ראשון

  • אם אין Cache → שליפה מה־DB (MongoDB / SQL)

  • שמירה ב־Redis עם TTL


Controller – שליפת טיול עם Cache

import json

TRIP_CACHE_TTL = 60

def get_trip_with_cache(trip_id: str):
    cache_key = f"trip:{trip_id}"

    cached_trip = redis_client.get(cache_key)
    if cached_trip:
        return json.loads(cached_trip)

    trip = get_trip_from_db(trip_id)
    if not trip:
        return None

    redis_client.setex(
        cache_key,
        TRIP_CACHE_TTL,
        json.dumps(trip)
    )

    return trip

Route

from fastapi import APIRouter, HTTPException

router = APIRouter()

@router.get("/trips/{trip_id}")
def get_trip(trip_id: str):
    trip = get_trip_with_cache(trip_id)
    if not trip:
        raise HTTPException(status_code=404, detail="Trip not found")
    return trip

3. Cache Invalidation

עדכון טיול

def update_trip(trip_id: str, data: dict):
    update_trip_in_db(trip_id, data)
    redis_client.delete(f"trip:{trip_id}")

מחיקת טיול

def delete_trip(trip_id: str):
    delete_trip_from_db(trip_id)
    redis_client.delete(f"trip:{trip_id}")

4. ספירת צפיות בטיול (Counters)

הגדלת מונה צפיות

def increase_trip_views(trip_id: str):
    redis_client.incr(f"trip:{trip_id}:views")

שילוב ב־GET:

def get_trip_with_cache(trip_id: str):
    increase_trip_views(trip_id)
    return get_trip_cached_logic(trip_id)

שליפת מספר צפיות

def get_trip_views(trip_id: str):
    return int(redis_client.get(f"trip:{trip_id}:views") or 0)

Route

@router.get("/trips/{trip_id}/views")
def trip_views(trip_id: str):
    return {"views": get_trip_views(trip_id)}

5. דירוג טיולים פופולריים (Sorted Set)

עדכון דירוג

def update_popular_trips(trip_id: str):
    redis_client.zincrby("popular_trips", 1, trip_id)

שילוב ב־GET:

increase_trip_views(trip_id)
update_popular_trips(trip_id)

שליפת 10 הטיולים הפופולריים

def get_top_trips(limit: int = 10):
    return redis_client.zrevrange(
        "popular_trips",
        0,
        limit - 1,
        withscores=True
    )

Route

@router.get("/trips/popular")
def popular_trips():
    return get_top_trips()

6. Rate Limiting ל־API

לוגיקה

  • מפתח לפי IP

  • TTL של דקה

  • חריגה → 429


Dependency

from fastapi import Request, HTTPException

RATE_LIMIT = 100
RATE_LIMIT_TTL = 60

def rate_limiter(request: Request):
    ip = request.client.host
    key = f"rate:{ip}"

    current = redis_client.incr(key)
    if current == 1:
        redis_client.expire(key, RATE_LIMIT_TTL)

    if current > RATE_LIMIT:
        raise HTTPException(
            status_code=429,
            detail="Too many requests"
        )

שימוש ב־Route

from fastapi import Depends

@router.get("/trips/{trip_id}")
def get_trip(
    trip_id: str,
    _: None = Depends(rate_limiter)
):
    return get_trip_with_cache(trip_id)

7. Redis כ־Session Store

יצירת Session

import uuid

def create_session(user_id: str):
    session_id = str(uuid.uuid4())
    redis_client.setex(
        f"session:{session_id}",
        3600,
        user_id
    )
    return session_id

בדיקת Session

def get_user_from_session(session_id: str):
    return redis_client.get(f"session:{session_id}")

8. Dependency ל־Redis

def get_redis():
    return redis_client

שימוש:

def some_controller(redis=Depends(get_redis)):
    redis.get("key")

9. דוקומנטציה

כל ה־endpoints:

  • מופיעים ב־/docs

  • כוללים:

    • 404 (לא נמצא)

    • 429 (Rate limit)

    • 200 (הצלחה)


10. סיכום ארכיטקטוני

  • Redis הוא שכבת ביצועים

  • Cache תמיד ניתן לאיבוד

  • DB הוא מקור האמת

  • TTL ו־Invalidation קריטיים

  • Redis מתאים:

    • Cache

    • Counters

    • Rate limiting

    • Sessions