Перейти до вмісту
Пошук в
  • Детальніше...
Шукати результати, які ...
Шукати результати в ...

Система очередей на Opencart (RabbitMQ)


ozzzi

2 314 перегляди

Я хочу затронуть тему очередей, которые используются повсеместно в интернет-проектах, но в Opencart данная тема особо не освещена. 

 

Представьте, что вам нужно прямо сейчас сделать выгрузку для какого-то маркетаплейса, вот только в выгрузке у вас, например, 50к товаров. Крон у вас работает раз в сутки, а менеджер магазина не подключится по ssh и не будет запускать консольный скрипт выгрузки. В подобной ситуации вам поможет система очередей.


Очереди - это не конкретная технология, а только принцип. В самом примитивном виде у нас есть издатель и подписчик (producer и worker). Издатель добавляет в очередь данные, по сути инициирует выполнение какого-то действия. А воркер непосредственно выполняет нужную нам работу. Между ними присутствует обменник, который хранит сообщения и распределяет их между воркерами. При этом мы можем использовать несколько воркеров (обработчиков) для одной задачи. 

 

queue.thumb.jpeg.8ae1cc166e5617a0a76ae434795249da.jpeg


Где можно использовать очереди

 

1. Асинхронное (фоновое) выполнение задач.
Допустим, что при оформлении заказа мы отправляем письма о новом заказе через внешний SMTP-сервер, админу кидаем уведомление в телеграм, а также экспортируем данные о заказе в CRM. 

 

Какие проблемы нас поджидают:

  • синхронное выполнение каждого процесса - пользователь будет ждать, пока отработает последовательно каждый из процессов
  • зависимость от внешних сервисов - они вполне могут работать нестабильно и все это время клиент будет видеть экран загрузки, вместо быстрого оформления заказа.

 

Вместо этого мы создаем три отдельных очереди (для email, телеграма и CRM) и просто кидаем в них сообщения. Пользователь успешно оформляет заказ, а в это время процессы отправки писем и уведомлений выполняются параллельно в фоне. 

Также можно: генерировать выгрузки в маркетплейсы по запросу пользователя, делать импорт/экспорт товаров, строить карты сайта, отчеты и т.д.


2. Имитация многопоточности. 
PHP "из коробки" однопоточный, но с помощью очередей можно сделать несколько обработчиков одной задачи.

 

Примеры:

  • Импорт товаров - у нас есть исходный эксель-файл с товарами. Распарсить файл и получить данные можно довольно быстро, а вот импорт данных потребует больших ресурсов, т.к. нужно выполнять вставку данных во множество таблиц. 

 

Исходя из этого разбиваем процесс импорта на два этапа:

  1.  на первом этапе парсим эксель файл и в результате парсинга каждой строки получаем результирующий набор данных, нужный для создания товара. Этот набор данных мы кидаем в очередь для импорта. 
  2. создаем обработчик, который будет заниматься только импортом готовых данных. При этом мы можем запустить одновременно 5 таких обработчиков (или сколько позволят ваши ресурсы) и система очередей будет распределять задачи по импорту товаров между данными обработчиками. В итоге вместо построчного импорта товаров мы получаем 5 параллельных обработчиков импорта.

 

Данную технику можно применить для парсинга товаров. 


От теории перейдем к практике. 


Система очередей на RabbitMQ

Выше я уже писал, что система очередей - это лишь архитектурный принцип и он может быть реализован с помощью множества технологий: крон и база данных, хранилище типа Redis и т.д., но я выбрал в качестве примера специалированное ПО RabbitMQ. Кролик содержит множество возможностей: гибкую маршрутизацию, масштабируемость, хранилище сообщений и т.д. 

 

Я использую Docker в качестве среды для локальной разработки, поэтому покажу, как установить RabbitMQ именно в этой среде. Про Docker я писал в этой статье: https://opencartforum.com/blogs/entry/383-zapusk-i-otladka-opencart-s-pomoschyu-docker-i-xdebug/

 

Цитата

Установка в Ubuntu/Debian: https://www.rabbitmq.com/install-debian.html
Установка для Windows: https://www.rabbitmq.com/install-windows.html

 

