Команда распределяет автотесты по нескольким CI-агентам, но общее время прогона почти не сокращается из-за неравномерной длительности наборов. Какой механизм балансировки следует применить?
Следует применить динамическое распределение тестов, или динамический шардинг: CI назначает следующий тест свободному агенту, ориентируясь на ожидаемую длительность, обычно рассчитанную по истории запусков. Это уменьшает простой агентов и сокращает время завершения всего прогона по сравнению со статическим делением на фиксированные группы.
Параллельный запуск появился как способ сократить длительность регрессионных проверок без уменьшения их объёма. Однако простое деление тестов на равные по количеству группы не гарантирует равное время работы: один тест может выполняться миллисекунды, другой — минуты.
Поэтому системы CI и тестовые раннеры стали использовать шардинг — разделение набора на части. Более развитый вариант учитывает фактическую длительность тестов и перераспределяет работу так, чтобы агенты завершали её примерно одновременно.
При статическом распределении агентам заранее назначают фиксированные группы тестов. Если в одной группе окажутся долгие end-to-end-сценарии, её агент будет работать дольше остальных, а завершение пайплайна будет ждать именно его.
Добавление новых агентов в такой схеме может почти не дать выигрыша: свободные агенты завершат работу раньше, но критический путь останется у самого медленного. Неверная оценка также приводит к нестабильному времени CI и затрудняет планирование обратной связи для разработчиков.
Нужно собирать длительность успешных и упавших тестов по отдельности, связывая её с устойчивым идентификатором теста. Перед запуском система оценивает стоимость каждого теста, сортирует тесты от самых долгих к самым коротким и распределяет их по агентам так, чтобы суммарная ожидаемая нагрузка была близкой.
Практически это может работать в двух режимах. При предварительном шардировании каждый агент получает рассчитанный набор до начала выполнения. При динамической очереди агенты последовательно забирают тесты или небольшие группы тестов из общей очереди; такой вариант лучше компенсирует ошибки прогноза.
Для эффективного балансирования размер группы должен быть компромиссом. Слишком крупные группы уменьшают накладные расходы, но ухудшают равномерность; слишком мелкие повышают стоимость планирования, передачи окружения и публикации результатов.
Исторические данные нужно регулярно обновлять: длительность меняется после оптимизации тестов, изменения окружения и появления новых сценариев. Для новых тестов без статистики применяют консервативную оценку, например среднее значение для аналогичного типа тестов, а затем заменяют её фактическими измерениями.
Балансировка не отменяет требований к изоляции тестов. Если тесты используют общие ресурсы, динамическое распределение может выявить гонки или конфликты; это не следует маскировать повторными запусками. Также необходимо учитывать ограничения лицензий, доступность браузеров, баз данных и других ресурсов, иначе арифметически равные группы не будут реально равными по времени.
Главный критерий качества — время критического пути, то есть от старта первого агента до завершения последнего, а не средняя длительность отдельного агента. Метрики полезно дополнять долей простоя агентов и разбросом времени между самым быстрым и самым медленным шардом.
Регрессионный набор из 240 тестов запускался на восьми агентах. Команда распределяла тесты по количеству: по 30 в каждый шард. Однако два шарда содержали большинство браузерных сценариев и выполнялись около 25 минут, тогда как остальные завершались за 10–14 минут.
Рассматривались два варианта. Увеличение числа агентов было простым, но почти не меняло время: новые агенты простаивали, пока завершались самые долгие шарды. Ручное перемещение тестов уменьшало перекос, но требовало постоянного сопровождения и быстро устаревало после изменений набора.
Выбрали динамический шардинг с историческими длительностями и небольшими группами тестов. После нескольких прогонов оценки стабилизировались, время критического пути снизилось примерно до 14–16 минут, а добавление новых сценариев перестало требовать ручного перераспределения.
Команда отдельно отслеживала тесты с резко меняющейся длительностью. Их не использовали как единственную основу для балансировки: вариативность могла указывать на проблемы окружения, ожиданий или самого теста.
Нет. Количество тестов — лишь косвенный показатель нагрузки. Тесты могут сильно различаться по числу сетевых обращений, длительности ожиданий, объёму данных и используемым ресурсам. Для балансировки важнее ожидаемая стоимость выполнения, а число тестов можно использовать только как запасной критерий при отсутствии статистики.
Он уменьшает дисбаланс работы между агентами, но не сокращает время каждого теста и не устраняет последовательные этапы пайплайна. Дополнительными ограничениями остаются подготовка окружения, загрузка зависимостей, публикация отчётов и дефицит внешних ресурсов. Если узким местом является одна общая база или ограниченный пул браузеров, добавление шардов может даже увеличить конкуренцию и ухудшить результат.
Одного среднего значения недостаточно: оно скрывает редкие, но дорогие запуски. Следует хранить не только среднюю длительность, но и показатели разброса или использовать более консервативную оценку, например высокий перцентиль. Одновременно нужно исследовать причину вариативности — нестабильную сеть, внешнюю зависимость, чрезмерные ожидания или конфликт ресурсов; балансировщик не должен превращаться в способ скрыть дефект теста.