JavaRush /Курси /Модуль 4: FastAPI /Як зменшити навантаження на сервери за допомогою кешуванн...

Як зменшити навантаження на сервери за допомогою кешування

Модуль 4: FastAPI
Рівень 9 , Лекція 7
Відкрита

Тепер настав час застосувати все, що ми вивчили, і розібратися, як саме кешування може зменшити навантаження на сервери. Ми зануримось у реальні сценарії оптимізації, щоб ваші додатки могли працювати швидко і стійко навіть при високому навантаженні.

Щоб зрозуміти, навіщо взагалі використовувати кешування для зниження навантаження на сервери, давайте невеликий вступ.

Уявіть, що у вас є API, який обробляє тисячі запитів на хвилину. Наприклад, ви ведете базу даних усіх кав'ярень у місті (де найкращий капучино, звісно). Кожного разу, коли користувач надсилає запит, ваш додаток звертається до бази даних, щоб дістати потрібну інформацію. При цьому:

  • Запити стають повільнішими. Звернення до бази даних потребують часу, особливо при складних запитах або великих обсягах даних.
  • Сервер починає задихатися. Чим більше запитів обробляється, тим більше ресурсів потрібно (CPU, RAM).
  • Зростає ймовірність відмови. Під високими навантаженнями сервер може перестати відповідати.

Навіщо тут Redis?

Справа в тому, що за допомогою Redis ви можете зберігати в пам'яті результати частих запитів, щоб потім не звертатися до важкої бази даних. Це як якщо ви зберігаєте свої улюблені жарти в голові, а не шукаєте їх у Google щоразу (так, це економить час).


Використання кешу для зниження навантаження

Тепер давайте розберемося, як саме Redis допомагає знизити навантаження на сервери. Почнемо з простого прикладу і поступово ускладнимо його.

Припустимо, ви розробляєте API для пошуку кав'ярень. Ось ваш endpoint:


@app.get("/coffee-shops")
async def get_coffee_shops(location: str):
    # 1. Виконуємо важкий запит до бази даних
    coffee_shops = database.query(f"SELECT * FROM coffee_shops WHERE location='{location}'")
    return {"data": coffee_shops}

Ваш сервер заходить у базу даних кожного разу, коли хтось запитує кав'ярні для певної локації. Це повільно. Давайте закешуємо результат:


import aioredis
from fastapi import FastAPI

app = FastAPI()
redis = await aioredis.from_url("redis://localhost")

@app.get("/coffee-shops")
async def get_coffee_shops(location: str):
    # 1. Перевіряємо, чи є дані в кеші
    cached_shops = await redis.get(location)
    if cached_shops:
        return {"data": cached_shops}

    # 2. Якщо даних немає, виконуємо важкий запит до бази даних
    coffee_shops = database.query(f"SELECT * FROM coffee_shops WHERE location='{location}'")

    # 3. Зберігаємо результат в Redis
    await redis.set(location, coffee_shops, ex=3600)  # Встановлюємо TTL на 1 годину

    return {"data": coffee_shops}

Тепер сервер спочатку перевіряє Redis. Якщо дані є, він дістає їх з пам'яті (супершвидко), а не робить запит до бази даних. Якщо даних немає (кеш "холодний"), він робить запит, а потім кешує результат для подальшого використання.


Зменшення навантаження на базу даних

Уявіть, що запити до вашого API обслуговують 10 000 користувачів. З Redis більша частина цих запитів обробляється прямо з кешу. Це означає:

  • Менше запитів до бази даних.
  • Менше використання пам'яті і процесорного часу сервера бази даних.
  • Прискорення часу відповіді для користувачів.

На практиці ви можете зменшити навантаження на базу даних до 90% (так, звучить як магія, але це реальність).


Які дані краще кешувати?

Кешувати має сенс дані, які:

  1. Часто запитуються.
  2. Змінюються рідко (або зміни можна легко відстежувати).

Наприклад:

  • Популярні товари в інтернет-магазині.
  • Географічні дані (наприклад, кав'ярні в певній локації).
  • Відповіді API з високою частотою запитів.

Вибір часу життя (TTL)

Не забувайте про TTL (Time to Live). Це час, протягом якого дані будуть зберігатися в кеші. Якщо дані застарівають, їх потрібно оновити. TTL допомагає автоматично видаляти старі дані.

Приклад з TTL:


await redis.set(location, coffee_shops, ex=3600)  # 1 година

Інвалідація кешу

Іноді дані в базі змінюються. Наприклад, відкрилась нова кав'ярня. Щоб користувачі не отримували застарілу інформацію, вам потрібно інвалідувати кеш — видалити або оновити старі дані.

Приклад:


# Під час додавання нової кав'ярні
@app.post("/coffee-shops")
async def add_coffee_shop(new_shop: dict):
    # Зберігаємо в базу даних
    database.insert("coffee_shops", new_shop)

    # Інвалідуємо кеш для локації
    location = new_shop["location"]
    await redis.delete(location)

Оптимізація навантаження за допомогою кешування

Тепер давайте розглянемо більш складний приклад, де ми використовуємо кеш для зменшення навантаження одразу на кілька компонентів системи.

Уявіть, що ваш додаток працює із зовнішнім API, щоб отримувати погодні дані. Зовнішній API повільний і дорогий (ви платите за кожен запит). Давайте закешуємо відповіді.

Приклад:


import requests

@app.get("/weather")
async def get_weather(location: str):
    # Спочатку перевіряємо кеш
    cached_weather = await redis.get(f"weather:{location}")
    if cached_weather:
        return {"data": cached_weather}

    # Якщо кешу немає, запитуємо дані з зовнішнього API
    response = requests.get(f"https://weather-api.com/{location}")
    weather_data = response.json()

    # Зберігаємо дані в кеш
    await redis.set(f"weather:{location}", weather_data, ex=600)  # 10 хвилин

    return {"data": weather_data}

Тепер замість того, щоб щоразу звертатися до зовнішнього API, сервер зберігає дані в Redis. Це знижує навантаження на ваш додаток і економить гроші.


Аналіз результатів

Після впровадження кешування варто провести аналіз, наскільки зменшилось навантаження на сервери. Один зі способів моніторингу — порівняння кількості запитів до Redis і до бази даних.

Інструменти моніторингу Redis:

  • Redis Monitoring
  • Використання вбудованої команди MONITOR.

Поради та кращі практики

  • Не намагайтеся кешувати все. Кешування даних з великою мінливістю може бути дорожчим за саму проблему.
  • Використовуйте унікальні ключі для кешу. Наприклад, f"user:{user_id}:profile".
  • Налаштовуйте TTL залежно від типу даних.
  • Подумайте про автоматичні механізми інвалідації кешу (наприклад, при зміні даних).
  • Моніторьте продуктивність Redis, щоб він сам не став вузьким місцем.

Тепер ви озброєні знаннями, як використовувати кешування для зменшення навантаження на сервери. У наступній лекції ми продовжимо досліджувати інші способи оптимізації і заглянемо ще глибше в можливості Redis!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