JavaRush /Курси /Модуль 4: FastAPI /Видалення та керування даними кешу в Redis

Видалення та керування даними кешу в Redis

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

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

Одним із ключових аспектів кешування є керування часом життя записів у кеші. У Redis це реалізовано через механізм TTL (Time To Live), який визначає, скільки часу ключ існуватиме до його автоматичного видалення.

Приклад задання TTL для ключа:


import redis

# Підключення до Redis
r = redis.Redis(host='localhost', port=6379, db=0)

# Встановлення значення з часом життя 10 секунд
r.set('username', 'Alice', ex=10)

# Отримання значення до закінчення TTL
print(r.get('username'))  # b'Alice'

# Через 10 секунд ключ автоматично видалиться

Флаг ex задає час життя в секундах, а px — в мілісекундах.

Більшість кешуючих систем встановлюють TTL, щоб не накопичувалися застарілі дані і кеш залишався актуальним.


Політики витіснення даних

Redis підтримує різні політики витіснення даних, які активуються, якщо пам'ять закінчилась. Найпопулярніші політики:

  • noeviction: нічого не видаляється, при вичерпанні пам'яті сервер повертає помилку.
  • allkeys-lru: видаляються найменш нещодавно використані ключі (Least Recently Used).
  • volatile-lru: видаляються найменш нещодавно використані ключі з встановленим TTL.
  • allkeys-lfu: видаляються найменш часто використовувані ключі (Least Frequently Used).

Ці політики налаштовуються у конфігураційному файлі Redis (зазвичай redis.conf) через параметр maxmemory-policy. Наприклад:


maxmemory-policy allkeys-lru

Якщо хочете протестувати витіснення даних, використайте таку налаштування для запуску Redis:


redis-server --maxmemory 100mb --maxmemory-policy allkeys-lru

Видалення даних з кешу

Видалення конкретних ключів у Redis здійснюється командою DEL. Це можна зробити як для одного ключа, так і для кількох:


# Видалення одного ключа
r.delete('username')

# Видалення кількох ключів
r.delete('key1', 'key2', 'key3')

Але інколи потрібно видаляти дані, які відповідають певному шаблону. Для цього використовують комбінацію SCAN і DEL:


# Знайти й видалити ключі, що починаються з "user:"
keys = r.scan_iter('user:*')
for key in keys:
    r.delete(key)

Використовуйте SCAN замість KEYS, бо остання може дуже навантажувати сервер при великій кількості записів.

Для очищення всіх даних з Redis застосовують команду FLUSHDB (очищає поточну базу даних) або FLUSHALL (очищає всі бази даних):


# Повністю очистити поточну базу
r.flushdb()

# Повністю очистити всі бази Redis
r.flushall()

Будьте обережні! Ці команди видаляють всі дані без можливості відновлення.


Обробка застарілих даних

Інвалідизація — це процес видалення застарілих або змінених даних з кешу, щоб уникнути використання невірної інформації. Наприклад, уявімо, що ми кешуємо інформацію про товар:


# Кешуємо інформацію про товар
product_id = 42
product_data = {'name': 'Laptop', 'price': 1500}
r.set(f'product:{product_id}', json.dumps(product_data), ex=300)

Якщо ціна товару змінюється в базі даних, потрібно видалити кеш, щоб він не повертав застарілі дані:


# Видаляємо старий кеш товару
r.delete(f'product:{product_id}')

У складних системах це може бути автоматизовано за допомогою механізму подій або сигналів, які спрацьовують при зміні даних.

Підходи до інвалідизації кешу:

  1. Явне скидання кешу: кеш видаляють вручну при оновленні даних.
  2. Lazy Loading (ліниве завантаження): застарілі дані видаляються лише при наступному запиті.
  3. Time-based Expiration: дані автоматично видаляються після закінчення TTL.

Приклад використання явної інвалідизації в FastAPI:


from fastapi import FastAPI
import redis
import json

app = FastAPI()
r = redis.Redis(host='localhost', port=6379, db=0)

@app.put("/update_product/{product_id}")
async def update_product(product_id: int, name: str, price: float):
    # Оновлення даних у БД (припустимо)
    database_update(product_id, name, price)

    # Видалення застарілих даних у кеші
    r.delete(f'product:{product_id}')
    return {"message": "Product updated and cache invalidated"}

Використання TTL і LRU для керування

Щоб мінімізувати кількість застарілих даних і оптимізувати використання пам'яті:

  • Встановлюйте TTL для даних, які змінюються рідко, але потребують регулярного оновлення.
  • Налаштовуйте політику витіснення, наприклад, volatile-lru для ключів з TTL.

Приклад:


# Кешуємо з TTL
r.set('user_preferences', json.dumps({'theme': 'dark'}), ex=86400)

# Перевірка залишкового часу життя
ttl = r.ttl('user_preferences')
print(f"Remaining TTL: {ttl} seconds")

Практика: керування даними в складній системі

Припустімо, ми зберігаємо інформацію про користувачів у кеші з ключами user:{id}. Коли користувач оновлює свої дані, кеш повинен оновлюватися, щоб уникнути застарілої інформації.

Приклад коду:


@app.put("/update_user/{user_id}")
async def update_user(user_id: int, name: str):
    # Оновлюємо дані у БД
    update_user_in_db(user_id, name)

    # Інвалідуємо кеш
    r.delete(f'user:{user_id}')

    # Заново додаємо дані в кеш
    new_data = {"id": user_id, "name": name}
    r.set(f'user:{user_id}', json.dumps(new_data), ex=3600)
    return new_data

Механізми очищення: автоматизація

Якщо ручне очищення здається занадто складним, можна використати:

  • Періодичні задачі: запускати очищення кешу за розкладом через Celery.
  • Подієвий підхід: зв'язувати операції в БД з кешуванням через сигнали.

Приклад очищення:


# Celery завдання для автоматичного очищення
@app.task
def clear_expired_cache():
    keys = r.scan_iter()
    for key in keys:
        if r.ttl(key) == -1:  # Якщо у ключа немає TTL
            r.delete(key)

Підсумкове застосування знань

Тепер ви знаєте, як керувати даними в кеші — від видалення конкретного ключа до налаштування складних політик витіснення. У реальному житті грамотне керування кешем не лише підвищує продуктивність — воно рятує вас від головного болю через застарілі дані. А що може бути гірше, ніж користувач, який бачить у системі стару інформацію? Хіба що баг у п'ятницю ввечері!

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