Модуль 31

Redis у Python: redis-py

Ось готовий урок, створений спеціально для вас у стилі CS50. Вмикайте уяву, ми починаємо!


🎓 Тема уроку: Redis у Python (redis-py)

Або: Як подарувати вашій програмі надзвукову швидкість 🚀


1. 🔥 Вступ: Чому ваш код "гальмує" і як це виправити?

Уявіть, що ви працюєте баристою в найпопулярнішій кав’ярні міста.

До вас підходить клієнт і каже: "Мені як завжди". У вас є два варіанти дій: 1. Варіант А (Повільний): Ви йдете в архів, шукаєте папку цього клієнта серед тисяч інших, читаєте його історію замовлень, повертаєтесь і робите каву. Це займає 5 хвилин. 2. Варіант Б (Швидкий): Ви просто пам’ятаєте його обличчя і кричите: "Один лате на вівсяному!". Це займає 2 секунди.

Варіант А — це ваша звичайна база даних (PostgreSQL, MySQL). Вона надійна, вона все пам’ятає назавжди, але вона повільна, бо пише на жорсткий диск. Варіант Б — це Redis. Це ваша короткочасна пам'ять.

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

Без Redis (або іншого кешу) ваші сервери "впадуть" від навантаження саме тоді, коли прийдуть користувачі. Redis — це прошарок між вашим повільним диском і миттєвим процесором. Це швидкість.


2. 🧠 Теоретична база: Що там "під капотом"?

Давайте без зайвих академічних термінів.

Що таке Redis? Це, по суті, гігантський Python-словник (dict), який живе не на жорсткому диску, а в оперативній пам'яті (RAM). * Оскільки це RAM — доступ до даних майже миттєвий. * Оскільки це словник — ми працюємо за принципом Ключ (Key) — Значення (Value).

Як це працює? Ви кажете Redis: "Запам'ятай під ключем user:101 значення Davyd". Redis відповідає: "Ок". Коли ви спитаєте "Хто такий user:101?", Redis віддасть відповідь за мікросекунди.

❗ Що треба запам’ятати обов’язково:

  1. Дані в RAM летючі. Якщо вимкнути сервер з розетки, дані в Redis можуть зникнути (якщо не налаштувати збереження, але про це пізніше). Тому ми не зберігаємо там сімейні фотоальбоми, а лише те, що можна відновити.
  2. Типи даних. Redis вміє зберігати не лише рядки, а й списки, множини та хеш-таблиці.
  3. TTL (Time To Live). Це суперсила Redis. Ви можете сказати: "Зберігай цей запис рівно 60 секунд, а потім знищ його". Це ідеально для сесій, SMS-кодів або кешування цін.

Інтуїтивно: Redis — це стікери на моніторі. Швидко наліпив, швидко глянув, коли не треба — викинув. База даних — це сейф з документами в підвалі.


3. 🧪 Приклади: Від "Hello World" до реальності

Для роботи нам знадобиться бібліотека redis. Встановіть її: pip install redis (і вам потрібен запущений сервер Redis, локально або в Docker).

Приклад 1: Hello, Redis!

import redis

# 1. Підключаємось до Redis (localhost, стандартний порт 6379)
r = redis.Redis(host='localhost', port=6379, db=0)

# 2. Записуємо дані (set)
r.set('greeting', 'Привіт, світе!')

# 3. Читаємо дані (get)
value = r.get('greeting')

print(value) 
# Очікуєте побачити 'Привіт, світе!'? 
# А побачите: b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd1\x96\xd1\x82...' (bytes!)

Чому так? Redis зберігає все в байтах. Як виправити? Треба декодувати або налаштувати клієнт:

# decode_responses=True автоматично перетворить байти в рядки
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

r.set('greeting', 'Привіт, світе!')
print(r.get('greeting'))  # Виведе: Привіт, світе!

Приклад 2: Реальний кейс (Кешування "важкого" запиту)

Уявіть функцію, яка дуже довго рахує щось важливе.

import time

# Це наша повільна функція (імітація бази даних)
def get_expensive_data(user_id):
    print(f"⏳ Йду в базу даних за даними для {user_id}...")
    time.sleep(3)  # Імітуємо затримку 3 секунди
    return "Дуже важлива інформація"

