Від повільного до швидкого: кешування POST запитів у FastAPI за допомогою Redis

pic

Фото Isaac Maffeis на Unsplash

Хто сказав, що тільки GET-запити можуть користуватися перевагами кешування? Хоча розробники часто вважають POST-запити некешованими за замовчуванням, є одна таємниця: вони можуть бути такими ж швидкими та ефективними, як і GET-запити. Використовуючи FastAPI та Redis, ви можете реалізувати потужне кешування POST-запитів, яке змусить вас переосмислити все, що ви знали про шаблони кешування HTTP. Давайте розглянемо, як вийти за межі цих обмежень і значно покращити продуктивність вашого API.

Початок роботи

Перед тим як заглибитися у магію, підготуйте наше FastAPI-додаток і переконайтеся, що Docker встановлений на вашому комп'ютері.

Слідуйте інструкціям для Docker та Docker Compose.

Весь код доступний тут:

[

GitHub - anotherbuginthecode/medium-fastapi-redis: Посібник по використанню FastAPI та Redis для кешування POST-запитів

Посібник по використанню FastAPI та Redis для кешування POST-запитів - anotherbuginthecode/medium-fastapi-redis

github.com

](https://github.com/anotherbuginthecode/medium-fastapi-redis?source=post_page-----0219c7fa454f--------------------------------)

Створення Dockerized FastAPI та Redis налаштувань

Dockerfile для FastAPI: створіть Dockerfile для вашого FastAPI додатку:

# Використовувати офіційний базовий образ Python  
FROM --platform=linux/x86_64 python:3.11-slim-buster  
ENV PYTHONBUFFERED=1 \  
 TZ=Europe/Rome \  
 LOG_LEVEL=INFO  
RUN apt-get update -y  
RUN apt-get install -y gcc g++ build-essential unzip dos2unix  
RUN apt-get install -y libpq-dev  
RUN apt-get update && apt-get install -y libcurl4-openssl-dev libssl-dev  
RUN pip install --upgrade pip  
# Встановлюємо робочий каталог всередині контейнера  
WORKDIR /app  
# Копіюємо файл вимог до робочого каталогу  
COPY requirements.txt .  
# Встановлюємо залежності додатку  
RUN pip install wheel pybind11  
RUN pip install --no-cache-dir -r requirements.txt  

# Копіюємо код додатку до робочого каталогу  
COPY . .  

# Відкриваємо порт, на якому буде працювати FastAPI  
EXPOSE 8000  
# Встановлюємо команду для запуску додатку  
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt: переконайтеся, що у вашому файлі requirements.txt є FastAPI та Redis

fastapi  
uvicorn  
redis  
pydantic  
sqlalchemy  
psycopg2-binary  
jinja2==3.0.3  
jinjasql==0.1.8

Docker Compose файл: створіть файл docker-compose.yml для налаштування контейнерів FastAPI та Redis:

version: "3.8"  

services:  
 redis:  
 container_name: redis  
 image: redis:7.0  

 redis-ui: # для наявності візуального UI для керування кешем redis  
 container_name: redis-ui  
 image: redislabs/redisinsight:1.14.0  
 ports:  
 - 8001:8001  
 depends_on:  
 - redis  

 db:  
 image: postgres  
 container_name: db  
 ports:  
 - "5432:5432"  
 environment:  
 POSTGRES_USER: postgres  
 POSTGRES_PASSWORD: postgres  

 api:  
 build: .  
 command: "uvicorn src.app:app --host 0.0.0.0 --port 8000 --reload"  
 ports:  
 - "8000:8000"  
 volumes:  
 - ./src:/app/src  
 depends_on:  
 - redis  
 - db

Щоб запустити контейнери, виконайте команду:

docker-compose up -d --build  
#if you are using the last version of docker  
docker compose up -d --build

Розуміння кешування POST-запитів

Кешування POST-запитів може здатися контрінтуїтивним, оскільки POST-запити зазвичай змінюють стан сервера. Однак для ідемпотентних POST-запитів — тих, що дають однаковий результат за однаковим вхідним даним — кешування може значно покращити продуктивність.

Ідея виникла під час розробки інформаційної панелі з динамічними фільтрами для обробки даних, що вимагають важкої обробки. Для оптимізації продуктивності нам потрібно було кешувати фільтри, надіслані через POST-запит. Так, я знаю — використання GET-запиту з параметрами запиту було б «правильним» і простішим вибором.
pic

Фото Isaac Maffeis на Unsplash

Хто сказав, що тільки GET-запити можуть користуватися перевагами кешування? Хоча розробники часто вважають POST-запити некешованими за замовчуванням, є одна таємниця: вони можуть бути такими ж швидкими та ефективними, як і GET-запити. Використовуючи FastAPI та Redis, ви можете реалізувати потужне кешування POST-запитів, яке змусить вас переосмислити все, що ви знали про шаблони кешування HTTP. Давайте розглянемо, як вийти за межі цих обмежень і значно покращити продуктивність вашого API.

Початок роботи

Перед тим як заглибитися у магію, підготуйте наше FastAPI-додаток і переконайтеся, що Docker встановлений на вашому комп'ютері.

Слідуйте інструкціям для Docker та Docker Compose.

Весь код доступний тут:

[

GitHub - anotherbuginthecode/medium-fastapi-redis: Посібник по використанню FastAPI та Redis для кешування POST-запитів

Посібник по використанню FastAPI та Redis для кешування POST-запитів - anotherbuginthecode/medium-fastapi-redis

github.com

](https://github.com/anotherbuginthecode/medium-fastapi-redis?source=post_page-----0219c7fa454f--------------------------------)

Створення Dockerized FastAPI та Redis налаштувань

Dockerfile для FastAPI: створіть Dockerfile для вашого FastAPI додатку:

# Використовувати офіційний базовий образ Python  
FROM --platform=linux/x86_64 python:3.11-slim-buster  
ENV PYTHONBUFFERED=1 \  
 TZ=Europe/Rome \  
 LOG_LEVEL=INFO  
RUN apt-get update -y  
RUN apt-get install -y gcc g++ build-essential unzip dos2unix  
RUN apt-get install -y libpq-dev  
RUN apt-get update && apt-get install -y libcurl4-openssl-dev libssl-dev  
RUN pip install --upgrade pip  
# Встановлюємо робочий каталог всередині контейнера  
WORKDIR /app  
# Копіюємо файл вимог до робочого каталогу  
COPY requirements.txt .  
# Встановлюємо залежності додатку  
RUN pip install wheel pybind11  
RUN pip install --no-cache-dir -r requirements.txt  

# Копіюємо код додатку до робочого каталогу  
COPY . .  

# Відкриваємо порт, на якому буде працювати FastAPI  
EXPOSE 8000  
# Встановлюємо команду для запуску додатку  
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt: переконайтеся, що у вашому файлі requirements.txt є FastAPI та Redis

fastapi  
uvicorn  
redis  
pydantic  
sqlalchemy  
psycopg2-binary  
jinja2==3.0.3  
jinjasql==0.1.8

Docker Compose файл: створіть файл docker-compose.yml для налаштування контейнерів FastAPI та Redis:

version: "3.8"  

services:  
 redis:  
 container_name: redis  
 image: redis:7.0  

 redis-ui: # для наявності візуального UI для керування кешем redis  
 container_name: redis-ui  
 image: redislabs/redisinsight:1.14.0  
 ports:  
 - 8001:8001  
 depends_on:  
 - redis  

 db:  
 image: postgres  
 container_name: db  
 ports:  
 - "5432:5432"  
 environment:  
 POSTGRES_USER: postgres  
 POSTGRES_PASSWORD: postgres  

 api:  
 build: .  
 command: "uvicorn src.app:app --host 0.0.0.0 --port 8000 --reload"  
 ports:  
 - "8000:8000"  
 volumes:  
 - ./src:/app/src  
 depends_on:  
 - redis  
 - db

Щоб запустити контейнери, виконайте команду:

docker-compose up -d --build  
#if you are using the last version of docker  
docker compose up -d --build

Розуміння кешування POST-запитів

Кешування POST-запитів може здатися контрінтуїтивним, оскільки POST-запити зазвичай змінюють стан сервера. Однак для ідемпотентних POST-запитів — тих, що дають однаковий результат за однаковим вхідним даним — кешування може значно покращити продуктивність.

Ідея виникла під час розробки інформаційної панелі з динамічними фільтрами для обробки даних, що вимагають важкої обробки. Для оптимізації продуктивності нам потрібно було кешувати фільтри, надіслані через POST-запит. Так, я знаю — використання GET-запиту з параметрами запиту було б «правильним» і простішим вибором.
Це корисно, якщо ви хочете мати більше контролю та аналізувати найбільш поширені комбінації, щоб надати стратегії для оптимізації застосунку.

// приклад payload  
{  
 "start_date": "2022-06-04",  
 "end_date": "2023-06-04",  
 "typology": "arrival"  
}  

// не захешований ключ:/data?start_date=2022-06-04&end_date=2023-06-04&typology=arrival

Інтеграція Redis з нашим кінцевим пунктом

from fastapi import FastAPI, Request, Depends  
from pydantic import BaseModel  
import json  
from .service import get_total_flights  
from .database import RedisWrapper, get_db  
from enum import Enum  

app = FastAPI()  
redis_wrapper = RedisWrapper()  

class FlightTypology(str, Enum):  
 departure = "departure"  
 arrival = "arrival"  

class BaseRequestSchema(BaseModel):  
 start_date: str  
 end_date: str  
 airport_codes: list[str] | None = None  
 typology: FlightTypology = FlightTypology.departure  

 class Config:  
 use_enum_values = True  

@app.post("/data")  
async def handle_post(data: BaseRequestSchema, db=Depends(get_db)):  
 cache_key = redis_wrapper.create_cache_key(data.model_dump())  
 not_hashed_cache_key = redis_wrapper.convert_payload_to_query_params(  
 endpoint="/data", payload=data.model_dump()  
 )  

 print("Не захешований ключ кешу: ", not_hashed_cache_key)  

 cached_response = redis_wrapper.get_from_cache(cache_key)  
 if cached_response:  
 return json.loads(cached_response)  

 response_data = get_total_flights(  
 db=db,  
 params=data.model_dump(),  
 )  
 redis_wrapper.store_in_cache(cache_key, json.dumps(response_data))  

 return response_data

Коли ми викликаємо наш POST-запит, метод handle_post перевіряє, чи існує ключ, згенерований методом redis_wrapper.create_cache_key(data.model_dump()), у Redis. Якщо так, він повертає кешований результат. В іншому випадку, він використовує згенерований ключ і вихідні дані з бази даних для збереження в Redis.

Давайте подивимося, як це працює

pic

Не кешований результат зайняв 14 мс

Додаток зайняв 14 мс для повернення результату, і якщо ми виконаємо той самий запит знову, це займе 7 мс, тому що результат вже кешовано в Redis.

pic

Кешований результат зайняв 7 мс

Перевірте Redis UI за адресою http://localhost:8001, щоб побачити ваші кешовані результати — кожен захешований запит payload і відповідне обчислене значення.

pic

Виведення, кешоване в Redis з використанням захешованого payload як ключа

Висновки

Вітаємо! Ви щойно розблокували потужний спосіб кешувати POST-запити — те, що багато розробників вважають неможливим. Тепер ви не тільки створили систему, яка робить ваш API швидшим і ефективнішим, але й навчилися мислити поза межами традиційних шаблонів кешування HTTP.

Експериментуйте з цим шаблоном у ваших проектах.
Чи то складна аналітика, важкі обчислення, чи операції з великими даними, тепер у вас є новий інструмент у вашому арсеналі для оптимізації.

Щасливого кешування!

Дякуємо, що стали частиною нашої спільноти

Перш ніж піти:

Перекладено з: From Slow to Fast: Caching POST Requests in FastAPI Using Redis

Leave a Reply

Your email address will not be published. Required fields are marked *