Установка RabbitMQ с помощью docker compose

1. В docker-compose.yml добавляем сервис:

 

rabbitmq:
    image: rabbitmq:3-management-alpine
    hostname: my-rabbit
    volumes:
      - ./rabbitmq/etc/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
      - ./rabbitmq/data:/var/lib/rabbitmq/mnesia/rabbit@my-rabbit
      - ./rabbitmq/logs:/var/log/rabbitmq/log
    ports:
      - 5672:5672
      - 15672:15672

 

2. В корневой директории Docker-проекта создаем папку rabbitmq и в ней создаем три папки: data, etc, logs для хранилища данных, конфигов и логов. В папке rabbitmq/etc создаем файл конфига rabbitmq.conf с содержимым:

 

loopback_users.guest = true
listeners.tcp.default = 5672
management.listener.port = 15672
management.listener.ssl = false

 

Далее как обычно билдим все в Docker для установки нового сервиса и запускаем контейнеры: 

 

docker-compose up -d --build

 

Для администрирования RabbitMQ поставляется с панелью, которая будет доступна по адресу: http://localhost:15672. В данной панели можно смотреть, какие очереди выполняются, получить сообщения, очистить очереди т.д. 

 

rabbitmq-panel.thumb.jpg.1b367cc8237f7cafb3abdcd918338e3b.jpg

 

Пароль и логин для доступа: guest / guest. Естественно, на рабочем сервере нужно удалить гостевого пользователя и добавить нового админа.


Использование RabbitMQ c Opencart

 

Написал простую библиотеку https://github.com/ozzzi/opencart-rabbitmq

 

Для ее работы нужно:

 

1. Установить зависимость:

 

composer require php-amqplib/php-amqplib

В библиотеке предполагается, что папка vendor будет лежать на уровень выше, чем корневая директория opencart.

 

2. Добавить в config.php конфиг RabbitMQ:

 

define('RABBITMQ_HOST', 'host');
define('RABBITMQ_PORT', '5672');
define('RABBITMQ_USER', 'guest');
define('RABBITMQ_PASS', 'guest');

 

Если речь идет о исполнении в докер-контейнере, то в качестве хоста нужно указать айпи контейнера (читаем предыдущую статью о докере).

 

Затем в опенкарте можем использовать библиотеку:

 

$this->load->library('queue');
$this->queue->addTask('queueName', ['some' => 'data']);

 

Первый параметр в методе addTask - имя очереди, а второй параметр (опциональный) - данные, которые нужно передать в воркер.

 

Цитата

Воркеры или обработчики - это независимые скрипты, которые мало того, что могут быть написаны на разных языках, они также могут располагаться на других серверах. Т.к. с опенкартом их напрямую ничего не связывает, то и писать их можно в удобном для вас виде. Для примеров я буду использовать мини-приложения с PSR-4 автозагрузчиком из composer.

 


Примеры

 

Далее я приведу примеры использования очередей для отправки почты, импорта товаров из Excel, и парсинга сайтов.

 

1. Отправка email

Полный код: https://github.com/ozzzi/email_service

 

В коде Opencart-а меняем родной код отправки email-ов на:

 

$this->load->library('queue');
$this->queue->addTask('email', ['data' => 'examlpe_data']);

 

Т.е. мы добавили в очередь email данные для обработки: кому, от кого и что отсылаем.

За обработку данной очереди отвечает воркер: cli/email_notify.php. Вы должны сами реализовать получение конфигов для SMTP-сервера.

 

В панели управления RabbitMQ можно увидеть, что во вкладке очередей появилась новая очередь и одно сообщение. Чтобы очередь его отработала, воркер cli/email_notify.php должен быть запущен. Для примера мы запустим его вручную внутри контейнера, а в конце я объясню, как сделать запуск автоматическим.

 

Смотрим имена контейнеров:

 

docker ps

 

Нас интересует, контейнер с PHP-FPM. Чтобы войти в него выполняем:

 

docker exec -it container_name bash

 