def get_data_smart(user_id):
    # 1. Формуємо унікальний ключ
    key = f"user_data:{user_id}"

    # 2. Спершу питаємо Redis
    cached_value = r.get(key)

    if cached_value:
        print("🚀 Взяв дані з кешу (миттєво!)")
        return cached_value

    # 3. Якщо в кеші пусто, йдемо в "базу"
    real_value = get_expensive_data(user_id)

    # 4. Записуємо результат в Redis на 10 секунд (ex=10)
    r.set(key, real_value, ex=10)

    return real_value

# Перший запуск
print(get_data_smart(1)) 
# Результат: чекаємо 3 сек, пише "Йду в базу..."

# Другий запуск (одразу ж)
print(get_data_smart(1)) 
# Результат: миттєво! пише "Взяв дані з кешу"

Що тут відбулося? Ми зекономили 3 секунди життя користувача. А якщо користувачів мільйон? Ми зекономили 3 мільйони секунд процесорного часу!


4. 🛠 Практична частина

Час "забруднити руки" кодом. Виконайте ці завдання:

  1. 🔹 Базовий пін-понг: Підключіться до Redis. Створіть ключ language зі значенням Python. Зчитайте його і виведіть на екран. Переконайтеся, що виводиться рядок, а не байти.

  2. 🔹 Лічильник відвідувань: Redis вміє класно працювати з числами. Використайте метод r.incr('visits'). Запустіть скрипт 5 разів. Щоразу число має збільшуватись. Аналогія: це як турнікет у метро.

  3. 🔹 "Місія нездійсненна": Запишіть повідомлення, яке самознищиться через 5 секунд (ex=5). Напишіть цикл while, який намагається прочитати це повідомлення кожну секунду і друкує його. Подивіться, в який момент воно перетвориться на None.

  4. 🔹 Робота зі словниками (Hashes): Замість простих рядків, використайте hset та hgetall, щоб зберегти профіль студента (ім'я, курс, оцінка) під одним ключем student:1. Підказка: Це схоже на вкладений словник у Python.

  5. 🔹 Кейс: Обмеження спроб входу (Rate Limiter): Напишіть функцію login_attempt(ip_address).

    • Якщо з однієї IP адреси було більше 3 спроб за хвилину — повертати "Блокування!".
    • Використовуйте incr та expire.
    • Подумайте: Як зробити так, щоб лічильник скидався сам?

5. 💡 Мислення як у розробника

Як думає новачок:

"Я буду зберігати все в Redis, бо він швидкий! І базу даних видалю!"

Помилка: Redis дорогий (RAM коштує дорожче за диск) і дані можуть зникнути при перезавантаженні.

Як думає Senior-розробник:

"Ці дані часто запитують? Так. Чи критично, якщо ми втратимо ці дані за останні 5 хвилин? Ні. Окей, кладемо в Redis."

💡 Поради з "полів":

  1. Завжди давайте ключам зрозумілі назви. Не називайте ключ просто id. Називайте session:user:42 або product:15:price. Використовуйте двокрапку як роздільник — це стандарт.
  2. Не забувайте про TTL. Кеш, який ніколи не очищується — це смітник. Ставте час життя даним, які можуть застаріти.
  3. Атомарність. Операції в Redis атомарні. Якщо два користувачі одночасно зроблять incr, нічого не зламається, лічильник збільшиться рівно на 2. У звичайному файлі це викликало б хаос.

6. 🧩 Підсумок

Отже, що ми сьогодні зробили? 1. Зрозуміли, що Redis — це оперативна пам'ять для вашого проєкту. 2. Навчилися підключатися через redis-py і розібралися з байтами/рядками. 3. Реалізували кешування, яке прискорює програму в сотні разів. 4. Створили дані, які самознищуються.

Що ви тепер вмієте? Ви вмієте розвантажувати базу даних і робити так, щоб ваш сайт "літав", а не "повзав".

🤔 Тизер наступного уроку: Ми навчилися зберігати дані. Але що, як нам треба, щоб одна частина програми поставила задачу ("Відправити 1000 емейлів"), а інша — виконала її у фоні, не змушуючи користувача чекати? Наступного разу поговоримо про Черги задач (Task Queues) та Celery. Там Redis розкриється з зовсім іншого боку!

А поки — практикуйтесь! 💻