Зачастую кажется, что 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, и быстро на коленке допиливалась самая первая версия. В результате она и опубликована как многократно проверенная, надежная, устойчивая и удобная.
Комментарии (9)
Wolf4ara
20.04.2016 18:57Тормозит на новых ядрах линукс, и похоже, проект забросили…
konst20
21.04.2016 03:26Можно подробнее про тормоза? Как именно? Тормозит вставка в очередь? Передача заданий? Прием результатов?
И по каким признакам «похоже, проект забросили»? Последние коммиты проекта на гитхабе датированы осенью 2015 годаWolf4ara
21.04.2016 21:08последний раз собирал отсюда:
https://launchpad.net/gearmand
тормозит все, на ядрах от 3,2 и выше, позже пришлю пример бенчмарка, которым мы проверяли.
ЗЫ дайте ссыль на гите
Hayate
20.04.2016 18:59Умеет ли Gearman работать с отложенными сообщениями? Например есть задача, для выполнения которой нужно отправить по API n запросов и каждый этап занимает, ну допустим минуту. Нет смысла долбиться по API постоянно. Здесь вот было бы самое то использовать отложенные сообщения.
Если не трудно, можете рассказать почему выбрали именно Gearman, а не ActiveMQ или RabbitMQ?konst20
21.04.2016 03:321) время выполнения задач для Gearman некритично. Я не очень понял вашу задачу, но мне кажется, что в данном случае Gearman решит ваши проблемы. Напишите подробнее мне в личку, думаю, что помогу вам
2) я начал работать в проекте, в котором был выбран именно Gearman. Убедился, насколько это простой и хороший инструмент, и далее в своих проектах использовал именно Gearman. Для него не хватало оболочки — именно то, о чем публикация. Я написал оболочку и далее о выборе инструмента не задумывался.
Несколько раз смотрел RabbitMQ, но, мне кажется, он много сложнее в использовании.
Проблема Gearman в том, что работать с ним под Windows — на том же DenWer или OpenServer — очень неудобно. У меня есть в планах написать библиотеку, которая будет заменять классы GearmanWorker(), GearmanClient().Hayate
21.04.2016 04:23Да зачем в личку, думаю раз тема о очередях и их реализациях, всем будет интересно. Мне по крайней мере была бы интересна такая дискуссия, если бы кто-то её вёл.
Более подробный пример: нам нужно совершить платёж. Мы отправляем сообщение в очередь, его получает воркер и делает запрос по API. На данном этапе платёжный шлюз только проверяет указанные данные. И проверяет он их допустим минимум 5 минут. Если мы после отправки первого запроса тут же отправим второй — «ну что там, как данные, годятся?» то мы получим ответ — «нет, жди ещё». И так все эти 5 минут.
Решение — нужно эти 5 минут ждать и не отправлять запросов. Это может быть реализовано например через крон, выгребать например записи из базы, фильтруя по какому-то признаку, или это может быть реализовано встроенными средствами брокера.
Вот я имел в виду — есть ли какие-то встроенные средства для этого?
В своё время когда выбирали брокер, я не нашёл таких средств, в RabbitMQ про это писали, что решается костылями, и устроил в итоге только ActiveMQ, там можно указать в заголовке время, через которое отправленное сообщение попадёт в очередь.
А сейчас стало любопытно, корректно ли я интерпретировал ситуацию с продуктами.
unSeen
21.04.2016 10:01Не очень правильно называть Gearman сервером очередей, ему больше подходит определение Сервер Задач. В отличие от классических, всем известных RabbitMQ и ActiveMQ, Gearman создавался именно как решение для распределенного выполнения задач, а не как решение по доставке сообщений от одного компонента к другогому. В Gearman вы можете передавать воркерам весь payload, когда в RabbitMQ вам пришлось бы использовать дополнительное хранилище как контекст, иначе бы получили переполнение оперативной памяти и деградацию сервиса.
ZurgInq
Когда то давно немного работал с gearman. Осталось ощущение, что он больше подходит для задач rpc, нежели для создания полноценных очередей.