# Распределённая сборка на кластере Distbuild

Для быстрой сборки больших проектов можно использовать кластер распределённой сборки *Distbuild*. 

Бóльшая часть опций сборки не зависят от того, где она исполняется, и описаны на [общей странице](./index.md)

Однако распределённая сборка имеет ряд особенностей, к которым относятся:

- [Ограничения распределённой сборки](#limitations)
- [Локальное конфигурирование и подготовка данных](#local)
- [Подвоз результатов и кэширование](#results)
- [Квотирование вычислительных ресурсов](#quotas)
- [`ya make --dist` и CI](#autocheck)

## Ограничения распределённой сборки { #limitations }


1. Для больших проектов может потребоваться skynet (который сейчас работает только под Linux): он используется для отправки [локального образа Аркадии](#local) на кластер Distbuild.
1. Не получится собрать целую Аркадию или даже половину Аркадии, т. к. есть лимит на количество файлов в отправляемом образе, но лимита более чем достаточно для сборки любого, даже весьма большого проекта.
1. Если сборка не герметична по зависимостям, она сломается в Distbuild: ей не хватит файлов из-за того, что набор файлов [готовится локально](#local) на базе сборочного графа.
1. Не поддерживается `arcadia_tests_data` и не будет поддерживаться никогда.
1. Скачивание результатов сборки может занять существенное время, особенно в случае больших бинарных файлов (по умолчанию скачивание выключено, [используйте ключ -E](#results)).
1. Время выполнения любого узла сборочного графа на кластере ограничено 15 минутами, поэтому тесты с бóльшим таймаутом запускать бесполезно.
1. Узлу графа во время выполнения предоставляется ограниченное количество [вычислительных ресурсов](https://docs.yandex-team.ru/distbuild/limits#compute), пропускной способности [дисков](https://docs.yandex-team.ru/distbuild/limits#io_throttling) и по умолчанию не предоставляется [доступ в сеть](https://docs.yandex-team.ru/distbuild/limits#network).


## Локальная подготовка к распределённой сборке { #local }

При локальном запуске сборки на кластере распределённой сборки `ya make --dist` часть работы выполняется локально.

В качестве источника данных используется локальное рабочее пространство. Все изменения, сделанные в нём (новые, закоммиченные локально, либо запушенные в ветку на сервер), будут учтены. 
В режиме [селективного чекаута](local.md#selective_co) все необходимые файлы будут получены в локальную рабочую копию.

На кластере Distbuild для подготовки рабочего пространства не используется
информация vcs из локального пространства. Вместо этого на кластер отправляются сами необходимые файлы, а информация от vcs используется для включения номера ревизии в код. Таким образом,
сборка выполняется на частичном образе Аркадии без vcs.

Это возможно благодаря следующему процессу:

- На основе локального рабочего пространства делается [конфигурирование](../../general/base_concepts.md#conf) и строится сборочный граф. Этот сборочный граф правильно учитывает сборочную платформу
  Distbuild (всегда Linux). Целевая платформа определяется [обычным образом](index.md#defaults).

- При построении сборочного графа дополнительно собирается информация обо всех файловых зависимостях, необходимых для исполнения графа.

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

  {% note alert %}

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

  {% endnote %}

- Образ передаётся на кластер Distbuild по специальному протоколу, который включает:

  - Проверку файлов на наличие в Distbuild (чтобы не передавать одно и то же два раза);
  - При небольшом количестве изменений передачу tar-архива с недостающими файлами.
  - При большом количестве изменений - передачу tar-архива через skynet.

- Локально построенный сборочный граф отправляется для исполнения на кластер Distbuild. Локальный процесс `ya make` мониторит исполнение и забирает результаты по мере их появления.

{% note alert %}

Всё написанное выше относится к локальному запуску сборки на кластере распределённой сборки `ya make --dist`. У кластера Distbuild есть собственная подсистема работы с vcs
и она поддерживает запуски поверх заданных ревизий vcs. Система сборки, в свою очередь, умеет запускать конфигурирования поверх таких ревизий напрямую в Distbuild.
Однако это всё считается специальными режимами работы, требующими аккуратного обращения, и потому используется только в автоматизированных сценариях devtools.
Если вам кажется, что ваш сценарий требует такой работы и его не покрывают автосборка для CI и Sandbox-задача YA_MAKE, обратитесь в [поддержку devtools](https://st.yandex-team.ru/createTicket?queue=DEVTOOLSSUPPORT).

{% endnote %}


## Получение и кэширование результатов { #results }

По умолчанию при распределённой сборке результаты не скачиваются на локальную машину, о чём система сборки честно предупреждает. Такое поведение полезно, если хочется просто проверить собираемость
кода или протестировать его. `ya make --dist -t` запустит не только сборку, но и тесты.

Чтобы получить результаты сборки локально, необходимо использовать ключ `-E`. По мере готовности результаты будут скачиваться с кластера и складываться в [локальный сборочный кэш](./local_ya_cache.md),
а оттуда [стандартными механизмами системы сборки](./index.md#results) попадать символьными ссылками в рабочую копию и хардликаться или копироваться в результирующую директорию, 
если задан параметр `--output`.

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

{% note info "UID-ы в локальной и распределённой сборке" %}

Кластер распределённой сборки полностью построен на Linux, соответственно, сборочная платформа там всегда Linux, а целевая может быть любой из длинного списка доступных. Чтобы UID-ы локальной и
распределённой сборки совпали, необходимо, чтобы в обоих случаях использовались одни и те же инструменты (по модулю сборочной платформы). Это свойство безусловно выполнено, если локальная сборочная
платформа - Linux. Кроме того, это свойство выполнено при сборке под macOS с macOS и Linux. Однако при сборке с macOS под целевую платформу Linux это не выполняется: такая сборка
использует линкер, отличный от такового на сборочной платформе Linux. Для целевой платформы Windows также не гарантируется совпадение UID-ов со сборочной платформой Linux в силу существенной
разницы в используемых инструментах.

{% endnote %}

Гарантию совпадения UID-ов в вышеперечисленных случаях можно использовать, чтобы с помощью распределённой сборки прогревать локальный кэш: например, после обновления рабочего пространства запускать большую пересборку распределённо с подвозом промежуточных результатов, а последующие сборки в процессе работы над кодом делать локально.

### Какие результаты кэшировать? { #localcacheheating }

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

- Используйте `--add-result .a` для кэширования библиотек и `--add-result .o` для кэширования объектных файлов.
- Используйте `--no-output-for .o`, чтобы избежать замусоривания рабочей копии или выходной директории ссылками на объектные файлы, либо `--no-src-links`, чтобы прогреть кэш вообще без получения ссылок.
- Используйте `--all-outputs-to-result`, чтобы кэшировались результаты сборочных команд, а не узлов фильтрации.
  
  Если у сборочной команды есть несколько результатов и `--add-result <.suff>` выбирает только один из них,
  то система сборки вставляет промежуточный *узел фильтрации*, чтобы выбрать только нужный файл. У такого узла свой UID, не совпадающий с UID сборочной команды, и результат будет закэширован именно для него, что приведёт
  к невозможности его переиспользования последующими сборками. `--all-outputs-to-result` привозит все результаты узла, если хоть один из них удовлетворяет `--add-result <.suff>`, и кэширует их с реальным UID-ом сборочной
  команды.

{% endnote %}

## Квотирование вычислительных ресурсов { #quotas }

По умолчанию пользовательские запуски `ya make --dist`, а также запуски из Sandbox задач выполняются в пуле `users/public` в порядке очереди по времени запуска билдов (FIFO). При этом существует возможность заказать ресуры для собственного выделенного пула. Подробнее о квотировании можно прочесть [здесь](https://docs.yandex-team.ru/distbuild/quoting).

## Как связаны распределённая сборка и CI { #autocheck }

Автосборка (CI Аркадии) исполняется в DistBuild. Но не вся, а только стадии Configure, Build, Small и Medium tests.

Часто возникает вопрос: как скачать результаты CI-сборок, ведь они уже сформированы? К сожалению, такой возможности сейчас нет и на то есть ряд причин:

1. Артефакты сборок CI не очень применимы локально, даже для пользовательских тестовых стендов. Целевые платформы CI достаточно специфические, они проектируются с учётом необходимости удерживать на приемлемом уровне порождаемую Автосборкой нагрузку на кластер DistBuild. 

   Например, основная целевая Linux-конфигурация в CI — это:

   - `--build relwithdebinfo` - релизная сборка с ассёртами для баланса между скоростью и информативностью,
   - `-DDEBUG_INFO_LINES_ONLY` - урезанный объём отладочной информации для уменьшения объёма программ/тестов,
   - `-DUSE_LIBEATMYDATA` - использование специальной библиотеки, отключающей `fsync()` в коде на C/C++ для снижения IO-нагрузки на сервера.

2. Пользовательская распределённая сборка (`ya make--dist`) -- гораздо менее контролируема и технически пользователи могут *отравить* UID-ы сборочных узлов. Автосборка для CI не должна от этого страдать и
   потому кэши на кластере distbuild для пользовательских сборок и автосборки CI разделены.

3. Кэш distbuild UID-адресуемый, и чтобы добыть из него что-то нужен именно UID, а не имя артефакта + ревизия.

4. DistBuild не даёт гарантий на время хранения артефактов. Автосборка CI выполняет очень много сборок, тысячи в час, генерируя огромные объёмы артефактов (промежуточных и финальных). Эти артефакты кэшируются для использования в текущей и последующих сборках, но всё равно живут недолго, даже
   несмотря на огромные объёмы кэшей. Особенно это относится к финальным артефактам - программам и тестам: они редко нужны в силу финальности и часто меняются в силу замыкания
   своих зависимостей.

Если вам необходимо воспроизвести и расследовать падение теста в CI, попробуйте запустить его на DistBuild с `ya make --dist -t -Е`. Проблемы упущенных файловых зависимостей можно воспроизвести локально в режиме [сторогого контроля зависимостей](../../general/base_concepts.md#exec) (`--sandboxing`).

## Как ускорить локальную сборку? 
- В релизных процессах мы рекомендуем использовать [yt-кэш](./yt_store.md) при [сборке в Sandbox](../sandbox/ya_make.md).
- В локальной разработке - либо [yt-кэш](./yt_store.md), либо распределённую сборку (с [локальным кэшированием](#localcacheheating)) для потенциально больших пересборок + локальную сборку в остальные моменты.