Далее переходим в папку cli и стандартно запускаем скрипт:

 

php email_notify.php

 

Если все прошло успешно, в панели кроля вы увидите, что очередь email очистилась. Значит сообщение ушло получателю.

 


2. Импорт товаров из Excel

Полный код: https://github.com/ozzzi/excel_import_worker

 

В админской части вам нужно реализовать загрузку файла, передать конфиг настроек полей и подключить загрузчик композер: '/vendor/autoload.php'

 

Затем реализовываем наш загрузчик (producer):

use App\Service\ExcelParser;

$file = 'price.xlsx';

$setting = [
    'category' => 'B',
    'name' => 'C',
    'model' => 'D',
    'price' => 'G',
    'quantity' => 'H',
    'manufacturer' => 'F',
    'description' => 'M',
];

$this->load->library('queue');

$excelService = new ExcelParser($setting, $file);

foreach ($excelService->parse() as $product) {
    $this->queue->addTask('import', ['product' => $product]);
}

 

В итоге после чтения каждой строки мы добавляем в очередь import объект с данными товара. Чтобы обработать все сообщение из очереди "импорт" запускаем воркер: cli/product_import.php (App\Service\ProductImport - вам нужно реализовать самим :) ). Чтобы процесс пошел "бодрей", можно запустить параллельно несколько воркеров product_import.php.

 

excel.thumb.jpeg.e88c4dea807a15fc7da2500998fc154b.jpeg

 

 

3. Парсер сайта в несколько потоков

Полный код: https://github.com/ozzzi/html_parser_worker

 

Цитата

Информация выложена в учебных целях. Не нужно убивать чужие сайты своими парсерами!

 

Для примера возьмем первый попавшийся магазин стройматериалов (ссылка в коде) и спарсим все товары из категории "Сухие смеси". Разделим процесс парсинга на два этапа:

 

  1. Получение списка ссылок на карточки товаров. За один запрос мы можем получить все ссылки на товары для первой страницы. Если страниц пагинации в категории 5 и в среднем на загрузку страницы уходит 1 секунда, то за 5 секунд мы получим все ссылки на товары в данной категории. 
  2. Парсинг страниц товаров в несколько потоков. Т.к. каждая карточка товара загружается условную секунду, то данный процесс нам нужно распараллелить, запустив несколько воркеров.

 

Запускаем скрипт cli/parser_category.php, который будет отправлять в очередь parse_product ссылки на товары.

 

Затем запустим несколько воркеров cli/import_worker.php. В результате ProductParser возвращает сущность Товар, которая импортируется с помощью сервиса ProductImport, с которым вы уже знаете, что делать. 


Надеюсь, что вы поняли, как применять очереди в таком простом виде.

 

Теперь расскажу, как запускать воркеры как демоны в автоматическом режиме (чтобы они работали постоянно и перезапускались сами вместе с системой). Один из способов - supervisor

 

Установка для Debian\Ubuntu стандартная:

 

apt-get install supervisor


Добавляем конфиг для запуска конкретного скрипта. Например, добавим конфиг для запуска воркера в виде двух процессов:


Создаем файл:

/etc/supervisor/conf.d/worker.conf
[program:worker]
command=php /path/to/script.php
stdout_logfile=/var/log/worker.log
autostart=true
autorestart=true
user=www-data
stopsignal=KILL
process_name=%(program_name)s_%(process_num)02d
numprocs=2

 

Перезагружаем supervisor: 

 

service supervisor restart


Если вам скучно, обязательно попробуйте очереди. :)

  • +1 19

18 коментарів


Recommended Comments

9 минут назад, pmshirshov сказал:

Ничего не понятно! Но очень интересно!

Для вас, как для владельца магазина, это позволит сделать "отзывчивый" магазин для клиента и удобный для менеджеров: выгрузить, импортировать что-то тяжелое можно будет нажатием условной кнопки.

 

Но есть и минус: все это кто-то должен поддерживать, а первый попавшийся opencart-программист не факт, что захочет лезть в эти дебри.

Надіслати
4 минуты назад, nikifalex сказал:

