Масштабирование путем распределения задач (PHP7 + Gearman + Supervisor)
Доброго времени суток, на связи Юрий Сиротенко. Сегодня речь пойдет о такой теме как оптимизация и масштабирование веб приложений путем распределения нагрузки. Любой высоконагруженный проект рано или поздно начинает нуждаться в оптимизации и масштабировании. Сервер на котором расположено ваше приложение просто может перестать справляться с возложенной на него нагрузкой и с этим безусловно нужно что-то делать.
Если вы хотите ознакомиться с материалом в видео формате, вы можете найти запись в лектории или просто перейти по ссылке. Также вы сможете получить методичку и перезентацию на данную тему под видео - лекцией.
Приведу наглядный пример, в каких случаях может возникнуть необходимость в масштабировании путем распределения задач между серверами:
В приложении существует модуль для генерации неких Excel отчетов. Документ довольно сложен и по мере роста данных в системе он активно масштабируется. Рост клиентов, которые используют приложение и генерируют документы тоже интенсивно возрастает. В результате сервер, на котором работает приложение просто перестает справляться с нагрузкой.
Чтобы избежать проблемы с высокой нагрузкой можно распределить эту самую нагрузку на другой сервер. В случае с примером выше, каждый генерируемый отчет будет выполняться на удаленной машине отдельной задачей.
И того есть проблема высокой нагрузки на сервер вследствие интенсивной генерации сложных отчетов с большим массивом данных. В качестве решения выступает способ распределения нагрузки.
Теперь об инструментах, которые помогут решить задачу:
Gearman - это открытая (OpenSource) система очередей. Позволяет масштабироваться на несколько серверов. При помощи Gearman можно выставлять приоритеты выполняемым задачам.
Дополнительные материалы: Supervisor - клиент / серверная система которая позволяет пользователям мониторить и управлять программами или скриптами. При помощи Supervisor можно запустить программу n количество раз параллельно, перезапустить ее при возникновении критической ошибки, отслеживать статус выполнения программы и управлять ее работой, фиксировать логи, назначать как готовые так и свои собственные обработчики на различные события программы и многое другое
Дополнительные материалы:
Добавляем репозиторий, спасибо ondrej
Если в очередной раз запустить клиент, то можно увидеть, что количество задач в очереди увеличится:
Воркер получился каким-то однозадачным, выполнив работу единожды он сразу же отключился. Этот вариант мало кого может устроить. В идеале было бы замечательно, если бы обработчик после выполнения задачи снова бы запускался автоматически. Для удовлетворения такой потребности может помочь менеджер процессов Supervisor
Супервизор автоматически получит созданный конфиг подключив его в основной. Также есть возможность указать свою директорию с конфигурационными файлами, который могут быть подключены в основной конфиг при помощи [include]. Подробнее читайте в официальной документации Supervisor.
Теперь нужно запустить Supervisor
Пояснение схемы:
Если вы хотите ознакомиться с материалом в видео формате, вы можете найти запись в лектории или просто перейти по ссылке. Также вы сможете получить методичку и перезентацию на данную тему под видео - лекцией.
Приведу наглядный пример, в каких случаях может возникнуть необходимость в масштабировании путем распределения задач между серверами:
В приложении существует модуль для генерации неких Excel отчетов. Документ довольно сложен и по мере роста данных в системе он активно масштабируется. Рост клиентов, которые используют приложение и генерируют документы тоже интенсивно возрастает. В результате сервер, на котором работает приложение просто перестает справляться с нагрузкой.
Чтобы избежать проблемы с высокой нагрузкой можно распределить эту самую нагрузку на другой сервер. В случае с примером выше, каждый генерируемый отчет будет выполняться на удаленной машине отдельной задачей.
И того есть проблема высокой нагрузки на сервер вследствие интенсивной генерации сложных отчетов с большим массивом данных. В качестве решения выступает способ распределения нагрузки.
Теперь об инструментах, которые помогут решить задачу:
- Операционная система Linux (дистрибутив Ubuntu)
- Веб сервер Apache
- PHP 7
- Приложение на PHP
- Сервер очередей Gearman
- Менеджер процессов Supervisor
Gearman - это открытая (OpenSource) система очередей. Позволяет масштабироваться на несколько серверов. При помощи Gearman можно выставлять приоритеты выполняемым задачам.
Дополнительные материалы: Supervisor - клиент / серверная система которая позволяет пользователям мониторить и управлять программами или скриптами. При помощи Supervisor можно запустить программу n количество раз параллельно, перезапустить ее при возникновении критической ошибки, отслеживать статус выполнения программы и управлять ее работой, фиксировать логи, назначать как готовые так и свои собственные обработчики на различные события программы и многое другое
Дополнительные материалы:
Установка
Gearman
В стандартном репозитории Ubuntu 16.04 уже есть Gearman и все зависимые от него компонентыsudo apt-get install gearman
- gearman-job-server - сервер
- gearman-tools - инструменты для управления и мониторинга Gearman сервером, например gearadmin
- libgearman7 - библиотека для работы с Gearman
- и т.д.
Добавляем репозиторий, спасибо ondrej
sudo add-apt-repository -y ppa:ondrej/php sudo apt-get update sudo apt-get install php-gearmanОбновляем конфигурационные файлы сервера
sudo service apache2 reload
Supervisor
sudo apt-get install supervisor
Приложение
В качестве примера будет написан "сервис" для генерации документов. Пользователь отправляет запрос на генерацию отчета, сервис генерирует документ и фиксирует статус в базе данныхАлгоритм
- Клиент (Client) отправляет запрос на генерацию документа
- Задача отправляется на сервер очередей и помечается как фоновая (background).
- Регистрируется функция и передаются аргументы
- На сервере очередей создается задача (task)
- Обработчик функции (Worker) увидев задачу в очереди начинает ее выполнение (если он свободен). Для обработчика, задача называется Job. Если обработчик функции отсутствует или занят, то задача ставится в очередь ожидая исполнения
- Client - клиент, который отправляет запрос серверу очередей
- Background - фоновая задача, выполняемая асинхронно
- Task - задача, которая ожидает выполнения и стоит в очереди
- Worker - обработчик задачи
- Job - работа над задачей, которую выполняет обработчик
Создание клиента
<?php // Name of function $funcName = 'generateReport'; // Data for function $data = [ 'report' => 'user_statistic', ]; $client = new GearmanClient(); $client->addServer('127.0.0.1', '4730'); $client->doBackground($funcName, json_encode($data));
Создание воркера
<?php $worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction('generateReport', 'generate'); $worker->work(); function generate($job) { $workload = $job->workload(); $data = json_decode($workload, true); // do generate... echo "generate... \n"; sleep(3); //set status into db echo "set status into db... \n"; sleep(2); echo "done! \n"; }
Тестируем
Запускаем обработчик
php Server.php
Запускаем клиент
php Client.phpТеперь можно увидеть, как обработчик вывел сообщение:
generate... set status into db... done!Готово! Обработчик выполнил свою работу и выключился. В этом можно убедиться воспользовавшись инструментом для мониторинга Gearman очередей gearadmin:
gearadmin --statusКак результат инструмент отобразит список функций и информацию о них:
generateReport 0 0 0где первая колонка - наименование функции зарегистрированной на сервере; вторая колонка - количество задач в очереди; третья колонка - количество выполняемых задач в настоящий момент; четвертая колонка - количество обработчиков которые будут работать с задачами.
Если в очередной раз запустить клиент, то можно увидеть, что количество задач в очереди увеличится:
php Client.php gearadmin --status generateReport 1 0 0Но задача не будет выполнена т.к. предыдущий обработчик завершил свою деятельность обработав предыдущий запрос. Запустим обработчик еще раз:
php Server.php gearadmin --status generateReport 1 1 1 gearadmin --status generateReport 0 0 0Обработчик еще раз выполнил работу и завершил свою деятельность, что и подтверждает утилита gearadmin.
Воркер получился каким-то однозадачным, выполнив работу единожды он сразу же отключился. Этот вариант мало кого может устроить. В идеале было бы замечательно, если бы обработчик после выполнения задачи снова бы запускался автоматически. Для удовлетворения такой потребности может помочь менеджер процессов Supervisor
Настройка Supervisor
Первое, что нужно сделать - это отконфигурировать Supervisor на запуск воркера. Чтобы не редактировать стоковый конфигурационный файл супервизора который находится в /etc/supervisor/supervisord.conf создадим свой собственный в /etc/supervisor/conf.d/Супервизор автоматически получит созданный конфиг подключив его в основной. Также есть возможность указать свою директорию с конфигурационными файлами, который могут быть подключены в основной конфиг при помощи [include]. Подробнее читайте в официальной документации Supervisor.
sudo touch generate.conf sudo vim generate.confВставляем:
[program:generateDocument] command=/usr/bin/php /a/path/Server.php ; the program (relative uses PATH, can take args) process_name=%(program_name)s ; process_name expr (default %(program_name)s) numprocs=1 ; number of processes copies to start (def 1) directory=/tmp ; directory to cwd to before exec (def no cwd) umask=022 ; umask for process (default None) priority=999 ; the relative start priority (default 999) autostart=true ; start at supervisord start (default: true) autorestart=true ; retstart at unexpected quit (default: true) startsecs=10 ; number of secs prog must stay running (def. 1) startretries=3 ; max # of serial start failures (default 3) exitcodes=0,2 ; 'expected' exit codes for process (default 0,2) stopsignal=QUIT ; signal used to kill process (default TERM) stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) user=username ; setuid to this UNIX account to run the program redirect_stderr=true ; redirect proc stderr to stdout (default false) stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) stdout_events_enabled=false ; emit events on stdout writes (default false) stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) stderr_events_enabled=false ; emit events on stderr writes (default false) ;environment=A=1,B=2 ; process environment additions (def no adds) serverurl=AUTO ; override serverurl computation (childutils)Важно не забыть поменять имя пользователя напротив директивы user и указать свой путь к обработчику в command, а также не забыть поменять логи в директивах stdout_logfile и stderr_logfile
Теперь нужно запустить Supervisor
sudo supervisordДалее запускаем утилиту для работы с supervisor
sudo supervisorctl start generateDocumentГотово. Теперь воркер запущен и в этом можно убедиться воспользовавшись инструментом gearadmin
gearadmin --status generateReport 0 0 1 php Client.php gearadmin --status generateReport 1 1 1 gearadmin --status generateReport 0 0 1Воркер успешно отработал и завершил свою деятельность, а supervisor вновь его запустил. Результат выполненной работы можно посмотреть в логах, путь до которых был указан в конфигурационном файле supervisor в директиве stdout_logfile
generate... set status into db...Как видим наша задача была полностью решена. Итоговая схема работы выглядит примерно следующим образом:

Пояснение схемы:
- Менеджер процессов supervisor запускает Worker
- Worker начинает мониторить наличие тасков на сервере очередей
- Client добавляет task в очередь
- Worker начинает работать с таском
- Worker фиксирует результат в базу данных
Дополнительная информация
Версии ПО на которых был протестирован алгоритм:- Linux Ubuntu 16.04
- PHP 7
- Supervisor 3.2.0
- Gearman 1.0.6
Информация
Дата создания:
01.01.2019
Категория:
Веб-разработка