Модуль 33

RabbitMQ у Docker

Це чудове завдання! Я готовий провести цей урок. Вмикаймо уяву, запускаємо термінал і — поїхали!


🎓 Урок: RabbitMQ у Docker — Як не "покласти" систему під навантаженням

Привіт, світе! 👋 Радий бачити вас на курсі. Сьогодні ми розберемо тему, яка відрізняє "код студента" від "архітектури сеньйора". Ми поговоримо про черги повідомлень, а саме — RabbitMQ, і запустимо це все у Docker.


1. 🔥 Вступ: Проблема та мотивація

Уявіть собі популярну кав’ярню в центрі міста зранку в понеділок. ☕️

Ви підходите до каси, замовляєте складний лате з кокосовим молоком. Що робить касир? 1. Він починає сам молоти каву? 2. Потім сам біжить доїти кокос? 3. І ви, і вся черга за вами чекаєте 10 хвилин, поки він це зробить?

Звісно, ні! Це було б катастрофою. Система б "лягла" після другого клієнта.

Натомість касир робить просту річ: він записує замовлення на чеку, клеїть його на спеціальну рейку і миттєво приймає наступного клієнта. А десь там, у глибині кухні, бариста (який навіть не бачить клієнта) бере цей чек і спокійно готує каву.

Риторичне запитання: А що, якби ваші програми працювали так само? Що, якби ваш вебсайт не змушував користувача чекати, поки згенерується важкий PDF-звіт або відправиться email, а просто казав: "Завдання прийнято, ми надішлемо результат пізніше"?

Ось тут на сцену виходить RabbitMQ. Це і є та сама "рейка" для чеків. А Docker нам потрібен для того, щоб ми цю "рейку" не будували вручну з дощок і цвяхів, а отримали готову, ідеальну конструкцію за одну команду.

Без розуміння черг ваші додатки будуть "гальмувати" при найменшому навантаженні. Давайте це виправимо!


2. 🧠 Теоретична база (Але без нудьги)

Давайте розкладемо все по поличках. RabbitMQ — це брокер повідомлень (Message Broker).

Як це працює "під капотом"?

Уявіть собі поштову скриньку 📮. 1. Ви кидаєте туди лист (повідомлення). 2. Ви не знаєте, коли саме листоноша його забере. 3. Ви не знаєте, яким маршрутом поїде фургон. 4. Але ви впевнені, що лист дійде до адресата.

У світі RabbitMQ є три головні дійові особи:

  1. Producer (Продюсер/Виробник): Той, хто відправляє повідомлення (наш касир).
  2. Queue (Черга): Буфер, де зберігаються повідомлення (рейка з чеками або поштова скринька). Вона живе всередині RabbitMQ.
  3. Consumer (Консьюмер/Споживач): Той, хто забирає повідомлення і обробляє їх (бариста).

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

  • RabbitMQ дозволяє системам спілкуватися асинхронно. Продюсер не чекає, поки Консьюмер закінчить роботу.
  • Docker дозволяє нам запустити RabbitMQ за секунди, не встановлюючи Erlang і купу бібліотек у вашу ОС.

🧩 Інтуїтивно (поки що):

Є ще така штука як Exchange (Обмінник). Це як розподільчий центр на пошті. Він вирішує, в яку саме чергу покласти лист. Але сьогодні ми будемо використовувати "дефолтний" обмінник — тобто кластимемо листи "прямо в руки".


3. 🧪 Приклади: Від "Hello World" до магії

Щоб побачити магію, нам не треба нічого встановлювати локально, крім Docker.

Крок 1: Запуск RabbitMQ (Те, чого ви чекали)

Відкрийте термінал. Ви, мабуть, очікуєте, що зараз ми будемо качати інсталятори? Ні. Одна команда:

docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management

Що тут відбулося? * -d: Запустити у фоні (detached). * -p 5672:5672: Порт для спілкування програм (Python, Java тощо). * -p 15672:15672: Важливо! Це веб-інтерфейс (Management Plugin). * rabbitmq:3-management: Ми беремо образ, де вже вбудована адмінка.

👉 Перевірка: Зайдіть у браузер за адресою http://localhost:15672. Логін: guest, Пароль: guest. Бачите графіки? Вітаю, у вас є свій поштовий сервіс!

Крок 2: Відправка листа (Python)

Уявімо, що це наш сайт приймає замовлення. Нам знадобиться бібліотека pika (стандарт для Python). (Якщо не встановлена: pip install pika).

Створимо файл sender.py:

import pika

# 1. Підключаємось до RabbitMQ (який крутиться в Docker на localhost)
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 2. Створюємо чергу 'hello', якщо її ще немає
channel.queue_declare(queue='hello')

