2026: глобальные команды — управление кэшем сборки iOS: Xcode Derived Data и зависимости — одна зона или региональные физические Mac?
Глобальные iOS-команды колеблются между «один авторитетный кэш + трансрегиональная синхронизация» и «локальные кэши на физических Mac в каждом регионе». Здесь — выравнивание задержки, консистентности и стоимости по порогам для согласования: две матрицы, семь шагов выкатки, готовые фрагменты rsync и переменных окружения, FAQ.
Кому больно: когда глобальные команды переиспользуют Xcode Derived Data и кэши SPM/CocoaPods между CI и удалёнными физическими Mac, трансокеанское восстановление кэша раздувает P95 времени сборки, а дрейф кэша даёт спорадические ошибки линковки. Вывод: не связывайте низкооборотные read-only кэши зависимостей с той же политикой репликации, что и высокочастотный Derived Data; выбирайте одну зону или колокацию по матрице порогов. Что внутри: две таблицы, семь шагов, готовые команды, FAQ.
1. Боли и скрытые издержки
- «Шторм мелких файлов»: Derived Data содержит огромное число крошечных файлов и индексов. Трансрегиональный rsync или листинг метаданных в объектном хранилище часто съедает полезную пропускную способность — джобы висят на «Restore cache», а не на компиляции.
- Консистентность важнее «последней ночной сборки»: смесь патч-версий Xcode, Swift toolchains, модульных кэшей и индексов даёт флейки инкремента. Нужны проверяемые content-addressed ключи. Для базовой линии RTT см. мультирегиональную приёмку удалённого физического Mac: SLO по RTT, джиттеру и потерям пакетов; для контекста iOS-поставки и пулов — Xcode Cloud и мультирегиональный пул физических Mac для iOS.
- Права и комплаенс: концентрация в одном регионе часто сводит отпечатки исходников и артефакты в одном бакете. С пер-региональными Mac явно разделите, какие каталоги могут покидать юрисдикцию, а какие остаются на локальных аудируемых дисках.
2. Derived Data и кэши зависимостей: авторитет одного региона vs локально на физических Mac
Сначала отрежьте по вопросам: насколько независимо регионы гоняют полные сборки и какую долю джобы съедает восстановление кэша (порядок величины можно подстроить под размер репозитория).
| Измерение | Один авторитетный регион + асинхронная репликация | Локальный кэш на физическом Mac в регионе (колокация) |
|---|---|---|
| Лучше всего подходит | Один основной регион сборок; остальные < 3 полных сборок/сутки и терпят холодный старт 15–45 мин | В регионе ≥ 5 интеграционных или полных сборок/сутки либо restore > ~25% длительности джобы |
| Сеть | Репликация по выделенке или внутри одного облака; массовое копирование — в окна обслуживания | Билдер, Git и артефакты в регионе; Derived Data не на горячем трансокеанском пути |
| Derived Data | «Золотые» снимки для вытягивания другими регионами; жёсткое разбиение по точной версии Xcode | Независимый записываемый каталог на регион; без жёстких ссылок между патч-версиями Xcode |
| SPM / CocoaPods | Объектное хранилище + CDN только для чтения; слой отдельно от Derived Data | Региональный том или локальный SSD; периодически сверяйте checksum с upstream |
| Главные риски | Один плохой снимок отравляет все регионы; счета за трансрегион | Дрейф раскладки диска и политик удержания; нужна автоматическая эвикция |
3. Трансграничная коллаборация: матрица задержка × консистентность
Отложите на ось P95 RTT к Git и артефактам и долю инцидентов кэша (недетерминированные сбои, отнесённые к кэшу, за неделю ÷ все сборки) для быстрых ревью.
| Инциденты кэша < 0,5% | Инциденты кэша ≥ 0,5% | |
|---|---|---|
| Региональный P95 RTT к Git < 80 мс | Предпочитайте колокацию: локальный Derived Data + кэш зависимостей в регионе | Сначала keyspace: бакеты по точной версии Xcode и ветке, затем колокация |
| P95 RTT ≥ 80 мс или нестабильные потери | Допустим авторитетный кэш зависимостей в одном регионе + минимальный набор compile-критичного вне региона | Запретите горячую трансокеанскую синхронизацию Derived Data; переходите на канареечные чистые пересборки |
В SLO-документ добавьте: максимальный возраст записи кэша в текущем релизном поезде; P95 от завершения restore до старта первой компиляции xcodebuild < 90 с (средние репо) или 180 с (монорепо). Нарушение — отключение удалённого кэша для метки джобы и принудительная чистая региональная сборка.
4. Семь шагов выкатки
- Инвентаризация путей: разделите
DerivedData, глобальный кэш SPM, кэш CocoaPods и кастомные бинарные фреймворки. В объектное хранилище — только content-addressed деревья только для чтения. - Ключи кэша: минимум версия Xcode, Swift, ветка или хэш lockfile, конфигурация Debug/Release. Запрет на один репозиторный указатель
latest. - Основной регион сборок: совместите с основным Git remote и реестром артефактов; остальные регионы синхронизируют только слой зависимостей или принимают длинные холодные старты.
- Канареечная джоба: продвигайте новый бакет только после полной чистой сборки и тестов на одном физическом Mac.
- Три фазы метрик: restore, компиляция, тесты отдельно. Если доминирует restore — чините топологию раньше, чем покупаете CPU.
- Инвалидация: в день апгрейда Xcode автоматически уберите старые бакеты; держите N−1 снимок только для чтения 7–14 дней для отката.
- Артефакт согласования: распечатайте обе матрицы на обложку runbook дежурства. Перед сменой топологии кэша повторите региональные пробы RTT/джиттера из статьи по приёмке выше.
5. Чек-лист параметров синхронизации (копируйте в скрипты)
Подставьте хосты и пути. Удаления сначала в dry-run.
A. rsync: массовый Derived Data (осторожно с --delete)
Пуш на региональный том (пример):
rsync -aH --numeric-ids --delete-delay \ --exclude 'ModuleCache.noindex/**' \ --exclude 'CompilationCache.noindex/**' \ --timeout=300 --contimeout=60 \ ~/Library/Developer/Xcode/DerivedData/ \ build@REGION-MAC.CORP:/Volumes/BuildCache/DerivedData/
B. rsync: SPM только для чтения (без --delete, чтобы не трогать параллельных билдеров)
rsync -aH --numeric-ids --omit-dir-times \ ~/Library/Caches/org.swift.swiftpm/ \ s3proxy-local:/spm-ro/KEY/
C. Поток tarball кэша CocoaPods (дорогой трансрегион — допустима устарелость порядка часа)
tar --posix -cf - -C ~/Library/Caches/CocoaPods . \ | pigz -1 \ | ssh -o ServerAliveInterval=30 build@REMOTE 'pigz -d | tar -xf - -C /Volumes/Cache/CocoaPods'
D. Переменные окружения (фрагмент шаблона CI)
export DERIVED_DATA_PATH="/Volumes/BuildCache/DerivedData/${CACHE_KEY}"
export CLONED_SOURCE_PACKAGES_DIR_PATH="/Volumes/BuildCache/SPM/${CACHE_KEY}"
export COCOAPODS_CACHE_DIR="/Volumes/BuildCache/CocoaPods/${CACHE_KEY}"
# Перед xcodebuild: проверьте права на запись и совпадение Xcode с CACHE_KEY
6. Резюме и цифры для цитирования
Примеры порогов: ① restore > ~25% длительности джобы → архитектурный разбор. ② сбои, связанные с кэшем, ≥ 0,5%/нед → заморозить трансрегиональный Derived Data. ③ --timeout=300, --contimeout=60 для rsync. ④ ключи обязаны включать точную версию Xcode. ⑤ пуловое продвижение только после канареечной чистой сборки.
Универсального рецепта нет: зависимости хотят «далеко, медленно, только чтение», а Derived Data — «рядом, быстро, одноразово». Сначала разведите бакеты; спор одна зона vs много регионов тогда сводится к арифметике полосы и математике SLO.
7. Запускайте эту модель управления на Mac mini и macOS
Все пути выше нативны для macOS: Xcode, SwiftPM, локальные SSD и Unix-утилиты без прослоек. Mac mini на Apple Silicon даёт высокую пропускную способность объединённой памяти при порядка 4 Вт в простое — удобный круглосуточный якорь регионального кэша, который прогревает индексы и зависимости, пока парк простаивает. Низкая частота падений macOS и связка Gatekeeper, SIP и FileVault упрощают согласование с ИБ по сравнению с «собранными» хостами.
Если цель — чтобы restore плюс компиляция укладывались в локальный RTT, а не тащили Derived Data через океан архивами, стандартизация пулов Mac mini по регионам — один из самых тихих форм-факторов: компактно, часто без вентилятора, ниже по энергии и вниманию эксплуатации на горизонте нескольких лет.
Когда нужно перейти от «где-то собирается» к подписанному SLO, Mac mini M4 — сильная точка входа по цене и стабильности для эталонных билд-узлов: арендуйте или масштабируйте региональную физическую ёмкость и закрепляйте политику кэша на реальных дисках и сетях.
Готовы разместить узлы там, куда указывают метрики? Откройте ZoneMac — физические Mac под вашу топологию CI.
8. FAQ
Где жить Derived Data — в одном регионе или на каждом региональном физическом Mac?
Если сборки в основном в одном регионе, а остальные лишь легко валидируют — авторитет в одном регионе с асинхронной репликацией. Если в каждом регионе ежедневные полные сборки и RTT к Git/артефактам через океан критичен — записываемый Derived Data колокируйте на региональных физических Mac, разрешение зависимостей — в регионе билдера.
Какие пороги консистентности важнее всего?
Примеры для согласования: макс. возраст записи в окне релизного поезда, согласованность checksum/content key, запрет общего пути для разных патч-версий Xcode, доля сбоев SPM и доля холодных стартов. Выше порога — региональная чистая пересборка вместо инкрементальной трансрегиональной синхронизации.
Должны ли SPM и CocoaPods следовать той же политике, что Derived Data?
Нет. Зависимости — content-addressed read-only; Derived Data — вывод сборки и индексы. Держите зависимости на объектном хранилище или томах только для чтения, Derived Data — записываемым per-регион.
Главный риск концентрации в одном регионе?
Трансрегиональная полоса, длинный хвост задержки на огромных деревьях каталогов и одна плохая синхронизация, отравляющая несколько регионов. Смягчайте порционной проверкой, бакетами по веткам и канареечными сборками до продвижения.
iOS-сборки ближе к Git и артефактам
Колокация узлов с репозиториями сокращает задержку восстановления Derived Data и зависимостей — пулы Xcode и удалённые рабочие столы по требованию.