Сервер очередей Gearman: опыт практического использования и веб-приложение Gearman Monitor && Control

    Сервер очередей Gearman — прекрасный инструмент. Но в работе сервер очередей в чем-то напоминает системный блок: что-то делает, но для того чтобы знать, что именно, и управлять процессом, нужен монитор с клавиатурой, и представление о том, что вообще происходит в системном блоке.
    Зачастую кажется, что Gearman — как диковинный инструмент без рукоятки: интересен и красив, но неясно, зачем нужен, а пользоваться болезненно.
    Нужно выбраться из этой ситуации, Gearman действительно хорош.
    Давайте рассмотрим:
    • Gearman «на пальцах»
    • примеры реальных задач с использованием Gearman
    • веб-приложение и класс для мониторинга в реальном времени и управления процессами на сервере очередей Gearman


    Интересно? Прошу под кат.


    Можно ли объяснить принцип работы Gearman «на пальцах»?

    Можно.

    Что такое воркер?
    Это просто консольный скрипт, на каком языке программирования — неважно. Скрипт запущен постоянно, это демон.
    При запуске воркер-демон отправляет на сервер строки — имена функций, которые он может выполнить, открывает сокет на сервер и ждет.

    Какие данные получает воркер?
    Воркеру приходит две строки: первая — имя ф-и, которую нужно выполнить, и вторая — аргумент. Подчеркнем: воркеру нельзя передать несколько аргументов, массив, объект — только строка, все другие виды данных должны быть приведены к строке — сериализация или json.
    Собственно, что удивительного — вся передача данных по протоколу, например, HTTP — это тоже передача только строк.

    Откуда приходят строки — задания для воркера?
    Клиент Gearman, отправляя на сервер задачу, передает как раз две строки — имя функции, которую нужно выполнить, и аргумент в виде строки. При этом задача в очереди помечается как находящаяся в процессе выполнения.

    И что дальше?
    Если задача — фоновая, воркер выполняет функцию и передает на сервер только сигнал выполнения ф-и. Если задача — не фоновая, воркер передает Gearman строку — результат выполнения ф-и, и сигнал выполнения.
    При получении сигнала выполнения Gearman отмечает задачу как выполненную и удаляет ее из очереди.

    А если в процессе выполнения функции воркер аварийно завершит работу или в ф-и возникнет нештатная ситуация — то есть ф-я не выполнится?
    Gearman в этом случае не получит сигнала успешного завершения, и задача останется в очереди

    Что такое клиент?
    Отдельное понятие «клиент» для Gearman сложно выделить. Можно обращаться к Gearman из ЯП, отправляя и принимая данные — можно отправить и ждать, можно в фоновом режиме. Но все еще проще.

    «Получает», «отправляет», «приходят» — как происходит обмен данными с сервером? Нужны низкоуровневые дополнения в ЯП?
    Общение с Gearman происходит через сокеты. Можно вообще не иметь дополнений в ЯП для работы с Gearman, обойтись работой с сокетами и Telnet. Так, например, в PHP работать с Gearman можно, установив PECL дополнение в язык, а можно использовать Pear библиотеку, просто подключив файлы нескольких классов.

    Если клиент отправит на сервер задачу, а воркера нет для этой функции нет — или нет свободного, или нет вообще?
    Задача «повиснет» в ожидании воркера. Если придут еще задачи на эту же функцию, образуется очередь — Gearman сервер очередей все же.

    Можно ли на сервере очередей различить две задачи на одинаковую функцию?
    Нет. Ни по аргументу, никак.

    Можно ли узнать, какая в очереди отправленная задача?
    Поскольку задачи на одну и ту же ф-ю неразличимы, то нет.

    Можно ли узнать, сколько задач в очереди?
    Да. Можно также узнать, сколько воркеров может обработать эту задачу, и откуда эти воркеры (IP).

    Представим, что поступила одна задача, и ее могут выполнить несколько воркеров. Кому достается задача?
    Задачи неразличимы, но и воркеры тоже неразличимы. Какому именно воркеру Gearman отдаст задачу — так просто не ответить. Очереди воркеров нет.

    Какие виды задач бывают на сервере очередей?
    Задачи можно разделить 1) по приоритетам, 2) фоновая задача или нет
    1) Приоритетов три — обычный, low — менее приоритетный, чем обычный, и high — более высокого, чем обычный, приоритета. Приоритет учитывается в очереди, по умолчанию — обычный приоритет.
    2) Фоновая задача ничего не отдает серверу очередей, и клиент не получает никаких данных. Обычная задача должна вернуть строку, и Gearman отдаст эту строку клиенту как результат выполнения задачи.

    Сколько можно одновременно запустить воркеров?
    Тут нужно уточнить — не сколько запустить, а сколько воркеров может одновременно подключиться к Gearman для обработки задач.
    Теоретически — сколько угодно. В реальности максимальное числов воркеров может быть ограничено максимальным числом одновременных потоков на внешний ресурс, числом одновременных подключений к БД и прочими условиями, не зависящими от Gearman. Автору этих строк удавалось запустить около 1000 на одном сервере, далее начинала ругаться MySQL.

    Можно ли работать в PHP с Gearman на Windows?
    Вопрос разделяется на два: 1) можно ли запустить сам сервер очередей Gearman на Windows и 2) можно ли работать с уже имеющимся на внешнием хосте сервером очередей.
    1) есть вариант установки Gearman на Windows с использованием cygwin

    2) Для комфортной работы, для использования в коде привычных конструкций вида
    $worker = new GearmanWorker();
    $worker->addServer()
    

    и подобных требуются дополнения в язык. Это сразу накладывает ограничения: вы не только не можете это сделать под Windows, но и не сможете это сделать на хостинге, если у вас нет прав на доступ к серверу, позволяющих устанавливать пакеты.
    Denwer и OpenServer не содержат дополнений для работы с Gearman.
    Значит, выхода нет, Gearman — только для *nix систем?
    Нет конечно. Решение проблемы — подключение к проекту библиотеки Pear Net_Gearman
    Там другие названия классов и немного другая логика, но пережить это можно и работать с Gearman позволяет полноценно.

    Реальные задачи с использованием Gearman



    1) Рекламное агентство сопровождает рекламные кампании AdWords и Яндекс.Директ для средних и крупных интернет-магазинов. Информация о товарах меняется постоянно: меняются цены (курс доллара и пр.), появляются новые товары, некоторые товары заканчиваются на складе, некоторые снимаются с продажи. Товаров в каждом магазине тысячи и десятки тысяч.
    Задача: сделать так, чтобы информация в рекламе AdWords и Яндекс.Директ была актуальной: нужно менять цены, добавлять рекламные объявления/группы/кампании для новых товаров, останавливать рекламу для закончившихся на складе, удалять объявления для товаров, снятых с продажи.
    Задача просто решается с использованием Gearman: из БД формируем задачи — изменение цен, добавление, остановка, удаление. Далее задачи бросаются на сервер очередей, и там спокойно обрабатываются в несколько потоков: воркеры обращаются к API AdWords или API Яндекс.Директ и выполняют требуемые операции.
    Получилось вот так:

    Gearman здесь решает две задачи: параллельное выполнение процессов — раз, и регулирование доступа к внешним ресурсам.
    Ни AdWords API, ни Яндекс.Директ API не дадут вам выполнять операции в сто, например, потоков — есть ограничение на количество запросов в секунду. В моем случае получилось максимум 4 потока к AdWords API и 8 потоков к Яндекс.Директ API.
    О времени выполнения. Начальная загрузка 10к товаров занимает до несколько часов, создается несколько сотен тысяч объявлений, несколько сотен кампаний и пр. Обновление — несколько минут, полностью в автоматическом режиме.

    2) Продолжение задачи 1. Почти все магазины передают данные в виде XML-файла. Но некоторые присылают XLS-файл. Нет проблемы получить данные из XLS-файла, есть PHPExcel. Но у PHPExcel есть нюанс: при обработке больших файлов он сильно тормозит, но главное — потребляет память вплоть до превышения лимитов в php.ini 1024Мб и больше.
    Процесс обработки файла XLS с помощью PHPExcel может быть распараллелен (идея была почерпнута из вот этой публикации, спасибо MParshin). Воркеры читают файл по строкам, каждый воркер — свои строки, таким образом, процесс распараллеливается.
    Здесь Gearman решает две задачи: 1)параллельная обработка и 2)обход ограничения на лимит памяти одного PHP-скрипта.
    Разумеется, в этом случае тоже нельзя запустить тысячу, например, воркеров — память сервера тоже не бесконечна. В моем случае получалось обрабатывать XLS-файл в 20 потоков.

    3) Крупный вендор — производитель оборудования — хочет знать, по каким ценам реально торгуется его оборудование. Данные можно получить из каталога, но опять же — только с сайта. Процесс стандартный: парсер, воркеры в несколько потоков получают данные с сайта каталога.
    Наличие API в разработанной системе Gearman Monitor && Control позволяет демонстрировать клиенту — вендору — получение данных в реальном времени.
    Здесь Gearman решает две задачи: параллельное получение и обработка данных, и отображение процесса в реальном времени.
    Вот клиентский интерфейс системы.


    4) Поставщики гостиничных услуг предоставляют данные. Задача: отобразить гостиницы на карте. Задача вроде бы совсем простая, так как данные предоставляются вместе с координатами. Но, к сожалению, многие из предоставленных координат неверные, и клиентам показывать такое нельзя — адрес в одном месте, а маркер гостиницы — совсем в другом. Было принято решение самостоятельно получать данные с помощью геокодера Гугла, используя адреса гостиниц. Но при простом вызове геокодера в яваскрипте многие маркеры не отображаются — яваскрипт пытается одновременно получить адреса всех гостиниц, геокодер блокирует большинство запросов из-за превышения лимита на число обращений в секунду.
    Решение: все запросы геокодера из яваскрипта направляются на свой прокси, которые передает задачу на сервер очередей.
    Здесь Gearman решает задачу регулирования и ограничения доступа к внешнему ресурсу — API геокодера Гугла.


    5) Последний пример — комплексное использование сервера очередей. На сайте предоставлена специфическая информация о нескольких тысячах объектов. Задача: получить и перевести эту информацию. Решение: запускаем воркеры для получения информации, и воркеры для перевода. Первые воркеры в несколько потоков получают информацию, как только воркер получил требуемый текст, он опять ставит задачу на сервер очередей, задачу для воркеров перевода. Воркеры-переводчики переводят ее и кладут уже готовый материал в БД.
    Gearman здесь используется стандартно — получение и обработка информации в несколько потоков, нюанс только в том, что воркеры сами ставят задачи другим воркерам.

    На основе практических задач появились требования к системе управления Gearman

    Представим, что мы работаем с сервером очередей. Как запустить один воркер? Набираем в консоли php worker.php
    Ок, нужно запустить 20 воркеров для параллельной обработки. Открыть 20 консолей? Не вариант. Или нужно запустить несколько разных воркеров — та же проблема. Итак, требуется метод класса и реализация в веб-интерфейсе:
    — запуск воркеров, с выбором какого именно и указанием количества
    Ок, разрабатываем дальше, запустили воркер, он работает. А остановить его как? Обязательно нужна
    — остановка воркеров
    Ситуация: запустили несколько разных воркеров в процессе разработки, и — ой, стоп, все назад, параметр не тот! Нас выручит:
    — остановка всех воркеров одним действием
    Но воркер — он как маленький ребенок: делает чего-то, а что — неясно, за ним присмотр нужен. Для этого потребуется:
    — логирование работы воркера
    Тут чуть подробнее. Очень приятно видеть, что делает воркер, наслаждаться творением. Но вот ситуация: бац — и воркер вылетел. Или еще лучше — вообще не стартует. А что за ошибка? В коде неправильно, или исключение необработанное, или ошибку от внешнего сервиса не предусмотрели? Поэтому:
    — логирование ошибок воркера, включая фатальные
    Лог может быть большим, просмотр его утомителен, а зачастую невозможен из-за объема. требуется
    — поиск в логе произвольного текста
    С воркерами разобрались, они нам подвластны. А очередь?
    Опять же, воркеры — как маленькие дети, разбирают кучку, а что в той кучке? Поэтому:
    — вывод всех функций, которые зарегистрированы на сервере очередей
    — вывод очереди задач по каждой функции
    Но вот клиенты набросали на сервер очередей задач, по одной скопилось их 1000, а воркер — один и явно не справится, или вообще нет воркеров и не предвидится. Или ближе к жизни: внешний сервис, к которому обращались воркеры, недоступен, очередь нужно сбрасывать. Как быть? Требуется
    — сброс/очистка очереди по каждой функции
    Но вот мы наигрались Gearman, нужно отключаться. Или же мы что-то сделали не так, отправили на сервер очередей, и нужно срочно все остановить. Поможет
    — полный сброс: очистка все очереди, останов всех воркеров.

    Добавим, что все происходящее должно отображаться в реальном времени без всяких обновлений страницы.

    Все указанные выше задачи решит класс Gearman_Monitor и веб приложение Gearman Monitor && Control, реализующее методы этого класса.
    Проект Gearman Monitor && Control на Github
    Чистый скриншот веб-приложения

    Тот же скриншот с подробными пояснениями


    Вот видео работы веб-приложения


    Для использования в разработке требуются классы Gearman_Monitor и Gmonitor_Settings (имена php-файлов совпадают с именами классов).
    Свойства и методы классов подробно задокументированы в самих файлах. Поясним только вот это:
    public static $func_name_synonyms = array(
            'summ' => 'Sum',
            'muliply' => 'Умножение и деление в воркере',
            'subtract' => 'Substract Function',
            'divide' => '功能',
        );
    

    Здесь
    ключ массива — имя функции, зарегистрированное воркером на сервере очередей
    значение — То, что вы увидите в таблице, в любом виде. Это для удобства работы операторов — раз, и еще применение. Представим, что на одном сервере очередей «крутятся» несколько проектов. Разумеется, хочется видеть не все в куче, а только свой проект. Для этого указываем синонимы (если не указали, используется имя функции), и устанавливаем значение
    public static $synonyms_only_view = true;
    

    В этом случае в таблице функций будут отображаться только те, для которых есть синонимы.

    Еще один момент. Веб-приложение содержит логгер и обработчик ошибок PHP. Если вы подключите к воркеру файл gearman_includes.php, то сможете записывать из воркера в лог, который отображается, и ошибки воркера тоже будут записываться и отображаться в логе.

    В директории /workers лежит два воркера. fake_worker.php нужен для работы приложения, второй воркер — из работающего проекта, можно рассмотреть его как пример.

    Для использования веб-приложения потребуется:
    — создание в БД таблицы log (см. файл log_create.sql)
    — указать параметры соединения с БД в файле Gearman_Db.php
    — установить права на запись во все директории внутри view / Smarty / smarty_dirs (в первую очередь касается директории view / Smarty / smarty_dirs / templates_c )
    — указать хост сервера Gearman в файле Gearman_Monitor.php

    Всем удачных очередей!

    P.S. Веб-приложение выдрано из работающего проекта, могут быть небольшие нестыковки, заранее прошу прощения.
    Еще момент. Неоднократно делались попытки переписать веб-приложение — облагородить код, интерфейс, но постоянно возникали задачи с использованием Gearman, и быстро на коленке допиливалась самая первая версия. В результате она и опубликована как многократно проверенная, надежная, устойчивая и удобная.
    • +10
    • 11.2k
    • 9
    Share post

    Similar posts

    Comments 9

      +4
      Когда то давно немного работал с gearman. Осталось ощущение, что он больше подходит для задач rpc, нежели для создания полноценных очередей.
        0
        Тормозит на новых ядрах линукс, и похоже, проект забросили…
          0
          Можно подробнее про тормоза? Как именно? Тормозит вставка в очередь? Передача заданий? Прием результатов?
          И по каким признакам «похоже, проект забросили»? Последние коммиты проекта на гитхабе датированы осенью 2015 года
            0
            если в популярном проекте нет коммитов полгода то да, забросили.
              0
              последний раз собирал отсюда:
              https://launchpad.net/gearmand
              тормозит все, на ядрах от 3,2 и выше, позже пришлю пример бенчмарка, которым мы проверяли.
              ЗЫ дайте ссыль на гите
            0
            Умеет ли Gearman работать с отложенными сообщениями? Например есть задача, для выполнения которой нужно отправить по API n запросов и каждый этап занимает, ну допустим минуту. Нет смысла долбиться по API постоянно. Здесь вот было бы самое то использовать отложенные сообщения.
            Если не трудно, можете рассказать почему выбрали именно Gearman, а не ActiveMQ или RabbitMQ?
              0
              1) время выполнения задач для Gearman некритично. Я не очень понял вашу задачу, но мне кажется, что в данном случае Gearman решит ваши проблемы. Напишите подробнее мне в личку, думаю, что помогу вам
              2) я начал работать в проекте, в котором был выбран именно Gearman. Убедился, насколько это простой и хороший инструмент, и далее в своих проектах использовал именно Gearman. Для него не хватало оболочки — именно то, о чем публикация. Я написал оболочку и далее о выборе инструмента не задумывался.
              Несколько раз смотрел RabbitMQ, но, мне кажется, он много сложнее в использовании.
              Проблема Gearman в том, что работать с ним под Windows — на том же DenWer или OpenServer — очень неудобно. У меня есть в планах написать библиотеку, которая будет заменять классы GearmanWorker(), GearmanClient().
                0
                Да зачем в личку, думаю раз тема о очередях и их реализациях, всем будет интересно. Мне по крайней мере была бы интересна такая дискуссия, если бы кто-то её вёл.
                Более подробный пример: нам нужно совершить платёж. Мы отправляем сообщение в очередь, его получает воркер и делает запрос по API. На данном этапе платёжный шлюз только проверяет указанные данные. И проверяет он их допустим минимум 5 минут. Если мы после отправки первого запроса тут же отправим второй — «ну что там, как данные, годятся?» то мы получим ответ — «нет, жди ещё». И так все эти 5 минут.
                Решение — нужно эти 5 минут ждать и не отправлять запросов. Это может быть реализовано например через крон, выгребать например записи из базы, фильтруя по какому-то признаку, или это может быть реализовано встроенными средствами брокера.
                Вот я имел в виду — есть ли какие-то встроенные средства для этого?
                В своё время когда выбирали брокер, я не нашёл таких средств, в RabbitMQ про это писали, что решается костылями, и устроил в итоге только ActiveMQ, там можно указать в заголовке время, через которое отправленное сообщение попадёт в очередь.
                А сейчас стало любопытно, корректно ли я интерпретировал ситуацию с продуктами.
              0
              Не очень правильно называть Gearman сервером очередей, ему больше подходит определение Сервер Задач. В отличие от классических, всем известных RabbitMQ и ActiveMQ, Gearman создавался именно как решение для распределенного выполнения задач, а не как решение по доставке сообщений от одного компонента к другогому. В Gearman вы можете передавать воркерам весь payload, когда в RabbitMQ вам пришлось бы использовать дополнительное хранилище как контекст, иначе бы получили переполнение оперативной памяти и деградацию сервиса.

              Only users with full accounts can post comments. Log in, please.