# 3. Відправляємо повідомлення
channel.basic_publish(exchange='', routing_key='hello', body='Привіт, RabbitMQ!')
print(" [x] Відправлено 'Привіт, RabbitMQ!'")

connection.close()

Запустіть це: python sender.py. Тепер зазирніть у браузер (в адмінку), вкладка Queues. Ви побачите, що в черзі hello лежить 1 повідомлення. Воно чекає!

Крок 3: Отримання листа

Тепер ми — "бариста", який прийшов на роботу. Створимо receiver.py:

import pika, sys, os

def main():
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='hello')

    # Функція, яка викликається, коли приходить повідомлення
    def callback(ch, method, properties, body):
        print(f" [x] Отримано {body.decode()}")

    # Підписуємось на чергу
    channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)

    print(' [*] Чекаю на повідомлення. Натисніть CTRL+C для виходу')
    channel.start_consuming()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('Interrupted')
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)

Запустіть python receiver.py. Що ви бачите? Він миттєво "з'їв" повідомлення, яке ви відправили раніше.


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

Тепер ваша черга! Не бійтеся ламати — це ж Docker, у крайньому разі перезапустимо контейнер.

Завдання 1: Масштабування ("Ефект чорної п'ятниці") 1. Запустіть receiver.py в одному терміналі. 2. Запустіть ще один receiver.py у другому терміналі. 3. Тепер швидко запустіть sender.py 5-6 разів підряд (або зробіть цикл у коді). 4. Спостереження: Подивіться, як RabbitMQ розподіляє повідомлення між двома одержувачами. Це називається Round-robin. Він роздає задачі по колу: тобі, тобі, тобі...

Завдання 2: "Важка робота" Модифікуйте receiver.py. Додайте import time і всередині функції callback напишіть time.sleep(5). Це імітує, що обробка займає 5 секунд (наприклад, рендеринг відео). Відправте повідомлення. Подивіться, як споживач "завис", обробляючи його.

Завдання 3: The Killer Вбийте контейнер RabbitMQ (docker stop some-rabbit), поки у черзі є повідомлення (відправте, але не запускайте receiver). Запустіть контейнер знову (docker start some-rabbit). Перевірте чергу. Повідомлення зникли? Виклик: Знайдіть у документації, як зробити чергу durable (довговічною), щоб вона переживала перезавантаження брокера.

Завдання 4: Міні-кейс Уявіть, що ви робите систему реєстрації. * Напишіть скрипт, який генерує JSON: {"user": "alex", "email": "alex@example.com"} і кидає в чергу registration. * Напишіть воркер, який читає цей JSON і просто друкує: "Відправляю вітальний лист на alex@example.com...".


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

Як відрізнити новачка від профі в роботі з чергами?

🚫 Типова помилка новачка:

Використовувати RabbitMQ як базу даних. "Я покладу сюди дані, нехай полежать тиждень". Ні! RabbitMQ — це "гаряча картопля". Мета черги — бути порожньою. Якщо черга росте — значить, ваші консьюмери не справляються, і це проблема.

🧠 Як думає архітектор:

1. "Що, якщо мій воркер впаде під час роботи?" В прикладі вище ми використали auto_ack=True. Це означає: "RabbitMQ, як тільки ти віддав мені повідомлення — забудь про нього". Але якщо воркер впаде з помилкою до того, як обробить задачу, повідомлення зникне назавжди! Профі використовує auto_ack=False і відправляє підтвердження (ack) вручну тільки після успішної обробки.

2. Ідемпотентність (Страшне слово, проста суть). Іноді RabbitMQ може доставити одне повідомлення двічі (мережеві збої). Ваша система має бути готова до цього. Якщо ви двічі обробите команду "Зняти 100 грн", клієнт буде незадоволений. Профі завжди перевіряють: "Чи не робив я це завдання раніше?".


6. 🧩 Підсумок

Отже, що ми сьогодні зробили? 1. Ми зрозуміли, навіщо потрібні черги (асинхронність, розвантаження). 2. Ми запустили RabbitMQ у Docker однією командою (ніякого болю з інсталяцією). 3. Ми написали Producer та Consumer і змусили їх спілкуватися.

Тепер ви вмієте: ✅ Розв'язувати проблему "гальмування" інтерфейсу, виносячи важкі задачі у фон. ✅ Піднімати інфраструктуру обміну повідомленнями за 10 секунд.

🔜 Тизер наступного уроку: Сьогодні ми запускали все руками. Але що, як у нас є RabbitMQ, база даних, 3 мікросервіси на Python і один на Node.js? Запускати 6 команд в терміналі? О ні. На наступному уроці ми познайомимося з Docker Compose — диригентом для нашого оркестру контейнерів!

А поки що — спробуйте не "покласти" свою кав'ярню! Успіхів! 🚀