Чому вам потрібна черга завдань

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

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

Цього тижня ми мали подію «це не відмова, це просто повільно», коли один з наших постачальників вийшов з ладу. Запити користувачів надходили, застрягали в очікуванні постачальника, уповільнювали всі наші веб-сервери, і нам було не до сміху.

Якби ця робота з постачальником виконувалась через чергу завдань — жодної проблеми. Черга могла б дочекатися, поки постачальник відновить роботу. І ви навіть не втрачаєте дані 🤘

Як працює сервер

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

pic

  1. Запит надходить, зберігається в пам'яті
  2. Сервер створює робочий процес
  3. Робочий процес виконує ваш код, запит — це вхідні дані
  4. Коли робочий процес завершує роботу, сервер відповідає на запит

Крок 2 — ось де важливі нюанси між різними стеком технологій.

Один процес для одного запиту

pic

У старому доброму LAMP (Linux, Apache, MySQL, PHP) моделі Apache створював абсолютно новий процес для виконання вашого PHP коду. Більш сучасне середовище (наприклад, gunicorn для Python або Ruby) може тримати пул робочих процесів і направляти запити до того, хто вільний. А серверless середовище створює нову машину для кожного запиту.

Використання «живих» робочих процесів допомагає з холодними стартами та робить вашу систему швидшою. Але якщо кількість доступних робочих процесів вичерпується, все починає уповільнюватися. І ви стаєте вразливими до витоків пам'яті.

Ваш код обробляє один запит за раз. Легко зрозуміти.

Один процес — багато запитів

pic

Альтернатива моделі з робочими процесами — це код додатка, який обробляє все це внутрішньо.

JavaScript, наприклад, використовує цикл подій (event loop), щоб мати можливість обробляти кілька запитів паралельно. Кожного разу, коли ви використовуєте async/await, зворотний виклик (callback) чи обіцянку (promise), JavaScript може призупинити виконання вашого коду і перейти до обробки інших запитів.

Це чудово підходить для обчислень, пов'язаних з введенням/виведенням, таких як веб-сервери. Поки ваш код чекає на API сторонніх постачальників чи читання файлів, він може почати обробляти інші запити.

Але як тільки ви заблокуєте процесор великими обчисленнями, увесь сервер повинен буде почекати. І якщо ви накопичите занадто багато відкладених обіцянок, серверу не вистачить часу для обробки нових запитів.

Все знову уповільнюється. Запити чекають в пам'яті, поки цикл подій не звільниться.

Ви також вразливі до витоків пам'яті. Один довготривалий процес 🙂

Результат теорії черг

Те, до чого я веду, — це теорія черг. Вам потрібно залишати запас у системі для обробки нових запитів.

Теорія черг — це ціла наука, і коледжний курс з цієї теми буквально розірвав мою голову. На практиці є 3 результати, які вам слід знати:

  1. Коли завантаженість наближається до 100%, час очікування наближається до нескінченності.
  2. Якщо завдання надходять швидше, ніж ви їх обробляєте, ваша черга буде зростати.
  3. Якщо черга переповнена, ви починаєте відкидати запити.

І ось що сталося з нами.

Постачальник виходить з ладу, робочі процеси серверів стають зайняті, запити продовжують надходити, і вся система ламається. Кожен сервер «утримує запити в пам'яті» до того моменту, поки ваш код не зможе їх обробити. Ось це і є черга! Вона може переповнитись. Або уповільнитися, якщо ваші робочі процеси зайняті.

Черги завдань рятують

Ваш код, з яким взаємодіють користувачі, має бути швидким. Чим швидше він буде, тим більше запитів ви зможете обробити.

У типовому веб-додатку під навантаженням більшість часу витрачається на те, щоб інші запити завершилися, щоб ваш зміг отримати свою чергу. Зі збільшенням кількості запитів збільшується й час очікування.

А якщо деякі запити стають дуже повільними через проблеми з постачальниками, неправильний запит до бази даних чи просто через велику кількість роботи, ваша вся система стане повільною. Не тільки цей запит.
🙃

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

pic

  1. Запит надходить, зберігається в пам'яті
  2. Сервер запускає ваш код
  3. Ваш код ставить повільні частини роботи в чергу завдань
  4. Код завершується, сервер відповідає
  5. Робочі процеси черги забирають роботу з черги та записують результати в базу даних, API сторонніх постачальників або будь-куди, де вам це потрібно

Як черга завдань створює надійність

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

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

Черги завдань використовують надійне зберігання для очікуючих завдань. Ви можете перезавантажити машину, не втративши незавершену роботу. Ви можете перевіряти очікуючі завдання, щоб бачити, що робить ваша система. Ви навіть можете дозволити завданням накопичуватись, поки ви запускаєте додаткові ресурси.

Черги завдань — це чудові буфери. Є піковий попит, але обмежені ресурси? Дайте черзі накопичуватися під час піку, а потім обробляйте її рівномірно. Це працює, якщо ви знаєте, що попит зменшиться, інакше спрацює правило 2.

Цей підхід може допомогти вам використовувати обмеження по кількості запитів до API. Додавайте роботу в чергу і налаштовуйте конфігурацію так, щоб не оброблялось більше 50 завдань за хвилину. Тоді ви можете підвищувати попит і не турбуватись про білінг.

І оскільки завдання надійні і виконуються незалежно, ви можете обробляти часткові та переривчасті відмови. Коли завдання не вдається, відправляйте його назад в чергу і спробуйте знову пізніше. Це вбудовано в будь-яку сучасну систему черг завдань.

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

Як це виглядає на практиці

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

Якби ми використовували чергу завдань, ми могли б дозволити завданням накопичуватися в черзі, а потім відтворити їх усі, коли постачальник повернеться. Користувачі б не помітили уповільнення, а ми б не втратили дані, просто були б затримки.

😉

Перекладено з: Why you need a task queue

Leave a Reply

Your email address will not be published. Required fields are marked *