Статьи

Делать вещи быстрее с Gearman и супервайзером

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

В этом случае приложение может стать змеей, поедающей слона, как в книге «Маленький принц» . Вы берете некоторые данные у пользователя и заставляете его ждать, потому что змее нужно некоторое время, чтобы переварить слона (или что-то еще, что должно сделать ваше приложение):

Змея ест слона

Чтобы быстрее обрабатывать эту функцию, вам нужно сделать части приложения асинхронными . Этого можно добиться, делегировав эту задачу более мощному серверу или запустив его в фоновом режиме.

И Gearman является подходящим инструментом, который можно использовать для этого.

В этом руководстве мы создадим простое приложение, которое будет делегировать задачу от клиента работнику Gearman. Наше приложение будет вычислять последовательность Фибоначчи в трех процессах. Для запуска рабочих процессов мы установим и настроим Supervisor.

Обратите внимание, что для примеров из этого руководства необходим PHP7.

Во-первых, давайте узнаем, что Gearman с его домашней страницы :

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

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

Если вы используете Debian / Ubuntu, выполните следующую команду, чтобы установить Gearman с необходимыми инструментами и расширением PHP:

1
sudo apt-get install gearman php-gearman gearman-tools

После этого запустите сервер Gearman и проверьте статус:

1
2
sudo gearmand -d
gearadmin —status

Но вы не увидите ничего полезного после команды status, потому что мы еще не создали ни одного рабочего. Просто запомни это, пока нам это не понадобится.

И мы готовы запустить скрипт под названием client.php . Этот скрипт создаст клиент Gearman и отправит информацию на сервер на том же компьютере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?php
 
// create gearman client
 
$client = new GearmanClient();
$client->addServer(‘127.0.0.1’);
 
// config
 
$numbers = [
    1, 2
];
 
// do a task with gearman worker
 
$res = $client->doNormal(‘get_sequence’, json_encode($numbers));

Возможно, вы заметили, что мы отправили числа в формате JSON. Клиенты и работники Gearman общаются друг с другом в строковом формате, поэтому одним из способов сериализации массива является использование функции json_encode() или чего-то подобного.

Получив ответ от работника, мы рассмотрим его с помощью json_decode() и json_decode() виде строк CSV:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?php
 
// decode answer
 
$lines = json_decode($res, true);
if (empty($lines)) {
    die(’empty answer’);
}
 
// output as csv
 
foreach ($lines as $numbers) {
    $line = implode(‘, ‘, $numbers);
    echo($line . PHP_EOL);
}

Мы только что закончили наш клиентский скрипт, поэтому давайте запустим его из терминала:

1
php /vagrant/tuts-gearman-supervisor/code/client.php

Но он застрянет без какого-либо вывода. Почему? Это ждет работника, чтобы соединиться.

Пришло время создать работника, который будет выполнять заказанную клиентом работу. Нам потребуется файл с функцией fibonacci() и мы создадим нового работника Gearman на текущем сервере:

1
2
3
4
5
6
<?php
 
require_once __DIR__ .
 
$worker = new GearmanWorker();
$worker->addServer(‘127.0.0.1’);

После этого мы добавим новую функцию, названную так же, как мы ее называли в клиентском коде:

01
02
03
04
05
06
07
08
09
10
11
<?php
 
$worker->addFunction(‘get_sequence’, function ($job) {
    // decode input
    $content = $job->workload();
    $data = json_decode($content, true);
 
    // calculate sequence and return result
    $rows = fibonacci($data);
    return json_encode($rows);
});

И, конечно же, не забудьте обернуть свой ответ в формате JSON. Последнее, что нужно сделать, — это зациклить рабочий скрипт, чтобы использовать его много раз без перезапуска:

1
2
3
4
5
<?php
 
for ($i = 0; $i < 100; ++$i) {
    $worker->work();
}

Мы можем запустить рабочий скрипт в фоновом режиме:

1
php /vagrant/tuts-gearman-supervisor/code/worker.php &

В этот момент вы, возможно, уже заметили, что клиентский скрипт закончил свою работу и написал что-то вроде этого:

1
2
3
4
5
6
vagrant@localserver:~$ /vagrant/tuts-gearman-supervisor/code/client.php
1, 2, 3
2, 3, 5
3, 5, 8
5, 8, 13
8, 13, 21

Наконец, у нас работает рабочий, поэтому мы можем проверить статус еще раз:

1
2
3
4
5
vagrant@localserver:~$ gearadmin —status
get_sequence 0 1 2
vagrant@localserver:~$ ps -aux |
root 4595 0.0 1.5 98928 7764 ?
root 4596 0.0 1.5 98928 7764 ?

В каждой строке есть имя функции и три числа: количество задач в очереди (0), количество запущенных заданий (1) и количество способных работников (2).

Конечно, чтобы добавить больше рабочих, вы можете запустить больше рабочих сценариев. Чтобы остановить каждого из них, вы можете использовать killall . Но есть отличный инструмент для управления работниками, который называется Supervisor.

Как сказано в руководстве:

Supervisor — это клиент-серверная система, которая позволяет пользователям отслеживать и контролировать ряд процессов в UNIX-подобных операционных системах.

Давайте установим его и создадим основной файл конфигурации:

1
2
sudo apt-get install supervisor
sudo nano /etc/supervisor/conf.d/supervisor.conf

В открывшемся редакторе мы создадим базовую конфигурацию для работника Gearman:

1
2
3
4
5
6
[program:gearman-worker]
command=php /vagrant/tuts-gearman-supervisor/code/worker.php
autostart=true
autorestart=true
numprocs=3
process_name=gearman-worker-%(process_num)s

Это скажет Supervisor, что рабочий должен работать в трех процессах и перезапускаться после завершения. Теперь сохраните файл конфигурации, перезагрузите Supervisor и проверьте состояние запущенных процессов:

1
2
3
4
5
6
vagrant@localserver:~$ sudo supervisorctl reload
Restarted supervisord
vagrant@localserver:~$ sudo supervisorctl status
gearman-worker:gearman-worker-0 RUNNING pid 4596, uptime 0:01:03
gearman-worker:gearman-worker-1 RUNNING pid 4595, uptime 0:01:03
gearman-worker:gearman-worker-2 RUNNING pid 4597, uptime 0:01:03

Мы видим трех рабочих, готовых работать по клиентским сценариям.

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

  • Добавьте некоторый рабочий процесс в фоновом режиме, например, отправив электронное письмо.
  • Поиграйте с приоритетами задач используя GearmanClient :: doHigh .
  • Блокировка данных с использованием GearmanJob :: sendData , которая может быть полезна в случае длинных задач, которые можно наблюдать в строке состояния.

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

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