Symfony Messenger + systemd

Symfony Messenger Systemd

10 Января 2022 | Symfony

В этой статье мы рассмотрим, как правильно использовать systemd для запуска воркеров Symfony Messenger.

Symfony Messenger + systemd

Что такое Symfony Messenger и systemd?

Документация Symfony говорит:

Компонент Messenger помогает приложениям отправлять и получать сообщения в/из других приложений или через очереди сообщений.

Конкретно, наша инфраструктура должна иметь постоянных работников для получения и обработки сообщений. Этими работниками должен управлять сервис-менеджер.

Сайт systemd говорит:

systemd — это набор основных строительных блоков для системы Linux. Он предоставляет диспетчер системы и служб, который работает как PID 1 и запускает остальную часть системы.

systemd — это диспетчер служб по умолчанию для всех ОС на основе Debian, который очень популярен среди серверов, используемых для размещения веб-приложений.

В systemd «сервис» — это своего рода «юнит». Есть много других видов юнитов , но здесь нам нужен только «сервис».

 

Как использовать systemd для управления воркерами?

systemd ищет служебные файлы во многих каталогах:

  • /etc/systemd/system/ для системных блоков (или служб) , созданных администратором сервера (созданный означает, что администратор является автором системного блока);
  • /usr/local/lib/systemd/system/ для системных блоков (или служб) , установленных администратором сервера (установлено означает, что администратор не является автором системного блока);
  • /lib/systemd/system/ для системных модулей (или служб) , установленных менеджером пакетов дистрибутива.

В зависимости от роли, которую вы играете на своих серверах, вы будете записывать файлы рабочих служб в /etc/systemd/system/ формате /usr/local/lib/systemd/system/ . Чтобы узнать больше о расположении сервисов, обратитесь к документации systemd .

Вот пример сервиса для запуска воркера Symfony Messenger:

some_worker.service

[Unit]
StartLimitIntervalSec=20s
StartLimitBurst=5

[Service]
ExecStart=/usr/bin/php -d memory_limit=-1 /home/app/bin/console messenger:consume transport_name --memory-limit=512m --env=prod
Restart=always
RestartSec=1
TimeoutSec=300
User=app

[Install]
WantedBy=multi-user.target

Давайте разберем этот файл, чтобы понять каждую директиву:

  • [Unit] : Раздел, используемый для настройки устройства:
    • StartLimitIntervalSec : интервал, в течение которого разрешено количество запусков службы. Количество пусков настраивается StartLimitBurst параметром;
    • StartLimitBurst : разрешенное количество пусков в течение StartLimitIntervalSec интервала.

документация systemd говорит:

Настройте ограничение скорости запуска юнита. Устройства, которые запускаются чаще, чем раз в течение интервала времени, больше не могут запускаться. Используйте StartLimitIntervalSec= для настройки интервала проверки и StartLimitBurst= для настройки разрешенного количества запусков за интервал.

Мы используем эти параметры в сочетании с RestartSec, чтобы избежать сжигания ЦП при сбое рабочего процесса во время его инициализации. Так система будет ждать 1 секунду перед перезагрузкой воркера, и если он слишком часто перезагружается (значит он действительно сломан, и перезагружать его больше бесполезно) мы его останавливаем.

Конечно, у вас должна быть система мониторинга, такая как Datadog, которая предупреждает вас, если служба не работает, и вы должны исправить это как можно скорее.

  • [Service] : Раздел, используемый для настройки сервиса:

    • ExecStart : Здесь вы будете писать свою команду Symfony для использования сообщений;
    • Restart : Настраивает, должна ли служба быть перезапущена, когда процесс службы завершается, завершается или истечет время ожидания;
    • RestartSec : время перехода в спящий режим перед перезапуском службы в секундах (или промежуток времени, например, «3 минуты 42 секунды»). По умолчанию 100 мс;
    • TimeoutSec : время, которое система должна ожидать, пока служба не запустится или не остановится. Если время ожидания истекло до запуска службы, она будет считаться неудачной. Если время ожидания истекло до того, как служба остановилась, она будет остановлена SIGTERM . Мы установили здесь большое значение, чтобы справиться со случаем, когда обработка сообщения занимает много времени, поэтому избегайте того, чтобы systemd завершал процесс до окончания обработки сообщения;
    • User : Пользователь, который будет выполнять команду.
  • [Install] : этот раздел используется enable и disable команды systemctl которого позволяют вам управлять установленными службами в вашей системе:

    • WantedBy : Позволяет определить зависимые службы от текущей.

 

Запуск службы

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

$ systemctl start some_worker.service

Эта команда запустит службу с именем some_worker.service . Предположим, что эта служба находится в /etc/systemd/system/some_worker.service .

Расширение «.service» не является обязательным, но полезно для быстрого распознавания сервисов среди других файлов.

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

$ systemctl enable some_worker.service

