Снижаем Нагрузку на CPU при Использовании GitHub Actions
Если вы используете GitHub Actions на собственных серверах, вы могли заметить, что они могут быть удивительно ресурсоемкими для ЦП, даже в режиме ожидания. При более внимательном рассмотрении становится ясно, что один раннер может загружать CPU на 100%. Это не ошибка в вашем рабочем процессе; это преднамеренное проектное решение в механизме сна раннера.
Проблема: «Занятое ожидание»
Вместо использования стандартных, эффективных функций сна, предоставляемых операционной системой, раннер GitHub Actions использует цикл «занятого ожидания» (Busy-waiting). Это означает, что он постоянно проверяет системные часы в плотном цикле, ожидая истечения заданного промежутка времени. Хотя такой подход обеспечивает совместимость в широком диапазоне сред, включая некоторые без традиционных функций сна, он крайне неэффективен для подавляющего большинства систем, таких как стандартные виртуальные машины Linux или Windows. Эта постоянная проверка поддерживает полную активность CPU, что приводит к нерациональному использованию ресурсов, повышению температуры и потенциальному снижению производительности других задач на той же машине.
Решение: интеллектуальный скрипт установки режима сна
К счастью, мы можем решить эту проблему, заменив стандартный скрипт установки режима сна на более интеллектуальную версию. Цель — использовать наиболее эффективный метод установки режима сна, доступный в системе. Вот скрипт, который отдаёт приоритет стандартным командам установки режима сна и предоставляет резервные варианты, обеспечивая как эффективность, так и совместимость.
Перейдите в папку, где установлен ваш раннер, и отредактируйте файл safe_sleep.sh. Замените его содержимое следующим:
#!/bin/bash
# Используем нативную команду 'sleep', если доступна (наиболее эффективно)
if [ -x "$(command -v sleep)" ]; then
sleep $1
exit 0
fi
# Пробуем 'read' с таймаутом (встроено в bash)
if [[ -n "$BASH_VERSINFO" && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
read -rt "$1" <> <(:) || :
exit 0
fi
# Креативный вариант с 'ping'
if [ -x "$(command -v ping)" ]; then
ping -c $1 127.0.0.1 > /dev/null
exit 0
fi
# Оригинальное «занятое ожидание» (в крайнем случае)
SECONDS=0
while [[ $SECONDS != $1 ]]; do
:
done
Этот скрипт сначала пытается использовать стандартную команду
sleep. Если она недоступна, он пытается использовать read с таймаутом, что является встроенной функцией оболочки и всё ещё эффективнее, чем ожидание в активном режиме. В качестве запасного варианта используется ping. Только если ни один из этих вариантов недоступен, скрипт возвращается к исходному циклу «занятого ожидания».Предупреждение:
Средства запуска GitHub Actions могут обновляться автоматически. При обновлении ваши изменения в файле safe_sleep.sh могут быть перезаписаны. Чтобы гарантировать сохранение исправления, вы можете настроить задание cron или запланированную задачу для периодического повторного применения этого изменения.
Дополнительные ресурсы
Для получения более подробной технической информации и обсуждения этой темы в сообществе вы можете обратиться к этим проблемам и пул-реквестам на GitHub:
- https://github.com/actions/runner/issues/2380
- https://github.com/actions/runner/issues/3792
- https://github.com/actions/runner/pull/3870
Источник: https://www.meziantou.net/reduce-github-actions-runner-cpu-usage.htm