Для удалённой сборки на Mac mini M4 в 2026 году узкими местами остаются не только CPU, но и пиковая RAM под параллельные компиляторы, поток записи в Derived Data и согласованность региона узла с вашим Git-оркестратором. Ниже — компактная матрица решений: соотношение xcodebuild -jobs и памяти, вынос DerivedData на внешний SSD с параметрами APFS, ориентиры по I/O и «охлаждению» очереди, плюс выбор между Токио, Сеулом, Гонконгом, Сингапуром и западом США. В конце статьи — кнопки на выбор узла, справку и главную страницу сайта.
Параллельная компиляция и пики памяти
Флаг -jobs N в xcodebuild задаёт число одновременных задач компиляции/линковки. На Apple Silicon каждый «жоб» — не константа по памяти: Swift и Clang могут кратковременно выбивать гигабайты RAM на модуль, особенно при whole-module оптимизации и крупных таргетах. На арендованном удалённом Mac нет смысла выкручивать N до числа ядер, если одновременно крутятся симуляторы, SPM-резолверы или скрипты post-build.
Стартовая эвристика: держите запас 4–8 ГБ под систему, демоны и файловый кеш; остальное делите на оценку «тяжести» проекта. Ниже — ориентирная таблица для типичного iOS-приложения среднего размера без экстремальных макросов генерации кода (ваши фактические пики снимайте через Activity Monitor или memory_pressure).
| Объём RAM узла | Стартовый -jobs (только сборка) |
Сборка + один Simulator / тесты | Сигнал перегруза |
|---|---|---|---|
| M4, 16 ГБ | 3–5 | 2–3 | Свап > 0, заметные паузы UI по SSH, код 137/oom в логе агента |
| M4, 24 ГБ | 5–8 | 3–5 | Рост «Memory pressure» жёлтый/красный дольше минуты, таймауты линковки |
В CI зафиксируйте -jobs в переменной окружения и понижайте её на ночных «тяжёлых» ветках. Для нескольких схем подряд предпочтительнее последовательные этапы с разными квотами, чем один гигантский параллельный шаг. Подробнее о регионах и пакетных очередях см. материал о задержке узлов и TCO аренды.
Derived Data: внешний путь и права
Внутренний SSD арендного Mac быстро заполняется инкрементальными артефактами Xcode. Вынесение Derived Data на внешний SSD (USB4/Thunderbolt, где доступно) разгружает системный том и упрощает политику ретенции: один скрипт чистит старые SHA, не трогая пользовательские данные.
Монтирование: подключите диск, отформатируйте под macOS как APFS, схема разделов GUID. В Дисковой утилите имя тома лучше задать предсказуемым (XcodeDerived), чтобы в CI не ломать путь при переподключении.
| Параметр | Рекомендация | Зачем |
|---|---|---|
| Файловая система | APFS (отдельный контейнер) | Снимки и предсказуемая работа с мелкими файлами Xcode |
| Регистр имён | APFS по умолчанию (без учёта регистра) — ок для большинства проектов | Меньше сюрпризов с CocoaPods/старыми скриптами; case-sensitive только при явной необходимости |
| Шифрование | FileVault на системном томе; для внешнего — по политике арендодателя | Баланс безопасности и возможности автомонтажа без GUI |
| Путь для Xcode | IDECustomDerivedDataLocation или -derivedDataPath | Явный каталог на внешнем томе, одинаковый в IDE и в xcodebuild |
Права: каталог Derived Data должен принадлежать пользователю, под которым крутится агент (часто отдельная учётная запись CI). Проверьте, что внешний том смонтирован до старта launchd-джоба или шага пайплайна; иначе Xcode создаст данные на локальном диске и вы потеряете кеш при следующем прогоне. Первичный доступ к машине и разделение SSH/VNC описаны в руководстве по первой настройке аренды.
I/O-квоты и пороги «охлаждения»
Даже быстрый внешний NVMe упирается в сатурацию по мелким файлам: тысячи объектных файлов и индексов модулей Swift дают высокий random write. На удалённом узле добавляется конкуренция с фоновыми процессами и snapshot-политикой APFS.
Введите явные пороги охлаждения в оркестраторе: если средняя задержка диска (например, по fs_usage или счётчикам хостинга) держится выше комфортного плато или свободное место на томе Derived Data падает ниже 15%, автоматически снижайте -jobs, откладывайте второстепенные таргеты или запускайте «чистую» сборку в окно низкой нагрузки.
Матрица действий:
- Высокий random I/O, CPU не загружен: уменьшить
-jobs, включить инкрементальные схемы, проверить антивирус/индексацию на томе. - Мало места: ротация Derived Data по веткам, хранение архивов
.xcarchiveв объектном хранилище, не на узле. - Троттлинг по температуре/питанию: реже на M4 в дата-центровых сценариях, но при длительных линковках держите вентиляцию; при повторяющихся таймаутах разнесите тяжёлые таргеты во времени.
Япония, Корея, Гонконг, Сингапур vs запад США: как выбрать узел
Регион влияет не на скорость компилятора внутри SoC, а на round-trip до Git, реестра пакетов, CDN с Xcode/SDK и артефактов CI. Командам из Азии обычно выгоднее Токио, Сеул, Гонконг или Сингапур; командам из Северной Америки — запад США, если большая часть трафика идёт в US-West endpoints.
| Направление | Типичный диапазон RTT | Заметный эффект для Xcode |
|---|---|---|
| Внутри одной агломерации (SG↔SG) | < 5 мс | Минимальные паузы git/SPM; комфортный remote edit |
| APAC ↔ APAC (напр. JP↔SG) | 30–80 мс | Приемлемо для batch CI; интерактивный VNC тяжелее |
| APAC ↔ US West | 120–200+ мс | Частые fetch и мелкие API-вызовы ощутимо дороже; кешируйте зависимости на узле |
Стоимость аренды: ориентиры каталога MacCompute для постоянной нагрузки — M4 16 ГБ около $102.9/мес, M4 24 ГБ около $202.9/мес; посуточный тариф удобен для коротких спайков (точные суммы — в тарифах). Правило из соседнего гайда: если узел нужен дольше ~5 полных дней в месяце на конфигурации 16 ГБ, помесячный план чаще выходит предсказуемее по бюджету.
FAQ: сбои, повторы и устойчивость пайплайна
Сборка упала с «Killed» или кодом 137. Снизьте -jobs, отключите параллельные тесты в том же шаге, проверьте лимиты cgroups/launchd, если хостинг их задаёт.
«Could not write to the sandbox» / ошибки Derived Data после ребута. Том не смонтирован или сменилась буква пути — добавьте проверку diskutil info и явный mount в pre-job.
Нестабильные повторы из сети. Экспоненциальный бэкофф для git и SPM, зеркало зависимостей в регионе узла, артефакты в ближайшем bucket.
Нужно ли два узла в разных городах? Да, если SLA требует резервирования или A/B регионов; синхронизируйте только минимальный кеш, остальное — из реестра.