Кэширование частых запросов — это, грубо говоря, как использование памяти "Ctrl+C" и "Ctrl+V". Вы берёте часто запрашиваемую информацию, сохраняете её в более лёгкодоступном месте и используете её, не прибегая каждый раз к тяжелым механизмам получения данных. Частые запросы, особенно к базе данных, могут значительно замедлить приложение. Кэширование решает эту проблему:
- Экономия ресурсов: данные извлекаются из памяти (Redis), а не базы данных.
- Снижение нагрузки на базу данных: уменьшение числа запросов к базе, что особенно важно для высоких нагрузок.
- Ускорение ответов: в большинстве случаев читать из Redis быстрее, чем из базы данных.
- Улучшение пользовательского опыта: никто не любит ждать.
Как выбрать, что кэшировать?
Не всё, что движется (или, в нашем случае, запрашивается), нужно кэшировать. Вот несколько советов для выбора:
- Частота запроса: если запрос выполняется часто, это первый кандидат для кэширования.
- Стабильность данных: данные, которые редко изменяются (например, курсы валют), идеально подходят для кэширования.
- Время выполнения запроса: если запрос медленный, его результаты стоит кэшировать, чтобы не "морозить" приложение.
Хорошие кандидаты для кэширования — это поисковые результаты, статистика, метаданные и т.п.
Реализация кэширования частых запросов в FastAPI
Давайте разберём, как кэшировать частые запросы к базе данных с использованием Redis.
Шаг 1: настройка Redis в FastAPI
from fastapi import FastAPI, Depends
import redis
import hashlib
# Настройка FastAPI
app = FastAPI()
# Настройка подключения к Redis
redis_client = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)
Маленький совет: чтобы не терять голову, проверяйте, что Redis-сервер запущен. Если он не запущен, FastAPI будет выглядеть как потерянный ребенок без своей любимой игрушки.
Шаг 2: пример хранилища данных
Допустим, у нас есть фейковая база данных со списком пользователей:
FAKE_DB = {
1: {"id": 1, "name": "John Doe", "email": "john.doe@example.com"},
2: {"id": 2, "name": "Jane Smith", "email": "jane.smith@example.com"},
3: {"id": 3, "name": "Alice Johnson", "email": "alice.johnson@example.com"}
}
Шаг 3: хэширование ключей для Redis
Чтобы запросы к кэшу были уникальны и предсказуемы, удобно использовать хэш в качестве ключей. Например:
def make_cache_key(function_name: str, *args):
key = f"{function_name}:{':'.join(map(str, args))}"
hashed_key = hashlib.sha256(key.encode()).hexdigest()
return hashed_key
Это полезно, когда у вас есть сложные запросы, требующие уникального кэширования.
Шаг 4: реализация кэширования данных
Теперь мы кэшируем запросы. Первым делом проверим, есть ли данные в кэше. Если да — вернём их. Если нет — возьмём из базы данных, сохраним в Redis и вернём клиенту.
@app.get("/users/{user_id}")
def get_user(user_id: int):
cache_key = make_cache_key("get_user", user_id)
# Проверяем кэш
cached_user = redis_client.get(cache_key)
if cached_user:
print("Получено из кэша")
return eval(cached_user) # Оценка строки в Python (осторожно!)
# Если в кэше нет, получаем из "базы"
user = FAKE_DB.get(user_id)
if user:
# Сохраняем данные в Redis с TTL 30 секунд
redis_client.setex(cache_key, 30, str(user))
return user
Шаг 5: тестирование
- Запустите приложение.
- В браузере или с помощью cURL откройте следующий URL:
http://127.0.0.1:8000/users/1. - Проверьте логи. Если всё работает как нужно, на первый запрос вы увидите
Получено из базы, а на последующие —Получено из кэша.
Инвалидирование данных
Данные в кэше могут устареть. Например, информация о пользователе изменилась, но в кэше мы всё ещё возвращаем старую копию.
Принципы инвалидирования:
- TTL: устанавливайте короткое время жизни (
setex), чтобы данные автоматически удалялись из кэша. - Ручная очистка: удаляйте кэшированные данные, если они изменились.
- Уникальность ключей: изменяйте ключи для новых данных.
Пример удаления устаревшего кэша:
Допустим, мы обновляем email пользователя. После обновления очистим его кэш:
@app.put("/users/{user_id}")
def update_user(user_id: int, email: str):
user = FAKE_DB.get(user_id)
if user:
user["email"] = email
# Инвалидируем кэш
cache_key = make_cache_key("get_user", user_id)
redis_client.delete(cache_key)
return {"msg": "User updated successfully"}
return {"msg": "User not found"}
Зачем это нужно в реальной жизни?
Представьте, у вас есть крупный e-commerce сайт. Запросы на главную страницу, фильтры и страницы товаров составляют 90% нагрузки на базу данных. Кэширование берет на себя обработку этих запросов, освобождая базу данных для критически важных операций — например, обработки заказов. Это не только повышает скорость сайта, но и делает его более отказоустойчивым: даже если база "упадёт", данные всё ещё можно извлечь из кэша.
Итоги
Мы реализовали кэширование частых запросов, проработали сценарии инвалидирования данных и проверили их интеграцию в FastAPI. Redis — это мощный инструмент, который, как волшебный носок с подарками, хранит данные для быстрого использования. Практикуйтесь, экспериментируйте и помните: кэширование — это не костыль, а стратегическая часть любой архитектуры.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