Это все! Теперь у вас есть фоновый сервис, который будет обрабатывать ваши сообщения Symfony Messenger и автоматически перезапускаться . Это очень приятно, потому что хорошая практика запуска воркеров Symfony Messenger заключается в том, чтобы время от времени убивать их, используя три варианта:

  • --limit=10 выйти после 10 сообщений;
  • --memory-limit=128M выйти, когда память достигает 128 МБ;
  • --time-limit=3600 выйти через час.

Цель состоит в том, чтобы избежать утечки памяти, закрытого соединения с базой данных, тайм-аута сокета…

Посмотреть состояние сервисов можно status командой:

$ systemctl status some_worker.service
● some_worker.service
     Loaded: loaded (/etc/systemd/system/some_worker.service; disabled; vendor preset: disabled)
     Active: active (running) since Wed 2021-12-22 20:58:00 CET; 14h ago
    Process: 2288289 ExecStart=/usr/bin/php -d memory_limit=-1 /home/app/bin/console messenger:consume transport_name --memory-limit=512m --env=prod
   Main PID: 2288289 (code=exited, status=1/FAILURE)
        Memory: 7.9M
        CPU: 1.587s

Этот вывод показывает некоторые данные об услуге, среди которых:

  • время безотказной работы сервиса (14ч);
  • статус (работает);
  • используемая память (7,9 МБ);
  • PID (2288289).

 

Как запустить несколько экземпляров одного воркера?

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

Учитывая some_worker@.service , что это ваш шаблон службы, обратите внимание на @ перед расширением. Он будет содержать все о вашей службе, затем вы можете создать столько служб, сколько хотите, запустив службу, названную по этому шаблону:

$ systemctl enable some_worker@{IDENTIFIER}.service

Здесь {IDENTIFIER} рассматривается как аргумент экземпляра службы. Это может быть просто целое число или любая строка.

При необходимости этот аргумент доступен в служебном файле через %i (экранированная версия) или %I (необработанная версия, неэкранированная). Его следует использовать, например, для установки описания службы или для того, чтобы сделать что-то динамичным в команде экземпляра службы.

ProTips©: В большинстве случаев нет необходимости создавать больше экземпляров службы, чем число логических ядер ЦП на машине. Процессы будут распределены между всеми ядрами, поэтому, если у вас больше экземпляров службы, чем ядер, некоторым ядрам придется управлять многими экземплярами службы одновременно.

 

Управление службами с помощью glob

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

Чтобы запустить все экземпляры службы шаблона, давайте использовать systemctl с glob :

$ systemctl start "dummy_worker@*.service" --all

Обратите внимание на --all то, что start  команде необходимо обязательно загрузить и запустить все модули (особенно если ваша служба зависит от других служб, которые на самом деле не загружены в glob или уже запущены).

Чтобы остановить все экземпляры службы, вы также можете использовать glob:

$ systemctl stop "dummy_worker@*.service"

В этой опции нет необходимости --all , потому что systemd остановит только экземпляр, соответствующий глобусу, а не их зависимости.

 

Логи

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

По умолчанию systemd записывает все в journalctl . Вы можете отслеживать журналы вашего сервиса, используя:

$ journalctl -xfeu some_worker
  • -x : означает «расширенный», это дает вам больше информации о вашем сервисе;
  • -f : как и команда -f of tail , следует за новыми строками добавления в файле;
  • -e : показывает конец файла, а не начало, очень полезно, если ваш сервис работает в течение длительного времени;
  • -u : позволяет уточнить название логотипов юнитов, которые вы хотите отобразить.

Но если вам нужно записать журналы в файл, вы можете изменить службу с помощью:

[Service]
...
StandardOutput=append:/path/to/log.log
StandardError=append:/path/to/error_log.log

Убедитесь, что целевой каталог журналов существует, systemd не создаст его для вас.

 

Удалить правильно службу

Чтобы удалить службу, необходимо выполнить 4 шага:

1: остановить службу

Чтобы остановить службу, используйте systemctl инструмент и его stop команду:

$ systemctl stop some_worker.service

2: отключить службу

Отключение службы означает, что система не будет пытаться автоматически запускать ее при загрузке. Воспользуемся disable командой:

$ systemctl disable some_worker.service

3: удалить службу

Следующий шаг, удаление службы. И на этот раз не с помощью systemctl команды, а очень просто rm :

$ rm /etc/systemd/system/some_worker.service

Наконец, последний шаг — перезагрузить демона systemd, чтобы он знал, что этот сервис удален. Это не повлияет на запущенные службы.

$ systemctl deamon-reload

 

Вывод

Поскольку он был разработан для управления службами ОС, systemd может предложить вам множество других функций. Его главное преимущество для нас в контексте Symfony Messenger заключается в том, что он установлен по умолчанию на популярных серверных ОС, поэтому нет необходимости устанавливать другой менеджер процессов, такой как Supervisord (который тоже является отличным инструментом!).

Комментарии
Если у вас есть вопросы, не стесняйтесь оставлять комментарии ниже.
Загрузка комментариев...