"За обработку данной очереди отвечает воркер: cli/email_notify.php. Вы должны сами реализовать получение конфигов для SMTP-сервера."

 

вот это меня смущает. Т.е. этот код уже Вне движка opencart?

 

и ладно. smtp

но вот это

"App\Service\ProductImport - вам нужно реализовать самим"

уже совсем никуда не годится.

 

А так то интересно.

1. Если вам интересно консольные скрипты писать в рамка движка Opencart - пожалуйста...

2. Я описываю суть, а не полную конкретику. Думаю, что вы без меня знаете, как писать SQL-запросы.

Надіслати

Статья то конечно хорошая, но мне кажется, что очереди для опенкарта - это избыточный функционал. То есть ну там из 100 магазинов - дай бог он нужен будет 2-3 от силы...

Отправка email - вот тут вообще не вижу смысла использовать очереди тем более в реализации кролика.
Что мы получим из плюсов:
1) возможность заспамить все население планеты
Что мы получим из минусов:
1) тяжелую поддержку (как автор и сам заметил не каждый сможет такое распедалить)
2) дополнительные ресурсы сервера точно потребуются
3) потребуется повышенный контроль за данным решением
4) далеко не все хостинги это поддерживают в случае, если хостинг виртуальный
Соответственно применимость к почтовым рассылкам тут - минимальная, так как минусы довольно сильно перевешивают плюсы

Импорт товаров - да, тут уже есть смысл подумать в сторону очередей, но только в случае, если это делается прям на постоянной основе в огромных количествах. Но опять же точно так же есть ряд недостатков, перечисленных выше И плюс ко всему прочему - парсер товаров даже большого количества можно запустить по крону и НЕ получать всего того гемора обслуживания решения на очередях. Ну то есть как бы.... тоже получается что мимо...

Парсер сайтов в несколько потоков - ну типа да оно как бы тоже можно, но зачем? Не будет ли лучше и дешевле интегрироваться с сервисом, который уже все давно распарсил за вас? То есть выбор получается между а) интеграция, которую сделает любой разработчик и б) написать сложную систему, которая еще и поддержки и мониторинга требует для того, что на постоянке рпасить 1 - 3 сайта... ну как бы...

Как по мне кролик да и вообще очереди как таковые в опенкарте не уместны, так как требуют как минимум разработчика выше чем нулевого уровня, поддержку, мониторинг и стоимость такого удовольствия довольно высока. При этом отдача по сравнению с конкурентными решениями не так чтобы чем-то прям сильно лучше....

Надіслати

Для простых обывателей и начинающих, мало полезно. Для гуру опенкарта в целом тоже, т.к и так понятно как работать с этим. НО за старания и подробное описание однозначно лайк.
Вот только докер тут имхо лишний, у 99% владельцев магазинов на VPS докера нету, а их "одмины" не знают, что это такое.

 

В 21.07.2021 в 18:43, OtezVikentiy сказал:

Отправка email - вот тут вообще не вижу смысла

Когда будете работать с магазинами где 500+ заказов в день, все начнет обретать смысл.
4. Про хостинги вообще, смешно до слез... Тем магазинам которые используют шаред хостинг эта статья не нужна в принципе, у них нет не бюджета, не потребности в этом.
Но вот из реального опыта скажу, что RabbitMQ решил для одного из моих проектов проблему с отправкой почты, благодаря очередям, т.к сторонний SMTP сервис не мог принимать больше 200 писем в минуту и его нельзя было менять на другой.
 

 

В 21.07.2021 в 18:43, OtezVikentiy сказал:

так как требуют как минимум разработчика выше чем нулевого уровня, поддержку, мониторинг и стоимость такого удовольствия довольно высока

Если говорить о реальных магазинах, а не ларьках с 3 продажами в день или сайтах мамкиных стартаперов, то очень даже нужная вещь. Но каждый смотрит с высоты своей колокольни, даже если она очень приземленная.

Надіслати
В 02.08.2021 в 13:06, ocdev_pro сказал:

