Ось готовий урок, створений спеціально для тебе у стилі CS50 та David Malan. Уяви, що ми зараз у великій аудиторії, я ходжу сценою, активно жестикулюю, а ти сидиш у першому ряду.
Поїхали! 🚀
🎓 Урок: Redis Lists — Опановуємо Черги та Стеки
Привіт, друзі! 👋
1. 🔥 Вступ: Хаос чи Порядок?
Уявіть собі ранок понеділка. Ви заходите в кав’ярню, де роблять найкращу каву в місті. Там черга.
Що було б, якби бариста обслуговував не того, хто прийшов першим, а того, хто зайшов останнім? Хаос. Бунт. Кава на підлозі.
Або уявіть свій браузер. Ви клікаєте по посиланнях, заходите все глибше в інтернет. Потім натискаєте кнопку "Назад". Куди ви потрапляєте? На найпершу сторінку, яку відкрили вранці? Ні! Ви повертаєтесь на попередню.
Питання до вас: Чому в кав’ярні один порядок обслуговування, а в кнопці "Назад" — абсолютно протилежний?
Тому що для різних задач потрібні різні структури даних.
Сьогодні ми поговоримо про Lists (Списки) у Redis. Але ми не будемо просто вчити команди. Ми навчимося будувати дві фундаментальні архітектурні конструкції, на яких тримається весь сучасний веб: 1. Черги (Queues) — основа фонових задач (відправка пошти, обробка відео). 2. Стеки (Stacks) — основа історії дій (Undo/Redo).
Без цього ваш сервер захлинеться від навантаження. З цим — він працюватиме як швейцарський годинник. Готові розібратися, як це працює?
2. 🧠 Теоретична база: Що "під капотом"?
У Redis тип даних List — це не зовсім той масив (Array), до якого ви звикли в JavaScript чи Python.
❗️ Запам’ятайте головне: Redis List — це Linked List (Зв’язний список).
Що це означає простими словами? Уявіть масив як книжкову полицю. Щоб вставити книгу в середину, вам треба посунути всі інші книги. Це довго і важко. А зв’язний список — це як ланцюг людей, що тримаються за руки. Щоб додати нову людину на початок або в кінець, вам не треба рухати всіх. Просто берете за руку крайнього. Це миттєво!
Саме тому вставка на початок або кінець у Redis займає час O(1) (супершвидко), навіть якщо у списку мільйон елементів.
Дві головні моделі поведінки:
-
FIFO (First In, First Out) — "Першим зайшов, першим вийшов".
- Це Черга (Queue).
- Як труба: в один кінець пхаємо, з іншого вилітає.
- Аналогія: Черга за кавою ☕️.
-
LIFO (Last In, First Out) — "Останнім зайшов, першим вийшов".
- Це Стек (Stack).
- Як стопка тарілок: ви кладете тарілку зверху і берете теж зверху.
- Аналогія: Обойма пістолета або кнопка "Назад" у браузері 🥞.
Ключові команди (логіка):
* LPUSH (Left Push) — додати зліва (на початок).
* RPUSH (Right Push) — додати справа (в кінець).
* LPOP (Left Pop) — забрати зліва.
* RPOP (Right Pop) — забрати справа.
3. 🧪 Приклади: Від простого до реального
Давайте перейдемо до консолі redis-cli.
Приклад 1: Стек (Stack) — "Історія браузера"
Ми хочемо реалізувати кнопку "Назад". Ми будемо додавати сторінки і забирати останню додану.
❓ Як думаєте: Які команди нам треба поєднати? (Підказка: вхід і вихід з одного боку).
# 1. Ви відвідали Google
RPUSH history "google.com"
# (integer) 1
# 2. Потім пішли на YouTube
RPUSH history "youtube.com"
# (integer) 2
# 3. Потім на GitHub
RPUSH history "github.com"
# (integer) 3
# Давайте подивимось на історію (0 -1 означає "все від початку до кінця")
LRANGE history 0 -1
# 1) "google.com"
# 2) "youtube.com"
# 3) "github.com"
Тепер натискаємо "Назад". Ми маємо отримати github.com.
RPOP history
# "github.com"
Бачите? Останній, хто зайшов, вийшов першим (LIFO).
Приклад 2: Черга (Queue) — "Ticket System"
Уявіть службу підтримки. Заявки мають оброблятися в порядку надходження.
❓ Логіка: Додаємо з одного боку, забираємо з іншого.
# Клієнти створюють заявки (додаємо зліва)
LPUSH tickets "Problem with login"
LPUSH tickets "Payment failed"
LPUSH tickets "Website is slow"
# Подивимось чергу
LRANGE tickets 0 -1
# 1) "Website is slow" <-- Цей прийшов останнім, він зліва (Head)
# 2) "Payment failed"
# 3) "Problem with login" <-- Цей прийшов першим, він справа (Tail)
Тепер менеджер бере задачу. Яку він має взяти? Ту, що справа (Problem with login).
RPOP tickets
# "Problem with login"
Вуаля! Справедливість відновлено (FIFO).
Приклад 3: Blocking Pop (Магія реального часу)
Уявіть, що черга порожня. Менеджер постійно оновлює сторінку (робить RPOP), отримує (nil), знову RPOP... Це спалює ресурси процесора даремно!
У Redis є команда BRPOP (Blocking Right Pop). Вона каже: "Redis, якщо список порожній, почекай, поки там щось з'явиться, і ТІЛЬКИ ТОДІ віддай мені".
# Список порожній.
BRPOP jobs 5
# Redis "зависне" на 5 секунд, чекаючи на дані.
# Якщо в іншому вікні хтось зробить LPUSH jobs "work", ви миттєво отримаєте результат.
Це основа асинхронних воркерів.
4. 🛠 Практична частина
Час розім'яти пальці! Відкрийте термінал і виконайте ці завдання.
🔹 Завдання 1: Розігрів
Створіть список todolist. Додайте туди 3 задачі. Видаліть середню (подумайте, чи це зручно в Redis?). Очистіть весь список.
🔹 Завдання 2: "Ctrl+Z" (Стек)
Ви пишете текстовий редактор.
1. Зробіть RPUSH actions "typed_hello".
2. Зробіть RPUSH actions "bold_text".
3. Користувач натиснув Ctrl+Z (Undo). Яку команду виконати, щоб повернути останню дію? Перевірте, що залишилось у списку.
🔹 Завдання 3: Принтер (Черга) У офісі один принтер. 1. Менеджер відправив "Report.pdf". 2. Бухгалтер відправив "Salary.xls". 3. Стажер відправив "Meme.jpg". Запишіть це в Redis так, щоб "Report.pdf" надрукувався першим, а "Meme.jpg" — останнім. Симулюйте друк (видалення зі списку).
🔹 Завдання 4: Реальний кейс (Message Broker)
Уявіть, що у вас є два термінали (або вкладки).
* Термінал 1 (Споживач): Запустіть команду, яка чекає повідомлення в списку messages (використайте блокуючу команду!).
* Термінал 2 (Виробник): Відправте повідомлення в messages.
* Подивіться, що станеться в Терміналі 1.
🔹 Завдання 5: Питання "на засипку"
Що станеться, якщо я спробую зробити LPOP з ключа, який не існує? Redis видасть помилку чи щось інше? Перевірте.
5. 💡 Мислення як у розробника
Як відрізнити новачка від профі, коли мова йде про Redis Lists?
❌ Помилка новачка:
Використовувати List як масив для доступу по індексу.
Команда LINDEX mylist 500000 (дай мені 500-тисячний елемент) — це дуже повільно. Redis доведеться "пробігти" ланцюжком через 500 тисяч елементів.
Якщо вам треба швидкий доступ до конкретних елементів — використовуйте Hashes або Sorted Sets.
✅ Як думає профі:
"Мені потрібен буфер".
Профі знає, що Lists ідеальні для часових серій (останні 10 логів) або черг задач.
Він використовує команду LTRIM, щоб список не ріс нескінченно.
Порада: Якщо ви робите стрічку новин (timeline), ви можете додавати нові пости через
LPUSH, а потім робитиLTRIM mylist 0 99. Так у вас в Redis завжди зберігаються тільки останні 100 постів. Це супер-ефективно по пам'яті!
6. 🧩 Підсумок
Отже, що ми сьогодні забрали з собою?
- Redis List — це зв’язний список, а не масив. Вставка по краях — миттєва ($O(1)$).
- Queue (Черга): Вхід з одного боку, вихід з іншого (FIFO). Ідеально для фонових задач.
- Stack (Стек): Вхід і вихід з одного боку (LIFO). Ідеально для історії дій.
- Blocking Operations:
BRPOPдозволяє чекати події, не навантажуючи процесор.
Тепер ви вмієте не просто зберігати дані, а керувати потоком виконання вашої програми. Ви можете створити свій міні-аналог RabbitMQ або чергу для відправки email-ів.
🤔 А що далі? У списках все добре, але є проблема: там можуть бути дублікати. Що, як нам треба зберігати список унікальних відвідувачів сайту за сьогодні? Список не підійде, бо один юзер може зайти 10 разів. Для цього нам знадобляться Redis Sets (Множини). Але це вже історія для наступного разу.
А поки — практикуйтесь і не переповнюйте свій стек! 👋