Но вот из реального опыта скажу, что RabbitMQ решил для одного из моих проектов проблему с отправкой почты, благодаря очередям, т.к сторонний SMTP сервис не мог принимать больше 200 писем в минуту и его нельзя было менять на другой.

Ну в таком случае то да, конечно очереди затащат, но это мне кажется прям какой-то очень специфичный узкий индивидуальный кейс, нет? Ну и потом кролик - не самое легковесное решение на самом то деле. Можно например своего менеджера очередей написать, как один из вариантов, если скиллов хватит ))))

Но так вообще да, согласен, что за старания за статью стоит поставить лайкос ))) Для тех кто хочет попробовать очереди - кролик - это самое оно )))

Надіслати

Спасибо за статью, я как раз пытаюсь разобраться, но скажите, есть ли что нибудь попроще с такой же концепцией но без docker/supervisor/RabbitMQ и для opencart :rolleyes:.

Надіслати

ай молодец! жаль шо из коробки пыха не умеет в очередя. на с++ писал приложение с очередями. мютексы все дела. однозначно развивает понимание мироздания :grin:

Надіслати

Можно самому залепить очередь для отправки почты, основанную на работе крона. Даже учитывая время "срабатывания" в 1 минуту

Надіслати
19.05.2023 в 13:10, chukcha сказал:

Можно самому залепить очередь для отправки почты, основанную на работе крона. Даже учитывая время "срабатывания" в 1 минуту

Конечно можно, а еще можено суп вилкой есть, неудобно правда, но работает.  Сразу видно у кого развитие остановилось этак в 2013

Надіслати
19.05.2023 в 23:53, ocdev_pro сказал:

Сразу видно у кого развитие остановилось этак в 2013

Это ты про себя? Самокритичен. Хвалю!

Надіслати
19.05.2023 в 15:57, chukcha сказал:

Это ты про себя? Самокритичен. Хвалю!

Дед ну ты стрелочник, не актуально.. придумай что-то новое. На вот ссылку  https://www.php.net/releases/8.2/en.php на релиз php 8.2 почитай, уверяю твой мир перевернется с ног на голову 

Надіслати
20.05.2023 в 00:24, ocdev_pro сказал:

Дед ну ты стрелочник, не актуально.. придумай что-то новое. На вот ссылку  https://www.php.net/releases/8.2/en.php на релиз php 8.2 почитай, уверяю твой мир перевернется с ног на голову 

Это ты только что нашел эту ссылку?
 

Надіслати
19.05.2023 в 16:27, chukcha сказал:

Это ты только что нашел эту ссылку?
 

Что-то новое придумай, твои сообщения не несут смысла, научись хоть контаргументы строить. Ты сравнил RabbitMQ и колхоз на CRON задачах и говоришь, что нечем не хуже... Ты устарел в знаниях и упорно бьешь себя в грудь, что я же дед, я кодил еще когда ты не родился. Иди уже на пенсию

Надіслати
20.05.2023 в 01:39, ocdev_pro сказал:

@chukcha Не хочу вести диалог с самоуверенным инфантильным человеком. бб

С тобой диалог? О чем?
С кем?
Когда человек не понимает элементарного (ок, не понимал)
989403628_.png.2d721060e6bbd448e7513493a07b79e7.png

  • +1 1
Надіслати

Створіть аккаунт або увійдіть для коментування

Ви повинні бути користувачем, щоб залишити коментар

Створити обліковий запис

Зареєструйтеся для отримання облікового запису. Це просто!

Зареєструвати аккаунт

Вхід

Уже зареєстровані? Увійдіть тут.

Вхід зараз
  • Зараз на сторінці   0 користувачів

    • Ні користувачів, які переглядиють цю сторінку

×
×
  • Створити...

Important Information

На нашому сайті використовуються файли cookie і відбувається обробка деяких персональних даних користувачів, щоб поліпшити користувальницький інтерфейс. Щоб дізнатися для чого і які персональні дані ми обробляємо перейдіть за посиланням . Якщо Ви натиснете «Я даю згоду», це означає, що Ви розумієте і приймаєте всі умови, зазначені в цьому Повідомленні про конфіденційність.